O que é o serialVersionUID?

O que é o serialVersionUID?

1. Visão geral

Simplificando,the serialVersionUID is a unique identifier for Serializable classes.

Isso é usado durante a desserialização de um objeto, para garantir que uma classe carregada seja compatível com o objeto serializado. Se nenhuma classe correspondente for encontrada, umInvalidClassException é lançado.

2. Exemplo

Vamos começar criando uma classe serializável e declarar um identificadorserialVersionUID:

public class AppleProduct implements Serializable {

    private static final long serialVersionUID = 1234567L;

    public String headphonePort;
    public String thunderboltPort;
}

Em seguida, precisaremos de duas classes de utilitários: uma para serializar um objetoAppleProduct em umString,e outra para desserializar o objeto daqueleString:

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;
    }
}

Começamos executandoSerializationUtility.java, que salva (serializa) o objetoAppleProduct em uma instânciaStringe, codificando os bytes usandoBase64.

Em seguida, usando esseString como um argumento para o método de desserialização, executamosDeserializationUtility.java, que remonta (desserializa) o objetoAppleProduct doString. fornecido

A saída gerada deve ser semelhante a esta:

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 o objetoAppleProduct da mesma String produzida anteriormente. Executar novamenteDeserializationUtility.java deve gerar esta saída.

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)

Alterando oserialVersionUID da classe, modificamos sua versão / estado. Como resultado, nenhuma classe compatível foi encontrada durante a desserialização e umInvalidClassException foi lançado.

3. Exemplo - Adicionar Novo Campo a uma Classe Existente

Digamos que precisamos adicionar um novo campolightningPort à nossa classeAppleProduct existente:

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

Como estamos apenas adicionando um novo campo,no change in the serialVersionUID will be required. Isso ocorre porqueduring the deserialization process, null will be assigned as the default value for the lightningPort field.

Vamos modificar nossa classeDeserializationUtility para imprimir o valor deste novo campo:

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

Agora, quando executarmos novamente a classeDeserializationUtility, veremos uma saída semelhante a:

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

4. Conclusão

Neste artigo rápido, demonstramos o uso da constanteserialVersionUID para facilitar o controle de versão de dados serializados.

Como sempre, os exemplos de código usados ​​em todo este artigo podem ser encontradosover on GitHub.