Quel est le serialVersionUID?

Quel est le serialVersionUID?

1. Vue d'ensemble

En termes simples,the serialVersionUID is a unique identifier for Serializable classes.

Ceci est utilisé lors de la désérialisation d'un objet, pour s'assurer qu'une classe chargée est compatible avec l'objet sérialisé. Si aucune classe correspondante n'est trouvée, unInvalidClassException est renvoyé.

2. Exemple

Commençons par créer une classe sérialisable et déclarons un identifiantserialVersionUID:

public class AppleProduct implements Serializable {

    private static final long serialVersionUID = 1234567L;

    public String headphonePort;
    public String thunderboltPort;
}

Ensuite, nous aurons besoin de deux classes d'utilitaires: une pour sérialiser un objetAppleProduct en unString, et une autre pour désérialiser l'objet de ceString:

public class SerializationUtility {

    public static void main(String[] args) {
        AppleProduct macBook = new AppleProduct();
        macBook.headphonePort = "headphonePort2020";
        macBook.thunderboltPort = "thunderboltPort2020";

        String serializedObj = serializeObjectToString(macBook);

        System.out.println("Serialized AppleProduct object to string:");
        System.out.println(serializedObj);
    }

    public static String serializeObjectToString(Serializable o) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(o);
        oos.close();

        return Base64.getEncoder().encodeToString(baos.toByteArray());
    }
}
public class DeserializationUtility {

    public static void main(String[] args) {

        String serializedObj = ... // ommited for clarity
        System.out.println(
          "Deserializing AppleProduct...");

        AppleProduct deserializedObj = (AppleProduct) deSerializeObjectFromString(
          serializedObj);

        System.out.println(
          "Headphone port of AppleProduct:"
            + deserializedObj.getHeadphonePort());
        System.out.println(
          "Thunderbolt port of AppleProduct:"
           + deserializedObj.getThunderboltPort());
    }

    public static Object deSerializeObjectFromString(String s)
      throws IOException, ClassNotFoundException {

        byte[] data = Base64.getDecoder().decode(s);
        ObjectInputStream ois = new ObjectInputStream(
          new ByteArrayInputStream(data));
        Object o = ois.readObject();
        ois.close();
        return o;
    }
}

Nous commençons par exécuterSerializationUtility.java, qui enregistre (sérialise) l'objetAppleProduct dans une instanceStringe, encodant les octets en utilisantBase64.

Ensuite, en utilisant ceString comme argument pour la méthode de désérialisation, nous exécutonsDeserializationUtility.java, qui réassemble (désérialise) l'objetAppleProduct à partir desString. donnés

La sortie générée devrait ressembler à ceci:

Serialized AppleProduct object to string:
rO0ABXNyACljb20uYmFlbGR1bmcuZGVzZXJpYWxpemF0aW9uLkFwcGxlUHJvZHVjdAAAAAAAEta
HAgADTAANaGVhZHBob25lUG9ydHQAEkxqYXZhL2xhbmcvU3RyaW5nO0wADmxpZ2h0ZW5pbmdQb3
J0cQB+AAFMAA90aHVuZGVyYm9sdFBvcnRxAH4AAXhwdAARaGVhZHBob25lUG9ydDIwMjBwdAATd
Gh1bmRlcmJvbHRQb3J0MjAyMA==
Deserializing AppleProduct...
Headphone port of AppleProduct:headphonePort2020
Thunderbolt port of AppleProduct:thunderboltPort2020

Now, let’s modify the serialVersionUIDconstant in AppleProduct.java, and reattempt to deserialize l'objetAppleProduct de la même chaîne produite précédemment. La réexécution deDeserializationUtility.java devrait générer cette sortie.

Deserializing AppleProduct...
Exception in thread "main" java.io.InvalidClassException: com.example.deserialization.AppleProduct; local class incompatible: stream classdesc serialVersionUID = 1234567, local class serialVersionUID = 7654321
    at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1630)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1521)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1781)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1353)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:373)
    at com.example.deserialization.DeserializationUtility.deSerializeObjectFromString(DeserializationUtility.java:24)
    at com.example.deserialization.DeserializationUtility.main(DeserializationUtility.java:15)

En changeant lesserialVersionUID de la classe, nous avons modifié sa version / état. En conséquence, aucune classe compatible n'a été trouvée lors de la désérialisation et unInvalidClassException a été renvoyé.

3. Exemple - Ajouter un nouveau champ à une classe existante

Disons que nous devons ajouter un nouveau champlightningPort à notre classeAppleProduct existante:

public class AppleProduct implements Serializable {
//...
    public String lightningPort;
}

Puisque nous ajoutons simplement un nouveau champ,no change in the serialVersionUID will be required. C'est parce que,during the deserialization process, null will be assigned as the default value for the lightningPort field.

Modifions notre classeDeserializationUtility pour afficher la valeur de ce nouveau champ:

System.out.println("LightningPort port of AppleProduct:"
  + deserializedObj.getLightningPort());

Maintenant, lorsque nous réexécutons la classeDeserializationUtility, nous verrons une sortie similaire à:

Deserializing AppleProduct...
Headphone port of AppleProduct:headphonePort2020
Thunderbolt port of AppleProduct:thunderboltPort2020
Lightning port of AppleProduct:null

4. Conclusion

Dans cet article rapide, nous avons démontré l'utilisation de la constanteserialVersionUID pour faciliter la gestion des versions des données sérialisées.

Comme toujours, les exemples de code utilisés tout au long de cet article peuvent être trouvésover on GitHub.