Question

I have a class which is intended for immutable use, hence I would like to label all the fields final.

However the class is serialized and deserialized to send over the network. For this to work an empty constructor is required. This prevents me creating the final fields.

I'm sure this is a fairly common problem but I can't find a solution. How should I proceed?

Was it helpful?

Solution

In the typical serialization case, it is not required that class have an empty constructor or non-final fields to be serializable.

Now, if you have to do your own serialization, or you need to subclass a class that doesn't implement Serializable, that is a different story.

So you need to provide some more details of how you are having a problem.

OTHER TIPS

A no-arg constructor is not required. The most derived non-serialisable class does need a no-arg constructor available to the least-most derived serialisable class.

If you need to mutate fields inside a readObject, then use a serial proxy through readResolve and writeReplace.

This issue is an open bug on the Java language. (Note that this only applies if you have to do the serialization manually, such as with readObject)

To echo what has been said, no-arg constructors are not a requirement if you are taking the route of implementing the java.io.Serializable interface. Take a look at the java.lang.Integer source code for example, a simple serializable/immutable class that has two constructors: one that takes an int, and one that takes a String. Source code: http://www.docjar.com/html/api/java/lang/Integer.java.html. Javadoc: http://java.sun.com/javase/6/docs/api/java/lang/Integer.html.

Also depending on the complexity of your class and what you are doing, you could consider implementing serialization via the java.io.Externalizable interface (although some consider it outdated, and it DOES require a no-arg constructor). Here's an overview on SO: What is the difference between Serializable and Externalizable in Java?, and here's the official Java tutorial: http://java.sun.com/docs/books/tutorial/javabeans/persistence/index.html.

For the record, since I had a similar issue:
I had a message "java.io.InvalidClassException: com.example.stuff.FooBar; com.example.stuff.FooBar; no valid constructor"

I thought it was because it was lacking a default constructor. But the above answers confirm it is not mandatory (but our app. uses an old serializer that indeed require a default constructor, so the case can arise).

Then I found a page stating:

If a class that is designed for inheritance is not serializable, it may be impossible to write a serializable subclass. Specifically, it will be impossible if the superclass does not provide an accessible parameterless constructor.

Hence the message I got, I suppose. It appeared that the core issue was classical: I declared a class as serializable, but the superclass was not! I moved the Serializable interface up in the hierarchy, and all was well.

But the message was a bit misleading... :-)

A no-arg constructor is not required. Let's read the source code:

// java.io.ObjectStreamClass
private static Constructor<?> getSerializableConstructor(Class<?> cl) {
    Class<?> initCl = cl;
    while (Serializable.class.isAssignableFrom(initCl)) {
        if ((initCl = initCl.getSuperclass()) == null) {
            return null;
        }
    }
    ...
}

So, actually the no-arg constructor is required in the nearest not Serializable class in the type hierarchy.

It means the following class Domain can be serialized.

class Domain implements Serializable {
    private final int a;

    public Domain(int a) {
      this.a = a;
    }
}

But the class Son can't:

class Father{
  private final int a;

  public Father(int a) {
    this.a = a;
  }
}

class Son extends Father implements Serializable {
  public Son(int a) {
    super(a);
  }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top