Recently I found out that some classes compiled by Java (Java 8) and by ajc (v.1.9.2) are not serialization-compatible. By serialization-compatibility I mean that calculated default serialVersionUID are not same.
Example:
public class Markup implements Serializable {
private final MyUnit unit;
public Markup(MyUnit unit) { this.unit = unit; }
public enum MyUnit { DOUBLE, STRING }
public static void main(String[] args) throws IOException, ClassNotFoundException {
Path path = Paths.get("markup.bin");
if (args.length == 0) {
try (OutputStream fileOutput = Files.newOutputStream(path);
ObjectOutputStream objectOutput = new ObjectOutputStream(fileOutput))
{
objectOutput.writeObject(new Markup(MyUnit.STRING));
}
} else {
try (InputStream fileInput = Files.newInputStream(path);
ObjectInputStream objectInput = new ObjectInputStream(fileInput))
{
System.out.println(objectInput.readObject());
}
}
}
static String switchType(MyUnit unit) {
switch (unit) {
case STRING: return "%";
case DOUBLE: return "p";
default: return "Undefined";
}
}
}
When I compile this class by ajc and run, and then compile this class by javac and run I get exception about incompatibility of serialization format:
Exception in thread "main" java.io.InvalidClassException: Markup; local class incompatible: stream classdesc serialVersionUID = -1905477862550005139, local class serialVersionUID = 793529206923536473
I also found out that's it's because of ajc switch code generator. It creates additional field in class private static int[] $SWITCH_TABLE$Markup$MyUnit
Fields generated by javac:
Fields generated by ajc:
My questions are:
- Is it allowed by specification for java compiler to generate fields which are not defined in the class?
- Why ajc generates additional field? Some sort of performance optimization?
- Are there any way to make ajc to not generate additional field?
- What the reason why
private static
affects generation of serialVersionUID ? - Are developers of aspectj aware of this behavior? If so, why they choose generate field anyway?
- Are there any guarantees how Java class will be serialized by JLS?
- How Javac-generated code works without this field?