JAXB - XML e Java de mãos dadas
Por Guilherme de Almeida Moreira em 27/02/08Você 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.
Ó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
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
Ó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
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
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
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
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
Alguém sabe como posso pegar os feriados que possam estar dentro do projeto ?
Comment by Gustavo Touzo — May 16, 2008 @ 3:28 pm
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
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
HUMMMM
vou ter que usar o JAXB
valeu pelo começo!!!
Comment by julio khichfy — August 28, 2008 @ 8:35 am
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
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
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
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