Singleton: How to stop create instance via Reflection

52,075

Solution 1

By adding below check inside your private constructor

private Singleton() {
    if( singleton != null ) {
        throw new InstantiationError( "Creating of this object is not allowed." );
    }
}

Solution 2

Define the singleton like this:

public enum Singleton {
    INSTANCE
}

Solution 3

How about checking in the constructor:

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

Of course, this may not really stop it - if someone is messing around with reflection to access private members, they may be able to set the field to null themselves. You have to ask yourself just what you're trying to prevent though, and how worthwhile it is.

(EDIT: As Bozho mentioned, final fields may not be settable even via reflection. I wouldn't be surprised if there were some way of doing it via JNI etc though... if you give folks enough access, they'll be able to do almost anything...)

Solution 4

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

Another thing you should watch is the readResolve(..) method, because your class implements Serialiable. There you should return the existing instance.

But the easiest way to use singletons is through enums - you don't worry about these things.

Solution 5

As an alternative to the singleton, you could take a look at the monostate pattern. Then, instantiation of your class is not a problem anymore, and you don't have to worry about any of the scenarios you listed.

In the monostate pattern, all the fields in your class are static. That means that all instances of the class share the same state, just like with a singleton. Moreover, this fact is transparent to the callers; they don't need to know about special methods like getInstance, they simply create instances and work with them.

But, just like with singleton, it's a form of hidden global state; which is very bad.

Share:
52,075

Related videos on Youtube

Talha Ahmed Khan
Author by

Talha Ahmed Khan

Updated on July 09, 2022

