Good morning,

I'm busy writing an article for a German magazine. Even though I speak and write German, it is not at the level where I would be able to write a decent article. Plus I write much quicker and more creatively in English. The article consists of several short sections about various topic that every advanced Java programmer should know. They don't have to be a master of any of them, but just enough to understand the implications. Please don't forward this, it is only for my email subscribers of The Java(tm) Specialists' Newsletter :-) It will also not be available on my website, but will be in the print version of the magazine - but in German :-)

Any feedback is of course highly appreciated - just reply to the email.

The first section is on Object Serialization:

At a recent panel discussion, the Java Architects were asked what their biggest regret was about Java. They seemed to agree that Serialization was pretty high up on their list. What is it, why do you need to know about it, and how much could you possibly configure?

Serialization was added in Java 1.1 to allow us to persist objects. It was designed to work transitively, which means that if our object pointed to another object, both would be persisted. It is smart enough to manage circular references without resulting in a StackOverflowError.

But why would the Java Architects feel that this was one of their biggest regrets? In Java 8, java.io.Serializable is implemented or extended 5237 times. And each time any of these classes is modified, it needs to also keep the same serializable format, otherwise existing systems might break. It is a very expensive "ball and chain". No wonder the JavaDoc lists author as "unascribed". No one wants to take responsibility!

One interesting example where I contributed a bit of code to the JDK was ThreadLocalRandom. In Java 7, this was implemented as a ThreadLocal with different thread-confined instances for each thread. In Java 8 they changed this into a Singleton. ThreadLocalRandom is Serializable. You might wonder what the point was of doing this in the first place? ThreadLocalRandom extends java.util.Random and that is Serializable, so all the subclasses need to support this contract. Blame Liskov.

In Java 7, the only thing that ThreadLocalRandom did special was to add the serialVersionUID. It is risky for this number to be automatically generated as some compilers might generate anonymous inner class accessor methods, also called synthetic methods, differently. The result is that different compilers might result in classes with varient serialVersionUIDs.

In Java 8, they substantially changed the structure of ThreadLocalRandom to be a Singleton. However, serialization needs to transcend versions. The serial format of a class should not change between versions of Java. Thus a Java 8 ThreadLocalRandom class should be able to read a Java 7 ThreadLocalRandom object, and vice versa. This is the ball-and-chain that the architects were complaining about. How did they do it?

They firstly added a special field:

private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("rnd", long.class),
new ObjectStreamField("initialized", boolean.class),
};

The Java 8 Singleton version of ThreadLocalRandom stores the random fields in the Thread class itself. It does not have any non-static fields. But the serialPersistentFields array pretends that it does have two fields, "rnd" and "initialized".

The next step is to add a private writeObject(), which allows us to write data that a Java 7 JVM would expect to see when deserializing a ThreadLocalRandom:

private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {

java.io.ObjectOutputStream.PutField fields = s.putFields();
fields.put("rnd", U.getLong(Thread.currentThread(), SEED));
fields.put("initialized", true);
s.writeFields();
}

Lastly, we needed to consider how Java 8 should react if someone tried to deserialize a ThreadLocalRandom. Remember that it is now implemented as a Singleton and thus we should avoid multiple instances. They did this by adding a readResolve() method. This is called after the object has been deserialized already and it simply calls the accessor method, in our case called current()

private Object readResolve() {
return current();
}

Whilst we were changing this code, we were asking ourselves whether anyone had ever serialized a ThreadLocalRandom. In a way, it would have been better to have published a writeObject() method in Java 7 that could say

private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
throw new java.io.NotSerializableException("Don't be silly");
}

One place where the JDK engineers put their foot down was with Optional. Since it's meant to be a return type and not a field, they did not make it Serializable. And as you might imagine, this is the biggest complaint that programmers have about that class. Because, well, they want to use it as a field :-) After all, 5237 other classes are serializable, why not Optional?

Oh and lambdas. They had to invent a special syntax to allow them to be Serializable. When I introduce Java 8, I normally say that lambdas are a short-hand for anonymous inner classes. This is not completely accurate, but in 99.9% of the cases it is close enough. One place where they differ is that an anonymous inner class can only implement one interface, not two. Thus you cannot write

Object serializableTask = new Runnable() & Serializable() {
public void run() {
System.out.println("Some task");
}
};

But you can with lambdas write the following:

Object serializableTask = (Runnable & Serializable) () ->
System.out.println("Some task");

Serializable has many other complexities that we won't go into in this article. It's something that an advanced Java programmer needs to understand, but where beginners can simply mark their classes as "Serializable" and add the serialVersionUID.

Kind regards from Poznan

Heinz


If you no longer wish to receive our emails, click the link below:

https://iw127.infusionsoft.com/app/optOut/8/a6ca3d5100f0d052/5038204/23515b1838fd14db

Cretesoft Limited 77 Strovolos Ave Strovolos, Lefkosia 2018 Cyprus