Serializando objetos Java em XML com XStream

Algumas vezes é necessário obter uma representação XML a partir de dados de objetos Java. A operação inversa – gerar um objeto Java a partir de uma representação XML – também pode ser igualmente útil. O processo de transpor objetos da memória como uma seqüência de bits (seja para arquivos no disco ou para transmissão via rede) é chamado de serialização.

Neste primeiro artigo, abordamos o XStream, uma biblioteca para serialização de objetos em formato XML e vice-versa.


Introdução
Existem várias bibliotecas para serialização de objetos Java em XML, tais como JOX, JAXB, XOM, WOX, Simple e etc. Cada uma destas APIs possui suas peculiaridades e suas características de performance, flexibilidade e simplicidade de uso. No entanto, quase todas possuem limitações como forçar que os objetos serializáveis estejam em formato de beans (com métodos acessores e modificadores para cada atributo), que os atributos sejam públicos, que as classes implementem uma dada interface ou mesmo que se precise definir mapeamentos entre dados da classe e sua representação XML.

De todas as bibliotecas de serialização em XML de propósito geral, a XStream se destaca por não possuir muitas destas limitações. Ou seja, XStream é capaz de gerar representação XML de praticamente quaisquer objetos Java, sem implicar em modificações nas classes originais ou nenhum outro pré-requisito em especial. Segundo os desenvolvedores, XStream terá limitações apenas para serializar classes não-públicas ou classes internas (inner classes), classes anônimas ou sem construtor default. Mesmo assim, para certas implementações específicas da Java JVM, é possível contornar estas limitações utilizando a biblioteca em um modo avançado.


Conhecendo o XStream
XStream funciona reconhecendo o tipo de dados dos atributos do objeto por reflexão e invocando um conversor interno à biblioteca para cada tipo de dados, tanto primitivos quanto referências, e gerando uma representação XML consistente e a partir da qual pode-se obter exatamente os mesmo dados.

Por exemplo, considere a seguinte definição de classe Java:

// arquivo Aluno.java

package br.com.devmedia.exemplo;
public class Aluno {
    private String nomeCompleto;
    private long numeroMatricula;
    private float[] mediasFinais = {0.0, 0.0, 0.0, 0.0};
    private boolean ehBolsista;

// construtor default de teste
     public Aluno() {
         System.out.println(“Chamou construtor default...”);
     }

// um construtor que inicializa os atributos
      public Aluno(String nome, long matricula, ehBolsista, float[] medias) {
           // segue a definição da classe...
      }


Depois de fazer o download da biblioteca XStream e colocá-la no classpath de sua aplicação, podemos criar uma representação XML de um objeto do tipo Aluno desta forma.

 

// arquivo Teste.java

package br.com.devmedia.exemplo;

import com.thoughtworks.xstream.XStream;

public class Teste {

       public static void main(String args[]) {
             // criando um Aluno
             Aluno aluno= new Aluno(“Marcelo Andrade”, 9912344L, true,

                                    new float[] {9.0, 8.5, 7.0, 10.0});
             // exibindo o resultado da serialização com XStream
             XStream xstream= new XStream();
             String representacao= xstream.toXML(aluno);
             System.out.println(representacao);
         }

Para obter uma string contendo uma representação XML, basta passar uma referência do objeto como parâmetro do método toXML do XStream. A saída do programa acima se pareceria com:

<br.com.devmedia.exemplo.Aluno>
<nomeCompleto>Marcelo Andrade</nomeCompleto>
<numeroMatricula>9912344</numeroMatricula>
<ehBolsista>true</ehBolsista>
<mediasFinais>
<float-array>
<float>9.0</float>
<float>8.5</float>
<float>7.0</float>
<float>10.0</float>
</float-array>
</mediasFinais>
</br.com.devmedia.exemplo.Aluno>

Como vemos, o formato XML de saída do XStream é bem simples e de fácil compreensão. Também é possível obter o objeto a partir destes dados XML, utilizando o método fromXML do XStream, como neste trecho:

// suponhamos os mesmos dados XML contidos na string
XStream xstream= new XStream();
Aluno aluno2= (Aluno) xstream.fromXML(representacao);

Uma aplicação prática para isto seria definir um formato de arquivo de exportação de dados de alunos de uma aplicação acadêmica para importação em outro sistema distinto, por exemplo.

Recursos úteis

Forçar chamada ao construtor
Neste último exemplo, de certa forma podemos ver que a serialização é apenas uma outra forma de se representar o objeto. Podemos facilmente constatar que o construtor default da classe não é chamado. O método fromXML não cria um novo objeto, o que faz sentido já que o objeto simplesmente é convertido de sua representação XML para formato de objeto na memória.

Entretanto, podemos subverter esta característica fazendo com que o construtor seja chamado, implementando o método readResolve, retornando a instância de nossa classe, assim:

// arquivo Aluno.java

package br.com.devmedia.exemplo;

class Aluno {
     // ...
     // implementar readResolve fazer que o construtor default
     // passe a ser chamado na desserialização
     private Object readResolve() {
           return this;
     }
// ...

Com isto, ao desserializar o objeto com fromXML, veremos na saída também a frase “Chamou construtor default...”.

Excluir atributo na saída
Caso queiramos excluir um atributo da representação XML de saída, a partir da versão 1.1.3 do XStream, podemos utilizar o método omitField, tal como neste trecho:

// ...
// não queremos o atributo “ehBolsista” da classe Aluno no XML
XStream xstream= new XStream();
xstream.omitField(Aluno.class, “ehBolsista”);
// ...

Uma alternativa a isto é definir os atributos indesejáveis com o modificador transient, presente na linguagem Java.

Renomeando classes e atributos
Vimos que a classe no XML gerado é representada, por default, por uma tag com seu nome de classe completo. Se não quisermos este comportamento, podemos definir nomes mais amigáveis usando o método alias.

// ...
// renomeando o nome da classe no XML de saída
XStream xstream= new XStream();
xstream.alias(“aluno”, Aluno.class);
// ...


Conclusão
Se você pretende apenas de uma forma de converter seus dados de objeto Java em um formato XML de forma simples e fácil, XStream é uma boa alternativa, que pode ser bastante útil em muitas situações. XStream possui ainda outros recursos mais avançados, como permitir que você escreva seus próprios conversores e altere o formato XML de representação dos objetos. Mais informações sobre a biblioteca podem ser encontradas no site oficial.

Por hora é isso, pessoal. Espero que as informações tenham sido úteis e até os próximos artigos.