Entendendo o serialVersionUID

Postado em 01. abr, 2008 por em Java

O serialVersionUID é 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 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 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 .class não precisam ser necessariamente os mesmos para que o processo de serialização ocorra com sucesso.

Por exemplo, considere a seguinte classe Usuario:

package br.com.caelum;

public class Usuario implements Serializable {
  private String login;
}

Essa classe possui o serialVersionUID igual a 2806421523585360625L. 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 pela especificação do processo de serialização. E como eu sei esse número? O JDK vem com a ferramenta serialver, que implementa esse mesmo hash:

serialver br.com.caelum.Usuario

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

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

public class Usuario implements Serializable {
  private String login;
  private String senha;
}

Agora teremos o serialVersionUID valendo 416295346730660862L. Caso você serialize um Usuario com a primeira classe aqui definida, e tentar recuperar essa informação usando essa nova versão de classe, receberemos a conhecida 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 serialVersionUID, e no caso de querer manter compatibilidade com a classe Usuario anterior, vamos utilizar o valor de serialVersionUID que seria gerado pela JVM: 2806421523585360625L. O código ficaria:

public class Usuario implements Serializable {
  private static final long serialVersionUID = 2806421523585360625L;
  private String login;
  private String senha;
}

Às vezes recebemos um warning do Eclipse, e ele pede para que seja definido o serialVersionUID da classe em questão. Isso ocorre porque você implementa Serializable ou uma de suas mães a implementa. O Eclipse então te abre três opções: utilizar o @SurpressWarnings 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, esse número não é um número aleatório!

Quando alguém esquece de manter o mesmo serialVersionUID 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 alguns InvalidClassExceptions que poderiam ser facilmente evitados se o serialVersionUID 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 java.text.AttributedCharacterIterator.Attribute (utilizada pela java.awt.Font). Do Java 1.3 para o Java 1.4 essa classe foi levemente alterada, e o serialVersionUID gerado pelo algoritmo da JVM desta classe mudou de -1514471214376796190L para -9142742483513960612L. Quando alguém serializava uma java.awt.Font 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 serialVersionUID gerou um bug no Java SE. Como isto foi resolvido? Definiram o serialVersionUID como -1514471214376796190L, que é o valor que seria gerado pela JVM na versão anterior da classe.

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

public class Usuario implements Serializable {
  private static final long serialVersionUID = 1L;
  private String login;
}

Porém se você está definindo o serialVersionUID 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 o serialVersionUID que seria gerado pela JVM na primeira versão, como foi o caso aqui quando adicionamos o atributo senha na classe Usuario, e também foi o caso da correção do bug da classe 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 serialVersionUID 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, Serializable seria uma anotação e version um atributo dela, talvez obrigatório, criando algo como @Serializable(version=12345L). Boas serializações e invocações remotas!

Paulo Silveira

Mais sobre o autor

Tags: , , , , , , , ,

