JAXB - XML e Java de mãos dadas

Por Guilherme de Almeida Moreira em 27/02/08

Você já participou de um projeto que precisou ler um arquivo de configuração em xml? Já precisou consumir um xml e transformá-lo em objeto? O que você usou? Quem já trabalhou com xml sabe da dificuldade que podemos encontrar pelo caminho, e é esse tipo de dificuldade que a especificação Java Architecture for XML Binding ou simplesmente JAXB tenta resolver.

Imagine a seguinte situação: Precisarmos enviar os dados contidos em um objeto para um outro servidor. Temos muitas opções para fazer o envio, como por exemplo colocar essas informações em um arquivo de texto seguindo uma máscara pré-definida. Porém apenas as aplicações que conhecessem essa máscara entenderiam os dados, e perdemos portabilidade. Usando xml a situação já é outra: qualquer aplicação, independende de linguagem, entenderá os dados contidos no arquivo xml.

Antes de falarmos sobre o JAXB vamos primeiro conferir alguns conceitos:

XML
XML é uma linguagem de marcação que serve para guardar dados de uma forma estruturada. Essa estrutura é definida pelo próprio usuário ou por um schema. Um xml é um arquivo de texto puro, portanto independente de plataforma, por isso é muito utilizado para transmitir dados entre diferentes aplicações e sistemas. Exemplo:
carro.xml


<?xml version="1.0" encoding="UTF-8"?>
<carro>
  <nome>Fusca</nome>
  <portas>2</portas>
  <motoristas>
    <motorista>
      <nome>Guilherme</nome>
    </motorista>
    <motorista>
      <nome>Leonardo</nome>
    </motorista>
  </motoristas>
</carro>

XSD
XSD é o schema citado na seção anterior, ele define quais são as regras que a estrutura do xml deve seguir, possibilitando a validação desse xml. Exemplo:


<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="carro" type="Carro" />
  <xsd:complexType name="Carro">
    <xsd:sequence>
      <xsd:element name="nome" type="xsd:string" minOccurs="1"
        maxOccurs="1" nillable="false"/>
      <xsd:element name="portas" type="xsd:int" minOccurs="1"
        maxOccurs="1" nillable="false"/>
      <xsd:element name="motoristas" type="Motorista" minOccurs="0"
        maxOccurs="unbounded"/>
    </xsd:sequence>
  </xsd:complexType>
  <xsd:complexType name="Motorista">
    <xsd:sequence>
      <xsd:element name="nome" minOccurs="1" maxOccurs="1"
        type="xsd:string" nillable="false"/>
    </xsd:sequence>
  </xsd:complexType>
</xsd:schema>

O primeiro ponto da especificação apresenta uma ferramenta chamada Binding Compiler, cuja função é transformar um xsd em um conjunto de classes que tenham uma estrutura compatível com a estrutura do xml que esse xsd define.

No XSD de exemplo definimos a seguinte estrutura: Um elemento carro deve ter um elemento nome e um elemento motoristas (do tipo Motorista), seguindo essa ordem, primeiro nome e depois motoristas. Depois definimos o tipo Motorista que deve conter apenas um nome.

O Binding Compiler é independente da implementação do JAXB, ou seja, quem define como ele será executado é quem implementa a especificação, porém a maioria e inclusive a própria RI(Reference Implementation) cria um comando que pode ser chamado pela linha de comando do Sistema Operacional, o xjc. Por exemplo no Linux:

xjc carro.xsd -d src -p br.com.caelum

Se você já está usando o Java 6, o JAXB já vêm junto com o JDK.

Com esse comando o Binding Compiler gera três classes: Carro.java, Motorista.java e a ObjectFactory.java. As classes Carro e Motorista seguem a estrutura do xsd.

Gerando e Lendo XML
A segunda parte da especificação define o que temos que fazer para transformar objetos em xml e vice-versa. A API do JAXB é quem se responsabiliza por essas transformações.

Transformando objetos em xml
O processo de transformar um objeto em xml é chamado de Marshal. Com o JAXB para transformar um objeto em xml precisamos de um JAXBContext, esse context é quem fornecerá o Marshaller. O Marshaller é quem finalmente transforma um objeto (JAXBElement) em xml. O JAXBElement contém o objeto de verdade a ser serializado e algumas propriedades do xml. É aqui que entra a importância do ObjectFactory criado pelo Binding Compiler, ele é responsável por criar uma instância do JAXBElement apropriada para o tipo de objeto a ser serializado.


  JAXBContext context = JAXBContext.newInstance("br.com.caelum");
  Marshaller marshaller = context.createMarshaller();
  JAXBElement<Carro> element = new ObjectFactory().createCarro(carro);
  marshaller.marshal(element, System.out);

