Entendendo o serialVersionUID - JAVA
Autor: UMC | Publicado: 2012-03-28T15:18:00-03:00


O&nbsp;serialVersionUID&nbsp;é uma dúvida constante entre muitos desenvolvedores. Afinal, quando e para que exatamente usá-lo? Devo gerar um número aleatório bem grande, ou um número qualquer? Essas perguntas são comuns, e ao desenvolvedor experiente é necessário conhecer a fundo esse detalhe do&nbsp;processo de serialização do Java.

Quando um objeto é serializado no Java, essa sequência de bytes, além de conter seus atributos de instância não transientes, carrega consigo um número que indentifica a “versão” da classe que foi usada durante o processo. Esse é o chamado&nbsp;serialVersionUID, ou seja, o indentificador de versão de serialização de uma classe. Esse número é utilizado para saber se o objeto que estamos recuperando é de uma versão “compatível” com a versão da classe que foi utilizada quando serializamos o objeto: em outras palavras, os arquivos&nbsp;.class&nbsp;não precisam ser necessariamente os mesmos para que o processo de serialização ocorra com sucesso.

Por exemplo, considere a seguinte classe&nbsp;Usuario:





package br.com.caelum;

&nbsp;

public class Usuario implements Serializable {

&nbsp;&nbsp;private String login;

}






Essa classe possui o&nbsp;serialVersionUID&nbsp;igual a&nbsp;2806421523585360625L.&nbsp;Esse número não é aleatório! Ele é um hash (SHA) calculado em cima dos nomes dos seus atributos, e assinaturas dos métodos em uma ordem bem definida&nbsp;pela especificação do processo de serialização. E como eu sei esse número? O JDK vem com a ferramenta&nbsp;serialver, que implementa esse mesmo hash:

serialver br.com.caelum.Usuario

Se o&nbsp;serialVersionUID&nbsp;utilizado durante a serialização não bater exatamente com oserialVersionUID&nbsp;da classe que está sendo usada para recuperar essa informação, uma exception é lançada:&nbsp;java.io.InvalidClassException.

Por exemplo, se adicionarmos um novo atributo na nossa classe&nbsp;Usuario:





public class Usuario implements Serializable {

&nbsp;&nbsp;private String login;

&nbsp;&nbsp;private String senha;

}






Agora teremos o&nbsp;serialVersionUID&nbsp;valendo&nbsp;416295346730660862L. Caso você serialize umUsuario&nbsp;com a primeira classe aqui definida, e tentar recuperar essa informação usando essa nova versão de classe, receberemos a conhecida&nbsp;java.io.InvalidClassException. Esse é o comportamente que em muitos casos queremos, mas algumas vezes fazemos pequenas modificações na classe as quais percebemos que não impactarão no processo de serialização, e precisamos manter compatibilidade com a versão antiga daquela classe. Para isso, basta definirmos explicitamente qual é o nosso&nbsp;serialVersionUID, e no caso de querer manter compatibilidade com a classe&nbsp;Usuario&nbsp;anterior, vamos utilizar o valor de&nbsp;serialVersionUID&nbsp;que seria gerado pela JVM:&nbsp;2806421523585360625L. O código ficaria:





public class Usuario implements Serializable {

&nbsp;&nbsp;private static final long serialVersionUID = 2806421523585360625L;

&nbsp;&nbsp;private String login;

&nbsp;&nbsp;private String senha;

}






Às vezes recebemos um warning do Eclipse, e ele pede para que seja definido oserialVersionUID&nbsp;da classe em questão. Isso ocorre porque você implementa&nbsp;Serializable&nbsp;ou uma de suas mães a implementa. O Eclipse então te abre três opções: utilizar o@SurpressWarnings&nbsp;para você assumir o risco, usar um valor default, ou usar o valor gerado. O gerador de UIDs do Eclipse é exatamente o mesmo gerador utilizado pelo Java SE para criar os UIDs padrão! Reforçando,&nbsp;esse número não é um número aleatório!

Quando alguém esquece de manter o mesmo&nbsp;serialVersionUID&nbsp;para duas versões compatíveis de uma classe, podemos ter problemas em usar diferentes versões do software que são teoricamente compatíveis. Isso muitas vezes acontece em servidores de aplicação, e se seu cliente esta desatualizado em relação a versão dos jars necessários pelo servidor, podemos ter algunsInvalidClassExceptions que poderiam ser facilmente evitados se o&nbsp;serialVersionUID&nbsp;tivesse sido corretamente aplicado. Claro que algumas outras vezes as versões realmente não são compatíveis e a exception procede.

Esse grave problema pode acontecer mesmo usando classes do Java SE entre diferentes versões, como é o caso da classe&nbsp;java.text.AttributedCharacterIterator.Attribute&nbsp;(utilizada pelajava.awt.Font). Do Java 1.3 para o Java 1.4 essa classe foi levemente alterada, e oserialVersionUID&nbsp;gerado pelo algoritmo da JVM desta classe mudou&nbsp;de-1514471214376796190L&nbsp;para&nbsp;-9142742483513960612L. Quando alguém serializava umajava.awt.Font&nbsp;em uma versão não podia desserializa-la em outra, sendo que as versões tecnicamente são compatíveis: a não definição explícita do&nbsp;serialVersionUID&nbsp;gerou um bug no Java SE. Como isto foi resolvido? Definiram o&nbsp;serialVersionUID&nbsp;como&nbsp;-1514471214376796190L, que é o valor que seria gerado pela JVM na versão anterior da classe.

Como então devemos proceder para escolher um&nbsp;serialVersionUID&nbsp;apropriado? É muito simples: se essa classe está nascendo neste momento, você pode se dar ao luxo de utilizar umserialVersionUID, como por exemplo:





public class Usuario implements Serializable {

&nbsp;&nbsp;private static final long serialVersionUID = 1L;

&nbsp;&nbsp;private String login;

}






Porém se você está definindo o&nbsp;serialVersionUID&nbsp;de uma classe já em produção, e sabe que a mudança que está fazendo é compatível com a versão anterior, você deve utilizar oserialVersionUID&nbsp;que seria gerado pela JVM na primeira versão, como foi o caso aqui quando adicionamos o atributo&nbsp;senha&nbsp;na classe&nbsp;Usuario, e também foi o caso da correção do bug da classe&nbsp;java.text.AttributedCharacterIterator.Attribute. Quando você fizer uma alteração onde percebe que o cliente precisará de atualização das classes envolvidas, basta definir um&nbsp;serialVersionUID&nbsp;diferente dos anteriormente utilizados.

Para completar, implementar uma interface que não define métodos (Serializable) e ser forçado a escrever um atributo sem um contrato mais burocrático é um tanto estranho em uma linguagem como o Java. Sem dúvida, se esse mecanismo todo tivesse sido inventado já com a existência de anotações,&nbsp;Serializable&nbsp;seria uma anotação e&nbsp;version&nbsp;um atributo dela, talvez obrigatório, criando algo como&nbsp;@Serializable(version=12345L). Boas serializações e invocações remotas!

Fonte: http://blog.caelum.com.br/entendendo-o-serialversionuid/