29 Respostas para “Entendendo o serialVersionUID”

  1. Antonio Lazaro

    01. abr, 2008

    Finalmente uma explicação clara e objetiva sobre a finalidade desse atributo!
    Valeu Paulo

  2. Zinho (Rafael)

    02. abr, 2008

    Muito bom. Vai pro favoritos =D

  3. Joao Paulo

    11. abr, 2008

    vlw mesmo!! aprendi mais uma..

    jopss

  4. Daniel

    22. abr, 2008

    Poderia esclarecer o que acontece quando o serialVersionUID não é definido?

  5. Paulo Silveira

    23. abr, 2008

    Olá Daniel. O quarto parágrafo fala disso. Se você não tem um, a API gera um para você baseado nos seus membros. Você pode ver isso pela ferramenta serialver que vem como o JDK.

  6. Rafael Hulk

    04. mai, 2008

    Direto e claro, muito bom mesmo!

  7. Juarez

    08. mai, 2008

    Muito bom o conteúdo. Minhas dúvidas estão sanadas.

  8. Fernando

    29. mai, 2008

    Para ficar mais claro deveria ter escrito assim: “…e no caso de querer manter compatibilidade com a classe Usuario anterior, vamos utilizar o valor de serialVersionUID” que serialver geraria PARA ESSA VERSÃO ANTERIOR da classe.

  9. Marco Antonio

    25. jun, 2008

    Compilando uma classe que implementa Serializable diretamente com javac, eu não recebo nenhum warning sobre isso. Isso significa que este aviso ou comportamento é uma particularidade do Eclipse e não um padrão do java?

  10. Weberson

    09. jun, 2009

    Perfeito, havia procurado em varios lugares e apenas aqui consegui entender por completo este assunto

  11. Daniel Monti

    29. jun, 2009

    excelente explicação, muito obrigado!

  12. rafael

    07. jul, 2009

    Precisamos mais artigos práticos e objetivos como esse na nossa área

    Parabéns

  13. Manuel

    29. set, 2009

    Muito bom

    Obrigado

  14. Claucia

    21. jan, 2010

    Perfeita a explicação, parabéns.
    Com está explicação agora sei resolver os problemas das minhas classes serializable

  15. Felipe Alexandre Rodrigues

    22. jan, 2010

    Demorei pra encontrar uma boa resposta :)

  16. vitor zachi

    27. mar, 2010

    finalmente uma boa explicação …

    valeu pelo esforço…

  17. Rodrigo Ramalho

    16. mai, 2010

    Direto ao ponto :) Ótimo artigo!

  18. Fernando

    10. out, 2010

    Eu acho esse lance de colocar o serialVersionUID extremamente tosco. Isso não é parte do meu domínio e não deveria estar na minha classe. Se fosse uma annotation seria “menos pior”. Aliás, tenho a impressão de que “fazer parte do domínio” não era algo muito pensado nos primórdios do java. E muitas características ruins permanecem até hoje por causa disso.

  19. Levy

    02. jan, 2011

    Agora eu entendi, só tem profissional porreta nessa caelum.

  20. Victor

    26. jan, 2011

    Parabéns! Há um tempo atras perguntei para um professor o porque do serialVersionUID pedido pelo eclipse e ele disse que ia pesquisar mas nunca me respondeu. Hoje bateu novamente a duvida e o pessoal da Caelum (Paulo Silveira) deu uma ótima resposta!

    Obrigado por ajudar a incrementar meu conhecimento!

  21. Renato

    10. mar, 2011

    Muito bom o artigo, meus parabéns.

    Só esqueceu de colocar o tipo primitivo (long) de serialVersionUID no último exemplo de código, mas dá para entender perfeitamente.

  22. Paulo Silveira

    11. mar, 2011

    Oi Renato! obrigado, editei e alterei o long faltante.

  23. Gustavo

    18. mai, 2011

    Isso que é exemplo de alguém que sabe o que está dizendo, e provavelmente deve fazer valer seu certificado Java.

    Excelente resposta, muito clara, e explica com clareza a utilização e necessidade da especificação do número de versão de serialização.

  24. Yelken Heckman

    08. nov, 2011

    Parabéns pela explicação, esclareceu bastante algumas dúvidas.

  25. chambas

    18. nov, 2011

    Tenho de admitir que esta explicação está completa.

    Agora sim fiquei esclarecido… e sem dúvidas.

    Parabéns!

Trackbacks/Pingbacks

  1. serialVersionUID - Para que ele server realmente? « Paulo Jr - JDevelopment - abril 2, 2008

    [...] http://blog.caelum.com.br/2008/04/01/entendendo-o-serialversionuid/ [...]

  2. Entendendo o serialVersionUID @ Professor Samuel - setembro 4, 2009

    [...] http://blog.caelum.com.br/2008/04/01/entendendo-o-serialversionuid/ Java, [...]

  3. Serialização :: Usando ObjectOutputStream e ObjectInputStream | ChristianBorges.com - julho 29, 2010

    [...] serem implementados. Como "boa prática de programação" podemos definir o atributo final static serialVersionUID que é o indentificador de versão de serialização de uma classe que implementa a interface [...]

  4. Java Simples » Spring 3.1 + Hibernate 4.0 - fevereiro 22, 2012

    [...] serialVersionUID: A serialização necessita de um identificador da classe (mais detalhes em http://blog.caelum.com.br/entendendo-o-serialversionuid/). Uma possibilidade é gerá-lo utilizando o próprio [...]

Deixar uma Resposta