November 11, 2020

How to prevent java reflection to create new instance by accessing private constructor of a class

This code will work on Java 9 and above. StackWalker was added in java 9.

You can watch me work on this code on YouTube.

 

We can use class check to make sure, the private constructor is not accessed from any other class.

You can read entire source code at github.
To restrict the access, we can put a class check in the constructor. If the caller is a class, which is not the current class, then raise an error.

if(SingletonClass.class != walker.getCallerClass()) throw new IllegalAccessError("Private Constructor can not be invoked from outside the class");

 

Full Source Code :-

SingletonClass.java

public class SingletonClass{
    final StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);

    private static SingletonClass INSTANCE;

    private SingletonClass(){
        if(SingletonClass.class != walker.getCallerClass()) throw new IllegalAccessError("Private Constructor can not be invoked from outside the class");
    }

    public void display(){
        System.out.println("Yes I am displaying");
    }

    public static SingletonClass instance(){
        if(INSTANCE == null){
        synchronized(SingletonClass.class){
                if(INSTANCE == null){
           INSTANCE = new SingletonClass(); 
            }
        }
    }
    return INSTANCE;
    }

}

 

SingletonClassTest.java -> with comments

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Constructor;
public class SingletonClassTest {
    public static void main(final String ... args)
                                                 throws 
                                            InvocationTargetException,
                                        IllegalAccessException,
                            InstantiationException {
        final Class<?> singletonClass = SingletonClass.class;
    final Constructor<?>[] arrayOfConstructors = singletonClass.getDeclaredConstructors();
    final Constructor<?> privateConstructor = arrayOfConstructors[0];
    privateConstructor.setAccessible(true);
    //final SingletonClass object = (SingletonClass) privateConstructor.newInstance();
    final SingletonClass object = SingletonClass.instance(); 
    object.display();
    //final SingletonClass object1 = (SingletonClass) privateConstructor.newInstance();
    //final SingletonClass object2 = (SingletonClass) privateConstructor.newInstance();
    //System.out.println("object1 and object2 are the same instance " + (object1 == object2));
    }
}