FULL PRODUCT VERSION :
java version "1.6.0"
Java(TM) SE Runtime Environment (build 1.6.0-b105)
Java HotSpot(TM) Client VM (build 1.6.0-b105, mixed mode, sharing)
On both OS's
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600 italian]
Debian Etch
A DESCRIPTION OF THE PROBLEM :
There seems to be a major problem introduced with serialization in version 1.6.0. The problem here described only happens with Java 1.6.0, and it has been tried with Java 1.5.07 and 1.5.09 both on Debian and Windows XP, and causes no problem on these releases.
We have an application that has classes that extend both java.awt.geom.Line2D.Double and java.awt.geom.Arc2D.Double, which in J2SE5 are NOT serializable. These classes, that in our case are called Line and Arc implement the Serializable interface. Please note that in Java 6 Line2D.Double and Arc2D.Double have been fixed and are now natively serializable.
When you try to serialize the Arc class (extends Arc2D.Double implements Serializable), the JVM causes completely unexpected results, throwing an InvalidClassException with message "No valid constructor", thus making it impossible to serialize anything that extends Arc2D.Double.
Please note that a similar class Line, that does nothing but extending Line2D.Double and implements Serializable, will serialize with no problem whatsoever.
This behaviour is observable only with Java 6. We have run several case studies and the following results apply:
Compiling the source with Java 5 and executing with Java 5 leads exatcly what expected with no error.
Compiling with Java 5 and executing with Java 6 causes the unexpected exception.
Compiling with Java 6 and executing with Java 6 causes the unexpected exception.
Therefore, it seems that the problem resides within the JVM code, not within the compiler. The above behaviour is identical in both Windows XP Home edition and Debian Etch.
Please note that the code below, used to reproduce the bug, also exposes another bug (6317435 - http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6317435) in the stack trace it produces. Don't be confused by the stack trace.
Please note that this seems to be a major issue as the behaviour is at the very heart of one of the most commonly used technologies of Java. We noticed it first when upgrading from Java 5 to Java 6 on a Hibernate-based application on a very complex class hierarchy, and by running several tests to narrow down the cause, it resulted to be one of those dreaded bugs that is exposed by a couple of lines of code.
Refer to the code below to reproduce the bug.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Create one simple class that extends Arc2D.Double and implements Serializable. Write another simple class to try to serialize it to a file. Compile and run using Java 6. See the results.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The expected result is to serialize the simple class to a file, and to be able to deserialize it.
ACTUAL -
The application crashed claiming an InvalidClassException - "No valid constructor" message.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.io.InvalidClassException: Arc; Arc; no valid constructor
at java.io.ObjectStreamClass.checkDeserialize(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at SerializationTest.main(SerializationTest.java:20)
Caused by: java.io.InvalidClassException: Arc; no valid constructor
at java.io.ObjectStreamClass.<init>(Unknown Source)
at java.io.ObjectStreamClass.lookup(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at SerializationTest.main(SerializationTest.java:16)
Please note that this stack trace is incorrect, probably due to bug 6317435.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
Create one simple class that extends Arc2D.Double and implements Serializable
------------------------------
import java.awt.geom.Arc2D;
import java.io.Serializable;
public class Arc extends Arc2D.Double implements Serializable {
public Arc() {
}
}
------------------------------
Now create the following test class to try to serialize and de-serialize the above class it to a file:
------------------------------
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializationTest {
public static void main(String args[]) {
Arc a = new Arc();
try {
FileOutputStream fos = new FileOutputStream(new File("object.bin"));
ObjectOutputStream out = new ObjectOutputStream(fos);
out.writeObject(a);
fos.close();
FileInputStream fis = new FileInputStream(new File("object.bin"));
ObjectInputStream in = new ObjectInputStream(fis);
Object o = in.readObject();
fis.close();
System.err.println(o);
}
catch (Throwable ex) {
ex.printStackTrace();
}
}
}
------------------------------
Compile using Java 6.
Run the SerializationTest main program. The program will cause an InvalidClassException with "no valid constructor" message.
---------- END SOURCE ----------