Skip to content

Instantly share code, notes, and snippets.

@alexandreaquiles
Last active August 29, 2015 14:22
Show Gist options
  • Save alexandreaquiles/896b6452ecccb0867a45 to your computer and use it in GitHub Desktop.
Save alexandreaquiles/896b6452ecccb0867a45 to your computer and use it in GitHub Desktop.

Pra utilizarmos JAXB, uma biblioteca que transforma de XML pra Java e de Java pra XML e que já vem com a JRE, devemos alterar um pouco as coisas.

  1. O JAXB não funciona bem com imutabilidade. Se quisermos deixar nossa classe Negociacao imutável e usá-la com JAXB, devemos:
    • criar uma versão mutável da classe. Veja a classe NegociacaoMutavel, que tem setters e cujos atributos não são final.
    • criar uma classe que herda de XmlAdapter, fornecendo implementações para o método marshal, que transforma de Negociacao para NegociacaoMutavel, e para o método unmarshal, que transforma de NegociacaoMutavel para Negociacao.
    • anotar a classe Negociacao com @XmlJavaTypeAdapter(NegociacaoAdapter.class)
  2. Outra coisa que não funciona bem com o JAXB são listas. Para que possamos ler um XML que tem uma lista de negociações, precisamos criar uma classe que embrulha a lista, como a classe ListaDeNegociacoes, que tem um atributo lista do tipo List<Negociacao>.. Algumas observações:
    • usamos a anotação @XmlRootElement(name="list") para indicar que será o elemento principal do XML e que será chamado de <list></list>.
    • usamos também @XmlAccessorType(XmlAccessType.FIELD) para indicar que as anotações estão nos atributos e não nos getters (o padrão do JAXB).
    • anotamos o atributo lista com @XmlElement(name="negociacao") para indicar que, dentro do <list></list>, as negociações estarão em tags <negociacao></negociacao>.
  3. A classe LeitorXML tem os seguintes passos:
    • criamos um JAXBContext passando a classe ListaDeNegociacoes, que é nosso elemento principal.
    • a partir do context criamos um Unmarshaller, que será responsável por transformar de XML para Java.
    • chamamos o método unmarshal do Unmarshaller, recebendo um objeto do tipo ListaDeNegociacoes.
    • obtemos a List<Negociacao> chamando o método getLista da ListaDeNegociacoes.
  4. A última diferença é o formato da data no XML. É utilizado o formato de datas ISO 8601, que fica algo como <data>2011-11-25T15:02:24</data>.
package br.com.caelum.argentum.reader.jaxb;
import java.io.InputStream;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import br.com.caelum.argentum.modelo.Negociacao;
public class LeitorXML {
public List<Negociacao> carrega(InputStream inputStream) {
try {
JAXBContext context = JAXBContext.newInstance(ListaDeNegociacoes.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
ListaDeNegociacoes negociacoes = (ListaDeNegociacoes) unmarshaller.unmarshal(inputStream);
return negociacoes.getLista();
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}
}
package br.com.caelum.argentum.reader.jaxb;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.Calendar;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import br.com.caelum.argentum.modelo.Negociacao;
public class LeitorXMLTest {
@Test
public void carregaXmlComUmaNegociacaoEmListaUnitaria() {
LeitorXML leitor = new LeitorXML();
String xmlDeTeste = "<list>"
+ " <negociacao>"
+ " <preco>43.5</preco>"
+ " <quantidade>1000</quantidade>"
+ " <data>2011-11-25T15:02:24</data>"
+ " </negociacao>"
+ "</list>";
InputStream xml = new ByteArrayInputStream(xmlDeTeste.getBytes());
List<Negociacao> negociacoes = leitor.carrega(xml);
Assert.assertEquals(1, negociacoes.size());
Negociacao negociacao = negociacoes.get(0);
Assert.assertEquals(43.5, negociacao.getPreco(), 0.001);
Assert.assertEquals(1000, negociacao.getQuantidade());
Calendar data = negociacao.getData();
Assert.assertEquals(2011, data.get(Calendar.YEAR));
Assert.assertEquals(Calendar.NOVEMBER, data.get(Calendar.MONTH));
Assert.assertEquals(25, data.get(Calendar.DAY_OF_MONTH));
}
}
package br.com.caelum.argentum.reader.jaxb;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import br.com.caelum.argentum.modelo.Negociacao;
@XmlRootElement(name="list")
@XmlAccessorType(XmlAccessType.FIELD)
class ListaDeNegociacoes {
@XmlElement(name="negociacao")
private List<Negociacao> lista;
public List<Negociacao> getLista() {
return lista;
}
public void setLista(List<Negociacao> lista) {
this.lista = lista;
}
}
package br.com.caelum.argentum.modelo;
import java.util.Calendar;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import br.com.caelum.argentum.reader.jaxb.NegociacaoAdapter;
@XmlJavaTypeAdapter(NegociacaoAdapter.class)
public final class Negociacao {
private final double preco;
private final int quantidade;
private final Calendar data;
public Negociacao(double preco, int quantidade, Calendar data) {
this.preco = preco;
this.quantidade = quantidade;
this.data = data;
}
public double getPreco() {
return preco;
}
public int getQuantidade() {
return quantidade;
}
public Calendar getData() {
return data;
}
public double getVolume() {
return preco * quantidade;
}
}
package br.com.caelum.argentum.reader.jaxb;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import br.com.caelum.argentum.modelo.Negociacao;
public class NegociacaoAdapter extends
XmlAdapter<NegociacaoMutavel, Negociacao> {
@Override
public Negociacao unmarshal(NegociacaoMutavel nm) throws Exception {
return new Negociacao(nm.getPreco(), nm.getQuantidade(), nm.getData());
}
@Override
public NegociacaoMutavel marshal(Negociacao n) throws Exception {
NegociacaoMutavel nm = new NegociacaoMutavel();
nm.setPreco(n.getPreco());
nm.setQuantidade(n.getQuantidade());
nm.setData(n.getData());
return nm;
}
}
package br.com.caelum.argentum.reader.jaxb;
import java.util.Calendar;
class NegociacaoMutavel {
private double preco;
private int quantidade;
private Calendar data;
public double getPreco() {
return preco;
}
public void setPreco(double preco) {
this.preco = preco;
}
public int getQuantidade() {
return quantidade;
}
public void setQuantidade(int quantidade) {
this.quantidade = quantidade;
}
public Calendar getData() {
return data;
}
public void setData(Calendar data) {
this.data = data;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment