Reputation: 15433
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();
}
Upvotes: 48
Views: 57674
Reputation: 9777
By adding below check inside your private constructor
private Singleton() {
if( singleton != null ) {
throw new InstantiationError( "Creating of this object is not allowed." );
}
}
Upvotes: 75
Reputation: 5183
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 :
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 :
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
Upvotes: 1
Reputation: 214
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
Upvotes: 0
Reputation: 2146
Perfect Singleton Class that can avoid instance creation during serialization, clone and reflection.
import java.io.Serializable;
public class Singleton implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
private static volatile Singleton instance;
private Singleton() {
if (instance != null) {
throw new InstantiationError("Error creating class");
}
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
return new Singleton();
}
}
}
return null;
}
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
Object readResolve() {
return Singleton.getInstance();
}
}
Upvotes: 0
Reputation: 123
Here Reflection not work
package com.singleton.nonbreakable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
class FullySingletonClass {
public static void main(String[] args) {
SingletonImpl object1 = SingletonImpl.getInstance();
System.out.println("Object1:" + object1);
try {
FileOutputStream fos = new FileOutputStream("abc.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(object1);
FileInputStream fis = new FileInputStream("abc.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
SingletonImpl object2 = (SingletonImpl) ois.readObject();
System.out.println("Object2" + object2);
} catch (Exception e) {
// TODO: handle exception
}
try {
Constructor[] constructors = SingletonImpl.class.getDeclaredConstructors();
for (Constructor constructor : constructors) {
// Below code will not destroy the singleton pattern
constructor.setAccessible(true);
SingletonImpl Object3 = (SingletonImpl) constructor.newInstance();
System.out.println("Object3:" + Object3);
break;
}
} catch (Exception ew) {
}
}
}
package com.singleton.nonbreakable;
import java.io.Serializable;
class SingletonImpl implements Cloneable, Serializable {
public static SingletonImpl singleInstance = null;
private static class SingletonHolder {
public static SingletonImpl getInstance() {
if (null == singleInstance) {
singleInstance = new SingletonImpl();
}
return singleInstance;
}
}
private SingletonImpl() {
}
@Override
protected Object clone() throws CloneNotSupportedException {
return singleInstance;
};
public Object readResolve() {
System.out.println("Executing readResolve again");
return SingletonImpl.getInstance(); // FIXME
}
public static SingletonImpl getInstance() {
return SingletonHolder.getInstance();
}
}
Output :
Object1:com.singleton.nonbreakable.SingletonImpl@15db9742
Executing readResolve again
Object2com.singleton.nonbreakable.SingletonImpl@15db9742
Upvotes: -3
Reputation: 123
We can break it using static nested class
Please follow below code its 100% correct, i tested
package com.singleton.breakable;
import java.io.Serializable;
class SingletonImpl implements Cloneable, Serializable {
public static SingletonImpl singleInstance = null;
private SingletonImpl() {
}
@Override
protected Object clone() throws CloneNotSupportedException {
return singleInstance;
};
public Object readResolve() {
return SingletonImpl.getInstance(); //
}
public static SingletonImpl getInstance() {
if (null == singleInstance) {
singleInstance = new SingletonImpl();
}
return singleInstance;
}
}
package com.singleton.breakable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
class FullySingletonClass {
public static void main(String[] args) {
SingletonImpl object1 = SingletonImpl.getInstance();
System.out.println("Object1:" + object1);
try {
FileOutputStream fos = new FileOutputStream("abc.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(object1);
FileInputStream fis = new FileInputStream("abc.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
SingletonImpl object2 = (SingletonImpl) ois.readObject();
System.out.println("Object2" + object2);
} catch (Exception e) {
// TODO: handle exception
}
try {
Constructor[] constructors = SingletonImpl.class.getDeclaredConstructors();
for (Constructor constructor : constructors) {
// Below code will not destroy the singleton pattern
constructor.setAccessible(true);
SingletonImpl Object3 = (SingletonImpl) constructor.newInstance();
System.out.println("Object3: Break through Reflection:" + Object3);
break;
}
} catch (Exception ew) {
}
}
}
**OUTPUT**
Object1:com.singleton.breakable.SingletonImpl@15db9742
Object2com.singleton.breakable.SingletonImpl@15db9742
Object3: Break through Reflection:com.singleton.breakable.SingletonImpl@33909752
Upvotes: 0
Reputation: 9
I Thing Below code will work ..
class Test {
static private Test t = null;
static {
t = new Test();
}
private Test(){}
public static Test getT() {
return t;
}
public String helloMethod() {
return "Singleton Design Pattern";
}
}
public class MethodMain {
public static void main(String[] args) {
Test t = Test.getT();
System.out.println(t.helloMethod());
}
}
output : Singleton Design Pattern
Upvotes: 0
Reputation: 1457
Just to note, that as of Java 8 and according to my check- you cannot instantiate a Singleton via Reflections as long as it has a private constructor.
You'll get this exception:
Exception in thread "main" java.lang.IllegalAccessException: Class com.s.Main can not access a member of class com.s.SingletonInstance with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at com.s.Main.main(Main.java:6)
Upvotes: 0
Reputation: 56477
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.
Upvotes: 1
Reputation: 1500775
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...)
Upvotes: 16
Reputation: 14769
Define the singleton like this:
public enum Singleton {
INSTANCE
}
Upvotes: 23
Reputation: 597114
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.
Upvotes: 10