views:

357

answers:

4

Consider the following Java exception classes:

public class FooException extends RuntimeException {
    // [...]
}

public class FooException extends BarException {
    private static final long serialVersionUID = -5322002268075295537L;

    // [...]
}

If I wish to update the inheritance hierarchy to remove BarException, such that FooException derives directly from RuntimeException, does this require a change to the serialVersionUID value?

// FooException with updated inheritance hierarchy
public class FooException extends RuntimeException {
    private static final long serialVersionUID = ???;

    // [...]
}
+1  A: 

The Java 1.5 Serialization Specification suggests that removing classes from the inheritance hierarchy is a compatible change, so a change to serialVersionUID should not be required.

Any extra information in the serialization stream pertaining to BarException would be ignored when deserializing to the new FooException (which is derived directly from RuntimeException).

Daniel Fortunov
You're probably referring to the "Removing classes" point, but I think that only covers completely removing classes, not removing them from inside the inheritance tree while keeping subclasses - it's a case of "Moving classes up or down the hierarchy"
Michael Borgwardt
There is in a method for handling reading an object with a missing class - `readObjectNoData`.
Tom Hawtin - tackline
I'm not sure that the spec is entirely consistent. Deleting a field is not okay, but an entire class is?
Tom Hawtin - tackline
It's a bit strange - removing a class necessarily means removing or changing all fields using that type. And I can't find "changing a (non-primitive) field's type" in either the compatible or the incompatible list.
Michael Borgwardt
+3  A: 

Yes. "Moving classes up or down the hierarchy" will cause incompatibility with previous serialized instances, as per the serialization spec.

Michael Borgwardt
A: 

Technically yes, but it depends on whether your system persists serialized objects and if you control how the new, refactored code is deployed.

If you don't do persistence and you will refresh the entire deployment with the new version of the code, I don't see the need to change the serialVersionUID.

hbunny
Hi Steve. As noted in the update to my question, "As long as I keep the serialVersionUID unchanged, I can successfully serialize and deserialize the original FooException as the updated FooException, and vice versa." This change does not seem to break serialization compatibility, so even if the system is persisting serialized objects, and I don't refresh the entire deployment at once, should I still change the serialVersionUID?
Daniel Fortunov
Short answer is I'm unsure - why not test it? I find the standard Java serialization brittle and it wouldn't surprise me if this worked (or even if it didn't)!
hbunny
A: 

Given that the specification is unclear enough to cause confusion and debate, with no clear answer emerging, the only option left is to trust empirical evidence.

Taking the examples from the question above, of FooException deriving from BarException deriving from RuntimeException, and then removing BarException from the inheritance chain, I put together a sample application to try serialization and de-serialization in various combinations.

I get the following results:

As long as I keep the serialVersionUID unchanged, I can successfully serialize and deserialize the original FooException as the updated FooException, and vice versa.

The following caveats apply:

  • I am using JDK 1.5.0_07, and have not tried this on any other versions.
  • FooException has members of type int and Exception, which are successfully deserialized.
  • BarException adds no additional members to RuntimeException.
Daniel Fortunov