40

I have a class which has not default constructor. And I need a way to get 'blank' instance of this class. 'blank' means that after instantiation all class fields should has default values like null, 0 etc.

I'm asking because I need to be able serialize/desirialize big tree of objects. And I have no access to sources of this objects classes and classes has neither default constructors nor implements serializable. It is likely not very good idea to try to serialize such structure but the alternative is to convert it to something more easily serializable.

Vladimir
  • 12,753
  • 19
  • 62
  • 77

5 Answers5

35

With standard reflection, no, but there is a library that can do it for you: objenesis.

It's specifically designed to instantiate classes without default constructors, and it's used by other serialization libraries like xstream.

Note: the constructor might not be called in these cases (but that's presumably what you want).

Brad Cupit
  • 6,530
  • 8
  • 55
  • 60
  • 1
    I agree - very evil. When a programmer creates no ctor they he/she expects that nobody calls it, and - surprise! :-) – iirekm Nov 09 '10 at 13:23
  • But from the other side, "normal" reflection also breaks the rules of class design (like accessing private fields), but at least most programmers realize, that such thing like reflection exists. Very few programmers know about objensis. – iirekm Nov 09 '10 at 13:25
  • 1
    Not particularly evil -- very useful in implementing custom serialization schemes, particularly when the original object isn't implemented as serializable. .NET has a method, FormatterServices.GetUninitializedObject(), for just this purpose. I wish Java had something similar that was "official." – Wayne Citrin Jun 24 '16 at 22:38
  • 1
    yes not particularly evil, but it can be used to break at least one of the guarantees of Java: http://jqno.nl/post/2015/02/28/hacking-java-enums/ – Jordan Aug 28 '17 at 10:45
25

Having Class instance provided as variable clazz:

ReflectionFactory rf = ReflectionFactory.getReflectionFactory();
Constructor objDef = parent.getDeclaredConstructor();
Constructor intConstr = rf.newConstructorForSerialization(clazz, objDef);
clazz.cast(intConstr.newInstance());

as described in http://www.javaspecialists.eu/archive/Issue175.html

mcveat
  • 1,416
  • 15
  • 34
  • Nice. We might have a winner here! (+1) – Sean Patrick Floyd Nov 09 '10 at 13:01
  • 4
    Keep in mind though that the ReflectionFactory class is a Sun class so this will only work on Sun/Oracle VMs, and even then it's subject to change. – Francis Upton IV Dec 22 '11 at 17:52
  • Where does `parent` come from? – Raffi Khatchadourian Jan 20 '17 at 20:45
  • This should by far be the accepted answer. I also have the same question (as so many other mothers)... who is/provides the parent...? or is it a list of calling `newConstructorForSerlialization` all the way up to a no arg constructor class either serializable or not? and then just filling up the instantiated classes with the serialized data? – Ordiel Jan 14 '19 at 17:10
  • Regarding `parent` - I think the idea is to "skip" the inaccessible c'tor and use one of the super classes' c'tor instead - so as much of the object fields will be initialized properly. As per @jonstok's answer, you can even just use `Object`'s default c'tor. The main think that I worry about here - fields that the provided c'tor don't know about, are they zero-initialized? – Guss Jun 24 '20 at 19:02
7

Your solution will be JVM specific.

If you need a portable solution use a 3rd party library.

For Sun's JVM v1.5 you can do this:

    final Class<?> myClass = MyClass.class;
    final ReflectionFactory reflection = ReflectionFactory.getReflectionFactory();
    final Constructor<Object> constructor = 
        reflection.newConstructorForSerialization(
            myClass, Object.class.getDeclaredConstructor(new Class[0]));
    final Object o = constructor.newInstance(new Object[0]);

    System.out.print(o.getClass());

The relevant classes in XStream are:

  • com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider
  • com.thoughtworks.xstream.core.JVM;
johnstok
  • 96,212
  • 12
  • 54
  • 76
  • If I understand correctly, your code causes Sun's `ReflectionFactory` to use `Object`'s default constructor in place of `MyClass`'s inaccessible constructors. This seems to work but the question remains - are `MyClass` fields zero initialized when no constructor code exist that know them? I tried to follow the code for `ReflectionFactory` but it was somewhat too complex for me. – Guss Jun 24 '20 at 19:11
3

The only solution I can think of would be to use a bytecode manipulation library such as javassist to add a default constructor.

Maurice Perry
  • 32,610
  • 9
  • 70
  • 97
2

If your class has no other constructor, then the compiler will create one for you. You might have a no-arg constructor and not realize it.

If you do not write a no-arg constructor, and you include even one constructor that takes an argument, then the compiler will not give you one. Reflection won't help, either: if you try to find a no-arg constructor and there isn't one, what do you expect to happen?

It doesn't sound like you can use Java object serialization using java.lang.Serializable, but that's not your only choice. You can also use XML, or JSON, or prototype buffers, or any other protocol that's convenient.

duffymo
  • 305,152
  • 44
  • 369
  • 561
  • +1 for being (almost) the only one who knows what he (and the OP) is talking about – Sean Patrick Floyd Nov 09 '10 at 13:00
  • Unsafe wasn't an option in 2010 when this question was posted. It's a JDK 9 feature: https://www.javaworld.com/article/2952869/java-platform/understanding-sun-misc-unsafe.html – duffymo Sep 12 '17 at 09:04