Comments

  • Talha Ahmed Khan
    Talha Ahmed Khan almost 2 years

    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();
    }
    
    • Mr_and_Mrs_D
      Mr_and_Mrs_D over 10 years
      You have accepted the wrong answer - the right one is stackoverflow.com/a/6994437/281545
    • Hrishikesh Mishra
      Hrishikesh Mishra about 7 years
      All answers are not solving this problem.
    • ihebiheb
      ihebiheb over 5 years
      I know that my question is somehow out of scope but can you tell me how did you managed to stop creating a class instance via reflexion ? I couldn't see such a thing in your code
  • Bozho
    Bozho almost 13 years
    I think final fields can't be modified with reflection
  • Talha Ahmed Khan
    Talha Ahmed Khan almost 13 years
    Luckily I have already implemented the readResolve() method.
  • Dave G
    Dave G almost 13 years
    I just used what was technically the body of newInstance(). I think, although not sure, the newInstance() method can be removed as that is actually a java.lang.Class<?> method and the method implementation provided in the question initially would do nothing.
  • Bozho
    Bozho almost 13 years
  • Mr_and_Mrs_D
    Mr_and_Mrs_D over 10 years
    hey - the right way is the enum one - see : stackoverflow.com/a/71399/281545. Actually item 77 of effective java 2nd edition demonstrates a (too technical for me) attack via deserialization that would probably beat this constructor (?)
  • Kumar Abhinav
    Kumar Abhinav almost 10 years
    Enum is a sure shot gaurantee against Reflection,clone and serialization-deserialization
  • ring bearer
    ring bearer almost 9 years
    There is a flaw in this approach, by which what if we create the instance using reflection before any getInstance invocation(with lazy init)? Reflection is still allowed to proceed as the static variable is still null at that time.
  • Kanwaljeet Singh
    Kanwaljeet Singh over 8 years
    I agree with @ringbearer , you can create as many objects using reflection as you like for this class, if the getIntance method is not invoked.
  • Ashish Agrawal Yodlee
    Ashish Agrawal Yodlee over 7 years
    this is pure Singleton, This code will not break in any case like- Cloning,Serialization, Reflection.
  • Hrishikesh Mishra
    Hrishikesh Mishra about 7 years
    This approach will not work if we create object first reflection, like this String className = "Singleton"; Class<Singleton> aClass = (Class<Singleton>) Class.forName(className); Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(); declaredConstructor.setAccessible(true); Singleton instance1 = (Singleton) declaredConstructor.newInstance(); print("instance1", instance1.hashCode()); Singleton instance2 = Singleton.getInstance(); print("instance2", instance2.hashCode()); both have different hashcode
  • Hrishikesh Mishra
    Hrishikesh Mishra about 7 years
    This approach will not work if we create object first reflection, like this String className = "Singleton"; Class<Singleton> aClass = (Class<Singleton>) Class.forName(className); Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(); declaredConstructor.setAccessible(true); Singleton instance1 = (Singleton) declaredConstructor.newInstance(); print("instance1", instance1.hashCode()); Singleton instance2 = Singleton.getInstance(); print("instance2", instance2.hashCode()); both have different hashcode
  • Hrishikesh Mishra
    Hrishikesh Mishra about 7 years
    This approach will not work if we create object first reflection, like this String className = "Singleton"; Class<Singleton> aClass = (Class<Singleton>) Class.forName(className); Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(); declaredConstructor.setAccessible(true); Singleton instance1 = (Singleton) declaredConstructor.newInstance(); print("instance1", instance1.hashCode()); Singleton instance2 = Singleton.getInstance(); print("instance2", instance2.hashCode()); both have different hashcode
  • Jon Skeet
    Jon Skeet about 7 years
    @HrishikeshMishra: Nope, when you call the constructor via reflection it throws an exception. I've just tried your code, and it threw an exception as expected...
  • Hrishikesh Mishra
    Hrishikesh Mishra about 7 years
    @JonSkeet, it will work of egger initialization but will not lazy. try out.
  • Jon Skeet
    Jon Skeet about 7 years
    @HrishikeshMishra: Don't know what you mean by that, but I tried the exact code you showed. Note that the class will be initialized before you get to call the constructor, in any reasonable VM...
  • Diganta
    Diganta almost 7 years
    But ENUM has it's restriction. I am actually looking for a solution which is apart from ENUM
  • Ashish Agrawal Yodlee
    Ashish Agrawal Yodlee almost 7 years
    Here its breaking with Reflection API by making constructor as visible, So please follow the below code provided by me , (Ashish Agrawal), Code is fully singleton
  • GorvGoyl
    GorvGoyl over 6 years
    @Diganta what restrictions?
  • Tom Drake
    Tom Drake over 6 years
    Enum is the cleanest way of providing singleton behavior in Java, bar none. As Kumar Abhinav stated, it provides these guarantees in the simplest, least error prone way.
  • ihebiheb
    ihebiheb over 5 years
    Yes you can Constructor<?>[] constructors = Counter.class.getDeclaredConstructors(); Constructor theConstructor = constructors[0]; //suppose you have 1 constructor theConstructor.setAccessible(true); theConstructor.newInstance();
  • ihebiheb
    ihebiheb over 5 years
    One restriction I can think of is when serializing an enum, field variables are not getting serialized (will lose the value of the field)
  • Rahul Jain
    Rahul Jain over 4 years
    If you set Security manager than you are not able to call SingletonClass sc = SingletonClass.getInstance(); you will get exception every time.
  • Holger
    Holger about 2 years
    @ringbearer When you try to create an instance of a class, whether via Reflection or directly, the class will be initialized, including the execution of field initializers. It doesn’t matter whether the getInstance has been invoked or not. Since the field initializer comes first, this approach will reject any Reflection instantiation attempts.
  • Holger
    Holger about 2 years
    @HrishikeshMishra you obviously never tried what you have posted.
  • Holger
    Holger about 2 years
    Neither of your workarounds works with class given in the question. Instantiation via Reflection still executes the class initializer first, further, you can’t change a static final field via Reflection.
  • Holger
    Holger about 2 years
    This is Cargo Cult programming. You’re using patterns without understanding their purpose. For example, your nested SingletonHolder class makes no sense at all, as it is not actually a holder class. Compared to what the questioner already provided, you only made things worse, by removing thread safety, for example, without providing any additional protection. Your code breaks, because you’re looping over all constructors and try to invoke each without arguments. Just use Constructor constructor = SingletonImpl.class.getDeclaredConstructor(); to get the right no-arg constructor instead.
  • Holger
    Holger about 2 years
    The initialization of an enum type is as lazy as any other class. As long as your class does not offer other static members unrelated to the singleton, there will be no unintended early instantiation, just like with the private static final Singleton singleton = new Singleton(); approach in the question’s original code.
  • Dave G
    Dave G about 2 years
    I posted this answer 11 years ago. As per this documentation docs.oracle.com/javase/tutorial/java/javaOO/initial.html the static initialization block will run the moment the class is loaded.
  • Holger
    Holger about 2 years
    Not exactly when the class is loaded (as the time of loading is not exactly specified), but definitely before an instance is created as specified. That’s sufficient for your approach. It’s annoying to see three comments wrongly claiming that this didn’t work.