Caelum | Ensino e Inovação - Cursos de Java, Scrum, Ruby on Rails


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.

  • Share/Bookmark

21 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

  16. Muito obrigado pela ajuda.

    Comment by Eder Ignatowicz — January 19, 2009 @ 6:16 am

  17. Conforme comentários de sueli, existe esse problema de ser gerado sempre :ns2 no namespace do xml, dependendo de como será lido, isso pode gerar problemas.

    A solução que achei na web pode ser uma GAMBI, segue link:
    http://www.guj.com.br/posts/list/83758.java

    Ou então um código gambiarrento que resolve o problema tbm

    // Passe o arquivo gerado por parametro e depois remova o ns2 abertura e fechamento
    public void ajustaXml(File file) throws Exception {

    FileReader reader = new FileReader(file);
    BufferedReader leitor = new BufferedReader(reader);

    leitor.read();

    String vlr = “”;
    StringBuffer vlrFile = new StringBuffer();
    String line = leitor.readLine();

    while(line != null) {
    vlrFile.append( line );
    line = leitor.readLine();
    }

    vlr = vlrFile.toString();

    // aqui acontece a gambi… temporariamente resolve o problema
    if (vlr.indexOf(“ns2:”) > -1) {
    vlr = vlr.replaceAll(“ns2:”, “”);
    }

    if (vlr.indexOf(“:ns2″) > -1) {
    vlr = vlr.replaceAll(“:ns2″, “”);
    }

    leitor.close();
    reader.close();

    FileWriter writer = new FileWriter(file);
    PrintWriter saida = new PrintWriter(writer);

    saida.print( “<” + vlr);

    writer.close();
    saida.close();
    }

    Comment by isaias — February 19, 2009 @ 12:07 am

  18. Galera precisava elaborar um trabalho sobre o JAXB mais não tenho nem idéia do que seja isso e os arquivos que achei na internet estão todos em inglês. Alguém pode me dar uma mãozinha com um link ou algo do tipo?!

    Valew…

    Comment by Zaqueu — May 22, 2009 @ 10:38 am

  19. Obrigado pelo post

    Comment by saisso — June 16, 2009 @ 8:33 am

  20. Tem como resolver o mesmo problema acima com menos gambi…
    Tem umas anotacoes nas classes geradas que da problemas… inclusive uma anotacao localizada na package-info.java…

    ABRACOS

    Comment by dcbasso — July 28, 2009 @ 11:29 am

  21. [...] que esta anotação não é a responsável por serializar o objeto no formato XML. O JAX-RS usa o JAX-B como serializador padrão, basta para isso colocar a anotação @XmlRootElement na classe desejada, [...]

    Pingback by Arquitetura REST com Java: JAX-RS | blog.caelum.com.br — December 15, 2009 @ 11:05 am

RSS feed for comments on this post. TrackBack URL

Leave a comment




Caelum | Ensino e Inovação
São Paulo: Rua Vergueiro, 3185, cj. 87, próximo ao Metrô Vila Mariana   |   Tel. (11) 5571-2751
Rio de Janeiro: Rua Senador Dantas, 80, cj. 307/308 - Centro   |   Tel. (21) 2220-4156 ou 2297-0033
Brasília: SCS Qd. 8 Bl. B-50, Sala 521 - Ed. Venâncio 2000   |   Tel. (61) 3039-4222