Singleton: How to stop create instance via Reflection
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.
Related videos on Youtube
Talha Ahmed Khan
Updated on July 09, 2022Comments
-
Talha Ahmed Khan almost 2 years
I know in Java we can create an instance of a Class by
new
,clone()
,Reflection
and byserializing 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()
andserialization
, 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 over 10 yearsYou have accepted the wrong answer - the right one is stackoverflow.com/a/6994437/281545
-
Hrishikesh Mishra about 7 yearsAll answers are not solving this problem.
-
ihebiheb over 5 yearsI 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 almost 13 yearsI think final fields can't be modified with reflection
-
Talha Ahmed Khan almost 13 yearsLuckily I have already implemented the
readResolve()
method. -
Dave G almost 13 yearsI 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 almost 13 years
-
Mr_and_Mrs_D over 10 yearshey - 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 almost 10 yearsEnum is a sure shot gaurantee against Reflection,clone and serialization-deserialization
-
ring bearer almost 9 yearsThere 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 over 8 yearsI 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 over 7 yearsthis is pure Singleton, This code will not break in any case like- Cloning,Serialization, Reflection.
-
Hrishikesh Mishra about 7 yearsThis 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 about 7 yearsThis 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 about 7 yearsThis 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 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 about 7 years@JonSkeet, it will work of egger initialization but will not lazy. try out.
-
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 almost 7 yearsBut ENUM has it's restriction. I am actually looking for a solution which is apart from ENUM
-
Ashish Agrawal Yodlee almost 7 yearsHere 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 over 6 years@Diganta what restrictions?
-
Tom Drake over 6 yearsEnum 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 over 5 yearsYes you can Constructor<?>[] constructors = Counter.class.getDeclaredConstructors(); Constructor theConstructor = constructors[0]; //suppose you have 1 constructor theConstructor.setAccessible(true); theConstructor.newInstance();
-
ihebiheb over 5 yearsOne 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 over 4 yearsIf you set Security manager than you are not able to call SingletonClass sc = SingletonClass.getInstance(); you will get exception every time.
-
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 about 2 years@HrishikeshMishra you obviously never tried what you have posted.
-
Holger about 2 yearsNeither 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 about 2 yearsThis 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 useConstructor constructor = SingletonImpl.class.getDeclaredConstructor();
to get the right no-arg constructor instead. -
Holger about 2 yearsThe initialization of an
enum
type is as lazy as any other class. As long as your class does not offer otherstatic
members unrelated to the singleton, there will be no unintended early instantiation, just like with theprivate static final Singleton singleton = new Singleton();
approach in the question’s original code. -
Dave G about 2 yearsI 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 about 2 yearsNot 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.