Singleton: How to stop create instance via Reflection

Viewed 53339

I know in Java we can create an instance of a Class by new, clone(), Reflection and by serializing and de-serializing.

I have create a simple class implementing a Singleton.

And I need stop all the way one can create instance of my Class.

public class Singleton implements Serializable{
    private static final long serialVersionUID = 3119105548371608200L;
    private static final Singleton singleton = new Singleton();
    private Singleton() { }
    public static Singleton getInstance(){
        return singleton;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException("Cloning of this class is not allowed"); 
    }
    protected Object readResolve() {
        return singleton;
    }
    //-----> This is my implementation to stop it but Its not working. :(
    public Object newInstance() throws InstantiationException {
        throw new InstantiationError( "Creating of this object is not allowed." );
    }
}

In this Class I have managed to stop the class instance by new, clone() and serialization, But am unable to stop it by Reflection.

My Code for creating the object is

try {
    Class<Singleton> singletonClass = (Class<Singleton>) Class.forName("test.singleton.Singleton");
    Singleton singletonReflection = singletonClass.newInstance();
} catch (ClassNotFoundException e) {
    e.printStackTrace();
} catch (InstantiationException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
}
13 Answers

Apart the enum solution, all the others can be workaround-ed via Reflexion These are two examples on how to workaround the Dave G Solution :

1 : Setting the variable Singleton.singleton to null

Constructor<?>[] constructors = Singleton.class.getDeclaredConstructors();
Constructor theConstructor = constructors[0];
theConstructor.setAccessible(true);
Singleton instance1 = (Singleton) theConstructor.newInstance();

Singleton.getInstance();

Field f1 = Singleton.class.getDeclaredField("singleton");
f1.setAccessible(true);
f1.set(f1, null);
Singleton instance2 = (Singleton) theConstructor.newInstance();

System.out.println(instance1);
System.out.println(instance2);

Output :

  • Singleton@17f6480
  • Singleton@2d6e8792

2 : not calling the getInstance

Constructor<?>[] constructors = Singleton.class.getDeclaredConstructors();
Constructor theConstructor = constructors[0];
theConstructor.setAccessible(true);
Singleton instance1 = (Singleton) theConstructor.newInstance();
Singleton instance2 = (Singleton) theConstructor.newInstance();

System.out.println(instance1);
System.out.println(instance2);

Output :

  • Singleton@17f6480
  • Singleton@2d6e8792

So I can think of 2 ways if you don't want to go with an Enum :

1st option : Using the securityManager :

It prevent from using unauthorized operations (calling private methods from outside the class ....)

So you just need to add one line to the singleton constructor proposed by the other answers

private Singleton() {
    if (singleton != null) {
        throw new IllegalStateException("Singleton already constructed");
    }
    System.setSecurityManager(new SecurityManager());
}

what it does is that it prevents from calling setAccessible(true) So when you want to call it :

Constructor<?>[] constructors = Singleton.class.getDeclaredConstructors();
Constructor theConstructor = constructors[0];
theConstructor.setAccessible(true);

this exeption will occure : java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "createSecurityManager")

2nd option : In the singleton constructor, test if the call is made via Reflexion :

I refer you to this other Stackoverflow thread for the best way to get the caller class or method.

So If I add this in the Singleton constructor :

String callerClassName = new Exception().getStackTrace()[1].getClassName();
System.out.println(callerClassName);

And I call it like this :

Constructor<?>[] constructors = Singleton.class.getDeclaredConstructors();
Constructor theConstructor = constructors[0];
theConstructor.setAccessible(true);
Singleton instance1 = (Singleton) theConstructor.newInstance();

the output will be : jdk.internal.reflect.DelegatingConstructorAccessorImpl

but if I call it regularly (Instantiating a public constructor or calling a method without Reflexion) the name of the class of the calling method is printed. So for example I have :

public class MainReflexion {
    public static void main(String[] args) {
        Singleton.getInstance();
    }
}

the callerClassName will be MainReflexion and so the output will be MainReflexion.


PS : If workarounds exists for the proposed solutions please let me know

To overcome issue raised by reflection, enums are used because java ensures internally that enum value is instantiated only once. Since java Enums are globally accessible, they can be used for singletons. Its only drawback is that it is not flexible i.e it does not allow lazy initialization.

public enum Singleton {
 INSTANCE
}

public class ReflectionTest 
{

    public static void main(String[] args)
    {
        Singleton instance1 = Singleton.INSTANCE;
        Singleton instance2 = Singleton.INSTANCE;
    System.out.println("instance1 hashcode- "
                                      + instance1.hashCode());
        System.out.println("instance2 hashcode- "
                                      + instance2.hashCode());
    }
}

JVM handles the creation and invocation of enum constructors internally. As enums don’t give their constructor definition to the program, it is not possible for us to access them by Reflection also.

Refer the post for more details.

Approach with Lazy initialization:

  private static Singleton singleton;

  public static Singleton getInstance() {
    if(singleton==null){
      singleton= new Singleton();
    }
    return singleton;
  }


private Singleton() {
    if (Singleton.singleton != null) {
      throw new InstantiationError("Can't instantiate singleton twice");
    }
    Singleton.singleton = this;
}

This approach works even if you decide to create an instance using reflection before any getInstance invocation

Related