Parseando xml em objetos java
Para fazer o caminho contrário, ou seja popular um objeto java com dados de um xml também precisamos de um JAXBContext, porém agora temos que pegar um Unmarshaller. O Unmarshaller recebe um arquivo xml e devolve um JAXBElement contendo um objeto populado.


  JAXBContext context = JAXBContext.newInstance("br.com.caelum");
  Unmarshaller unmarshaller = context.createUnmarshaller();
  JAXBElement<Carro> element = (JAXBElement<Carro>unmarshaller.
    unmarshal(new File("resources/carro.xml"));
  Carro carro = element.getValue();

Conclusão
O JAXB facilita muito a vida dos programadores java, fazendo o consumo e criação de xml menos trabalhosos. Essa API também fornece outros recursos como, validação, geração de schema (a partir de classes java, cria um xsd), opções para trabalhar com Namespace e etc. Comente nesse post outras oções do JAXB e outras bibliotecas que você usa no seu dia-a-dia.

15 Comments »

  1. Ótimo post! Já usei também uma implementação open source da JAXB API, chamada JaxMe. Segue a mesma linha de manipulação de xml’s, por meio de Marshalling e UnMarshalling. XStream também é uma API interessante para serializar e deserializar objetos em XML também.

    Comment by Rafael Naufal — February 27, 2008 @ 11:22 am

  2. Costumo usar o XStream, mas à vezes me deparo com algumas limitações. Algumas vezes já pensei em usar JAXB, mas o fato de ter que escrever um XSD e a partir dele gerar as classes, me desanimou um pouco. Mas outro dia desses, por conta de um XML fora do padrão que foi estabelecido aqui na empresa, acabei voltando a considerar o JAXB, justamente por causa do XSD.

    Bem, de qualquer forma, já tenho uns 10 serviços trabalhando com XStream.

    Comment by Leandro Silva — February 27, 2008 @ 12:12 pm

  3. Ótimo post! À alguns dias utilizei o xstream com Alias para ler serviços do Yahoo, tanto XML quanto JSON e achei a programação muito simples.

    Comment by Eloy Lima — February 29, 2008 @ 12:58 am

  4. Eu uso XStream quase sempre, principalmente em web services REST. Para a maioria dos casos o simples uso de aliases dá conta do recado. Para situações mais complicadas eu normalmente implemento converters. Ainda não me deparei com nenhum mapeamento que eu não conseguisse fazer usando converters.

    O XStream é tão fácil e flexível que eu tenho uma tremenda má vontade pra avaliar qualquer outra forma de binding :)

    Para implementar web services WS-* eu utilizei o Axis 2 com Axis Data Binding na maioria das vezes. Ele gera uma estrutura horripilante para fazer os mapeamentos e validações, mas o desenvolvedor não precisa tocar nisso.

    Para XML de uma maneira geral, XStream all the way ;)

    Comment by Bruno Pereira — March 12, 2008 @ 2:14 am

  5. Pois é, esse negócio de gerar Object Factory não gostei não, é uma boa, mas devia ter uma versão mais simples para se fazer como é XStream.

    Comment by Luiz Gustavo — March 13, 2008 @ 6:28 pm

  6. Olá.. legal o tuto, mas…

    porque eu usaria JAXB ao invés do XStream, sendo este último mais transparente e fácil??

    jopss

    Comment by Joao Paulo — April 11, 2008 @ 11:46 am

  7. tb utilizo o XStream….com as anotações fica muito simples criar a estrutura do xml….

    Comment by maxwell — April 16, 2008 @ 12:40 pm

  8. Alguém sabe como posso pegar os feriados que possam estar dentro do projeto ?

    Comment by Gustavo Touzo — May 16, 2008 @ 3:28 pm

  9. Alguém sabe como posso pegar os feriados que possam estar dentro do projeto ?
    meu e-mail: gtouzo@click21.com.br

    Comment by Gustavo Touzo — May 16, 2008 @ 3:31 pm

  10. Olá a todos,
    uma pequena diferença, ao menos ao fazer a implementação aqui no projeto é que ao fazer o unmarshal, fizemos o cast direto para a entidade JAXB:

    Carro carro = (Carro) un.unmarshal(new File(”resources/carro.xml”);

    Ao tentar usar o unmarshal com JAXBElement, recebemos um class cast exception.

    Abraços

    Comment by Paulo Suzart — July 3, 2008 @ 2:43 pm

  11. HUMMMM
    vou ter que usar o JAXB
    valeu pelo começo!!!

    Comment by julio khichfy — August 28, 2008 @ 8:35 am

  12. Estou tendo um erro de caracter inválido ao ler ao fazer o unmarshal de um XML que segue o esquema do Project. Alguém sabe dizer o que pode ser ?

    Comment by Gustavo Touzo — September 15, 2008 @ 6:16 am

  13. Com o XStream eu não consigo fazer o marshal a partir de um XSD:
    “Can XStream generate classes from XSD?
    No. For this kind of work a data binding tool such as XMLBeans is appropriate.”
    http://xstream.codehaus.org/faq.html

    Comment by Claudson — October 3, 2008 @ 2:51 pm

  14. Estou utilizando o JAXB, mas meu arquivo gera sempre com ns2: na frente, alguem sabe se tem algo para que eu tire estes ns3 que aparece na frente ex:
    001
    37754
    VENDAS
    1
    55

    Alguem sabe como tirar ?

    Comment by Sueli — November 11, 2008 @ 9:58 pm

  15. Muito bom amigo… aprendi a usar a ferramenta… fácil e rápido, eu queria mesmo eh gerar as classes apartir do XDS!

    Abraçosss

    Comment by Dante — November 25, 2008 @ 6:33 am

RSS feed for comments on this post. TrackBack URL

Leave a comment