Running on Java 22-ea+15-1134 (Preview)
Home of The JavaSpecialists' Newsletter

175Creating Objects Without Calling Constructors

Author: Dr. Heinz M. KabutzDate: 2009-09-08Java Version: 6Category: Tips and Tricks
 

Abstract: De-Serialization creates objects without calling constructors. We can use the same mechanism to create objects at will, without ever calling their constructors.

 

Welcome to the 175th issue of The Java(tm) Specialists' Newsletter. Something rather odd happened last night in Crete, which has not occurred since May. We had water falling down from the sky! So, it is time that I say goodbye to my extended summer holiday and start working again :-)

I am en route to the JavaZone conference in Oslo, Norway, where I will be speaking about some of the weird and wonderful things you can do with reflection (download slides here). Hope to see some of you at the conference! The organizers thought it would be fun to give me the second-last speaking slot of the last day ... at least if I embarrass myself, there won't be too many witnesses :-)

javaspecialists.teachable.com: Please visit our new self-study course catalog to see how you can upskill your Java knowledge.

Creating Objects Without Calling Constructors

A few months before disappearing amongst the sand dunes of Chania's beaches on my extended summer vacation, I was explaining to the students on my advanced Java course how deserialization worked. If the object is serializable, then it is created magically without having the constructor called. If its parent class is not serializable, then the super class no-args constructor is invoked. For example, let's begin with a superclass that does not implement Serializable:

public class NotSerializable {
  public NotSerializable() {
    System.out.println("NotSerializable constructor called");
  }
}

We subclass this with MySerializable that prints out a message in the constructor:

import java.io.Serializable;

public class MySerializable extends NotSerializable
    implements Serializable {
  public MySerializable() {
    System.out.println("MySerializable constructor called");
  }
}

We now write the MySerializable object to an ObjectOutputStream and generate a byte[] from which we then read back the object. When we run this, we see that the NotSerializable constructor is called twice, once when the MySerializable object is constructed and once when it is deserialized. We also see that the MySerializable constructor is only called once:

import java.io.*;

public class DeserializeTest {
  public static void main(String[] args)
      throws IOException, ClassNotFoundException {
    MySerializable ms = new MySerializable();

    // writing object to byte[]
    System.out.println("writing ms");
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(ms);
    oos.close();
    byte[] objectInBinaryForm = baos.toByteArray();

    // reading object from byte[]
    System.out.println("reading ms2");
    ObjectInputStream ois = new ObjectInputStream(
        new ByteArrayInputStream(objectInBinaryForm)
    );
    MySerializable ms2 = (MySerializable) ois.readObject();
    System.out.println("ms == ms2 = " + (ms == ms2));
    System.out.println("ms = " + ms);
    System.out.println("ms2 = " + ms2);
  }
}

The output is the following, note the number of times that each constructor is called:

    NotSerializable constructor called
    MySerializable constructor called
    writing ms
    reading ms2
    NotSerializable constructor called
    ms == ms2 = false
    ms = MySerializable@1827391d
    ms2 = MySerializable@6f7a29a1

By digging around a bit, I found the code that is used to construct the serializable object without calling the constructor, which we can use to create objects. To use it, we need to specify the first class in our hierarchy, where we want to call the actual constructor. For example, to simulate what happens in the DeserializeTest, we could call it with

      SilentObjectCreator.create(
        MySerializable.class,
        NotSerializable.class)
    
Here is my SilentObjectCreator, used to instantiate objects without invoking any constructors:

import sun.reflect.ReflectionFactory;
import java.lang.reflect.Constructor;

public class SilentObjectCreator {
  public static <T> T create(Class<T> clazz) {
    return create(clazz, Object.class);
  }

  public static <T> T create(Class<T> clazz,
                             Class<? super T> parent) {
    try {
      ReflectionFactory rf =
          ReflectionFactory.getReflectionFactory();
      Constructor objDef = parent.getDeclaredConstructor();
      Constructor intConstr = rf.newConstructorForSerialization(
          clazz, objDef
      );
      return clazz.cast(intConstr.newInstance());
    } catch (RuntimeException e) {
      throw e;
    } catch (Exception e) {
      throw new IllegalStateException("Cannot create object", e);
    }
  }
}

In our test class, we demonstrate what happens when we create the MySerializable by also calling the superclass constructor and the default behaviour of only calling Object's constructor:

public class CreationTest {
  public static void main(String[] args) {
    // Creating MySerializable by calling NotSerializable no-args
    // constructor, but not the MySerializable constructor.
    MySerializable ms = SilentObjectCreator.create(
            MySerializable.class, NotSerializable.class);
    System.out.println("ms = " + ms);

    // Creating MySerializable by not calling any constructors.
    MySerializable ms2 = SilentObjectCreator.create(
        MySerializable.class
    );
    System.out.println("ms2 = " + ms2);
  }
}

In the output we see that in the first case, the NotSerializable constructor is called, but not in the second:

    NotSerializable constructor called
    ms = MySerializable@1d5ee671
    ms2 = MySerializable@593d93f4

We can use this mechanism to create just about any class, except abstract classes. For example, here we are making Thread.State.class instances:

import java.lang.reflect.Field;

public class EnumCreation {
  public static void main(String[] args) throws Exception {
    Thread.State fastAsleep =
        SilentObjectCreator.create(Thread.State.class);
    Field name = Enum.class.getDeclaredField("name");
    name.setAccessible(true);
    name.set(fastAsleep, "FAST_ASLEEP");
    System.out.println("fastAsleep = " + fastAsleep);
  }
}

This creates enum instances, but for a better approach, please see my newsletter 161.

This SilentObjectCreator could of course also be used to create Singleton instances, even if we were very careful to protect ourselves against that. For example:

public class Singleton {
  private static final Singleton instance = new Singleton();

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

  public static Singleton getInstance() {
    return instance;
  }

  // etc.
}

We can now easily make several instances of this, despite the check in the constructor, by simply instantiating it with the SilentObjectCreator class.

Disclaimer

We should avoid using sun.* classes in our code directly, as it is then not portable and will break if we change JDKs. In my original article, I did not mention this (on purpose) as I assume that readers of an advanced Java newsletter would be aware of this.

Kind regards

Heinz

 

Comments

We are always happy to receive comments from our readers. Feel free to send me a comment via email or discuss the newsletter in our JavaSpecialists Slack Channel (Get an invite here)

When you load these comments, you'll be connected to Disqus. Privacy Statement.

Related Articles

Browse the Newsletter Archive

About the Author

Heinz Kabutz Java Conference Speaker

Java Champion, author of the Javaspecialists Newsletter, conference speaking regular... About Heinz

Superpack '23

Superpack '23 Our entire Java Specialists Training in one huge bundle more...

Free Java Book

Dynamic Proxies in Java Book
Java Training

We deliver relevant courses, by top Java developers to produce more resourceful and efficient programmers within their organisations.

Java Consulting

We can help make your Java application run faster and trouble-shoot concurrency and performance bugs...