31
Aug
11

Backward compatibility Object Serialization in Java

Breaking object-serialization in Java is easy. Just change some fields in the used DTOs transfered via network and whooopp its broken.

I came along this topic as i tried some openjdk contribution.

The contribution was to same exceptions that are extending RuntimeException but not supporting the 2 conventional constructors with the exception cause.

There are 10 Exception where i found a seperate cause field.

1. javax/xml/crypto/NoSuchMechanismException.java:    private Throwable _exception;
2. javax/security/sasl/SaslException.java:    private Throwable _exception;
3. java/lang/reflect/UndeclaredThrowableException.java:    private Throwable undeclaredThrowable;
4. java/lang/reflect/InvocationTargetException.java:    private Throwable target;
5. java/lang/ClassNotFoundException.java:    private Throwable ex;
6. com/sun/java/browser/dom/DOMAccessException.java:    private Throwable ex;
7. com/sun/java/browser/dom/DOMUnsupportedException.java:    private Throwable ex;
8. javax/naming/NamingException.java:    protected Throwable rootException = null;
9. java/rmi/RemoteException.java:    public Throwable detail;
10. java/rmi/activation/ActivationException.java:    public Throwable detail;

Nr. 1 was the first i have looked at. My first attempt was to just remove the cause field add the missing constructors and remove the unnessacery methods for printing the stacktrace. But this definitly break serialisation compatibility. The serialversionUID is the same but the serialization content is missing the cause field.

My second attempt was to add the cause field in serialization manually through introducing something like this.

  65     private static final ObjectStreamField[] serialPersistentFields = {
  66         new ObjectStreamField("cause", Throwable.class)};
 114     private void readObject(ObjectInputStream stream)
 115             throws IOException, ClassNotFoundException {
 116         initCauseFieldFromSerializationStream(stream, "cause");
 117     }
 118
 119     private void writeObject(ObjectOutputStream stream)
 120             throws IOException {
 121         writeCauseAsAPrivateField(stream, "cause");
 122     }

While introducing the following in Throwable.java

1097     protected void initCauseFieldFromSerializationStream(ObjectInputStream stream, String oldFieldName) throws ClassNotFoundException, IOException {
1098         GetField readFields = stream.readFields();
1099         Throwable cause = (Throwable) readFields.get(oldFieldName, this);
1100         /* If there is a cause that is deserialized and there is no cause
1101          * set in Throwable.cause (== null means serialized prior jdk8)
1102          * then initialize cause. There is another implicit functionality here:
1103          * If Throwable.cause is initialized yet(since jdk8) and
1104          * this.getCause() != cause then there is something is rotten in the
1105          * state of Denmark. Calling initCause in this situation will result
1106          * in an exception
1107          */
1108         if (cause != null && this.getCause() != cause) {
1109             // If cause is
1110             initCause(cause);
1111         }
1112     }
1131     protected void writeCauseAsAPrivateField(ObjectOutputStream stream, String oldFieldName) throws IOException {
1132         PutField putFields = stream.putFields();
1133         if (this.getCause() != null) {
1134             putFields.put(oldFieldName, this.cause);
1135         }
1136         stream.writeFields();
1137     }

This might be ok. But it is somewhat the otherway around this problem is solved already in
the other cases mentioned above. The other solution leaves the cause field but utilizes the
functionality of chaining in Throwable in an much easier fashion.

But this will be part of another post.

Advertisement

0 Responses to “Backward compatibility Object Serialization in Java”



  1. Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s


Follow

Get every new post delivered to your Inbox.