Skip to content

The Porting to 11 Theory - The QName Distraction

If you have been using Java for quite some time (since 1.4) and wanted to maintain binary data compatibilitiy, chances are high, that you are relying on the com.sun.xml.namespace.QName.useCompatibleSerialVersionUID=1.0 system property. This will ensure your JVM creates and reads serialized javax.xml.namespace.QName Objects with the same serialisation version UID compatibleSerialVersionUID = 4418622981026545151L. This is especially needed, if you use serialization to store or transmit object trees containing XML objects (and you did not serialize the XML to actual text).

The actual serialVersionUID of QName is meanwhile -9120448754896609940L, but with the compatibility hack you did not only generate objects with the compatible version, but also accepted them.

When you move to Java beyond 8 however, this might break. The backward compatible logic has been removed in JAXP of Java 11. This means your QName instances saved with a not so old Java runtime of 8 (but with the compatibility flag set), suddenly do not work anymore.

Bummer. This is one of the reasons why it is important to follow up on such compatibility hacks and fix them for good. Otherwise it will bite you when you port to newer Java versions just a few decades later.

In JDK11 the compatibility function was removed, with a somewhat sarcastic comment:

  // tests show that the ID is the same from JDK 1.5 through JDK 9
  private static final long serialVersionUID = -9120448754896609940L;

Certainly JDK 1.5 up until 10 did use the default UID, but not if you had used the compatibility flag the whole time.

So the following test code will demonstrates the servialVersionUIDs returned by different Java versions, with and without the compat flag:

Runtime: OpenJDK 64-Bit Server VM 1.8.0_212-b04/25.212-b04 on Windows 10 10.0
 com.sun.xml.namespace.QName.useCompatibleSerialVersionUID=1.0
Created QName: {http://eckenfels.net}bernd  with UID 4418622981026545151
Serialized: rO0ABXNyABlqYXZheC54bWwubmFtZXNwYWNlLlFOYW1lPVIaMLx2_f8CAA...dAAA

Runtime: OpenJDK 64-Bit Server VM 1.8.0_212-b04/25.212-b04 on Windows 10 10.0
 com.sun.xml.namespace.QName.useCompatibleSerialVersionUID=N/A
Created QName: {http://eckenfels.net}bernd  with UID -9120448754896609940
Serialized: rO0ABXNyABlqYXZheC54bWwubmFtZXNwYWNlLlFOYW1lgW2oLfw73WwCAA...dAAA


Runtime: OpenJDK 64-Bit Server VM 11.0.1+13-LTS/11.0.1+13-LTS on Windows 10 10.0
 com.sun.xml.namespace.QName.useCompatibleSerialVersionUID=N/A
Created QName: {http://eckenfels.net}bernd  with UID -9120448754896609940
Serialized: rO0ABXNyABlqYXZheC54bWwubmFtZXNwYWNlLlFOYW1lgW2oLfw73WwCAA...dAAA

Runtime: OpenJDK 64-Bit Server VM 11.0.1+13-LTS/11.0.1+13-LTS on Windows 10 10.0
 com.sun.xml.namespace.QName.useCompatibleSerialVersionUID=1.0
Created QName: {http://eckenfels.net}bernd  with UID -9120448754896609940
Serialized: rO0ABXNyABlqYXZheC54bWwubmFtZXNwYWNlLlFOYW1lgW2oLfw73WwCAA...dAAA

As you can see, on the JDK11 the compat flag is ignored: only the new default serialVersion UID is used.

With a little modified ObjectInputStream (and there are many reasons to have a custom OIS, like this replacement, but also for hooking into modularized classloaders or doing object filtering) all variantes can be read without the need for a compat flag:

Runtime: OpenJDK 64-Bit Server VM 1.8.0_212-b04/25.212-b04 on Windows 10 10.0
 com.sun.xml.namespace.QName.useCompatibleSerialVersionUID=1.0

Deserialize Old
 Default OIS read: {http://eckenfels.net}bernd
 My OIS read: {http://eckenfels.net}bernd

Deserialize Default
 Default OIS failed: java.io.InvalidClassException: javax.xml.namespace.QName; local class incompatible: stream classdesc serialVersionUID = -9120448754896609940, local class serialVersionUID = 4418622981026545151
 My OIS read: {http://eckenfels.net}bernd


Runtime: OpenJDK 64-Bit Server VM 11.0.1+13-LTS/11.0.1+13-LTS on Windows 10 10.0
 com.sun.xml.namespace.QName.useCompatibleSerialVersionUID=N/A

Deserialize Old
 Default OIS failed: java.io.InvalidClassException: javax.xml.namespace.QName; local class incompatible: stream classdesc serialVersionUID = 4418622981026545151, local class serialVersionUID = -9120448754896609940
 My OIS read: {http://eckenfels.net}bernd

Deserialize Default
 Default OIS read: {http://eckenfels.net}bernd
 My OIS read: {http://eckenfels.net}bernd

The code for this tester can be found in a GitHub Gist (including test vectors and complete sample output).

Trackbacks

Keine Trackbacks

Kommentare

Ansicht der Kommentare: Linear | Verschachtelt

Noch keine Kommentare

Kommentar schreiben

BBCode-Formatierung erlaubt
Umschließende Sterne heben ein Wort hervor (*wort*), per _wort_ kann ein Wort unterstrichen werden.
Die angegebene E-Mail-Adresse wird nicht dargestellt, sondern nur für eventuelle Benachrichtigungen verwendet.
Um einen Kommentar hinterlassen zu können, erhalten Sie nach dem Kommentieren eine E-Mail mit Aktivierungslink an ihre angegebene Adresse.

Um maschinelle und automatische Übertragung von Spamkommentaren zu verhindern, bitte die Zeichenfolge im dargestellten Bild in der Eingabemaske eintragen. Nur wenn die Zeichenfolge richtig eingegeben wurde, kann der Kommentar angenommen werden. Bitte beachten Sie, dass Ihr Browser Cookies unterstützen muss, um dieses Verfahren anzuwenden.
CAPTCHA