Immutability is a property I look after when designing most of my classes. Achieving immutability requires:
- A constructor initializing all attributes
- No setter for those attributes
However, this design prevents or makes testing more complex. In order to allow (or ease) testing, a public no-arg constructor is needed.
Other use-cases requiring usage of a no-arg constructor include:
- De-serialization of serialized objects
- Sub-classing with no constructor invocation of parent classes
- etc.
There are a couple of solutions to this.
1. Writing a public no-arg constructor
The easiest way is to create a public no-arg constructor, then add a big bright Javadoc to warn developers not to use. As you can imagine, in this case easy doesn’t mean it enforces anything, as you are basically relying on developers willingness to follow instructions (or even more on their ability to read them in the first place - a risky bet).
The biggest constraint, however, is that it you need to be able to change the class code.
2. Writing a package-visible no-arg constructor
A common approach used for testing is to change visibility of a class private methods to package-visible, so they can be tested by test classes located in the same package. The same approach can be used in our case: write a package-visible no-arg constructor.
This requires the test class to be in the same package as the class which constructor has been created. As in case 1 above, you also need to change the class code.
3. Playing it Unsafe
The JDK is like a buried treasure: it contains many hidden and shiny features;
the sun.misc.Unsafe
class is one of them.
Of course, as both its name and package imply, its usage is extremely discouraged.
Unsafe offers a allocateInstance(Class<?>)
method to create new instances without calling any constructors whatsoever, nor any initializers.
Note Unsafe only has instance methods, and its only constructor private… but offers a private singleton attribute. Getting a reference on this attribute requires a bit of reflection black magic as well as a lenient security manager (by default).
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
java.sql.Date date = (java.sql.Date) unsafe.allocateInstance(java.sql.Date.class);
System.out.println(date);
Major constraints of this approach include:
- Relying on a class outside the public API
- Using reflection to access a private field
- Only available in Oracle’s HotSpot JVM
- Setting a lenient enough security manager
4. Objenesis
Objenesis is a framework which sole goal is to create new instances without invoking constructors.
It offers an abstraction layer upon the Unsafe
class in Oracle’s HotSpot JVM.
Objenesis also works on different JVMs including OpenJDK, Oracle’s JRockit and Dalvik (i.e. Android) in many different versions by using strategies adapted to each JVM/version pair.
The above code can be replaced with the following:
Objenesis objenesis = new ObjenesisStd();
ObjectInstantiator instantiator = objenesis.getInstantiatorOf(java.sql.Date.class);
java.sql.Date date = (java.sql.Date) instantiator.newInstance();
System.out.println(date);
Running this code on Oracle’s HotSpot will still require a lenient security manager as Objenesis will use the above Unsafe
class.
However, such requirements will be different from JVM to JVM, and handled by Objenesis.
Conclusion
Though a very rare and specialized requirement, creating instances without constructor invokation might sometimes be necessary. In this case, the Objenesis framework offers a portable and abstract to achieve this at the cost of a single additional dependency.