JAXB – XML e Java de mãos dadas

Postado em 27. fev, 2008 por em Java

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.

Guilherme de Almeida Moreira

Mais sobre o autor

Tags: , , , ,

23 Respostas para “JAXB – XML e Java de mãos dadas”

  1. Rafael Naufal

    27. fev, 2008

    Ó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.

  2. Leandro Silva

    27. fev, 2008

    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.

  3. Eloy Lima

    29. fev, 2008

    Ó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.

  4. Bruno Pereira

    12. mar, 2008

    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 ;)

  5. Luiz Gustavo

    13. mar, 2008

    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.

  6. Joao Paulo

    11. abr, 2008

    Olá.. legal o tuto, mas…

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

    jopss

  7. maxwell

    16. abr, 2008

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

  8. Gustavo Touzo

    16. mai, 2008

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

  9. Gustavo Touzo

    16. mai, 2008

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

  10. Paulo Suzart

    03. jul, 2008

    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

  11. julio khichfy

    28. ago, 2008

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

  12. Gustavo Touzo

    15. set, 2008

    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 ?

  13. Claudson

    03. out, 2008

    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

  14. Sueli

    11. nov, 2008

    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 ?

  15. Dante

    25. nov, 2008

    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

  16. Eder Ignatowicz

    19. jan, 2009

    Muito obrigado pela ajuda.

  17. isaias

    19. fev, 2009

    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();
    }

  18. Zaqueu

    22. mai, 2009

    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…

  19. saisso

    16. jun, 2009

    Obrigado pelo post

  20. dcbasso

    28. jul, 2009

    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

  21. Mateus Leal

    05. nov, 2011

    Olá, alguem poderia me passar um tutorial (em portugues de preferencia) de como usar a classe XStrean, estou precisando apenas ler dados em arquivos XML e depois armazenar dinovo nos mesmos arquivos lidos (caso mude algum valor). Obrigado

  22. Fi

    19. dez, 2011

    Para quem precisar apenas processar um XML e extrair dados diretamente dele, sem transformar em objetos, a melhor biblioteca que eu já vi é a JDOM!
    http://www.jdom.org/

Trackbacks/Pingbacks

  1. Arquitetura REST com Java: JAX-RS | blog.caelum.com.br - dezembro 15, 2009

    [...] 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, [...]

Deixar uma Resposta