Como faço para marcar java.util.List com JAXB como JAX-RS (CXF e Jersey) Do [duplicado
Pergunta
Esta pergunta já tem uma resposta aqui:
Parece que os mais recentes Jax-Rs podem lidar com métodos que retornam java.util.List como o XMLROOTELEMENT, mas o Jaxb normal não pode. Eu gostaria de imitar o que CXF e Jersey estão fazendo.
Em outras palavras, eu gostaria de marcar uma lista e, assim como CXF e Jersey. Normalmente, se você tentar marcar uma lista com o JAXB, você obtém a exceção do elemento raiz. Como faço para contornar isso sem ter que fazer um objeto de embrulho?
EDIT: Obrigado pelas muitas respostas, mas estou muito familiarizado com o @xmlelementwrapper, mas isso nem chega perto de simular o que Jax-Rs está fazendo.
Jax-rs faz isso:
@XmlRootElement(name="dog")
public class Dog {
private String name;
public String getName() { return this.name; }
//Setter also
}
Agora, se eu em série uma lista de cães:
serialize(List<Dog> dogs);
XML deve ser (o que Jax-Rs faz):
<dogs>
<dog><name>Rascal</name></dog>
</dogs>
Então você pode ver que eu não quero ter que fazer um objeto de invólucro para cada objeto de domínio.
Solução 7
Blaise Doughan, acredito que mostra uma boa solução para este problema aqui: É possível configurar programaticamente o JAXB?
e
http://blog.bdoughan.com/2012/11/creating-generic-list-wrapper-in-jaxb.html
E aqui, embora um caso de uso um pouco diferente:
http://blog.bdoughan.com/2012/02/xmlanyelement-and-xmladapter.html
Outras dicas
Você não poderia simplesmente acrescentar:
@XmlElementWrapper(name = "wrapperName")
Não há necessidade de fazer um objeto de invólucro. Este será então o elemento de rota em sua resposta XML marsificada.
Usei uma lista iterável personalizada usando o código a seguir, espero que isso ajude.
package bindings;
import java.io.Serializable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
@XmlType
@XmlRootElement
public class CustomBindList<V> implements Iterable<V>, Serializable {
private static final long serialVersionUID = 4449835205581297830L;
@XmlElementWrapper(name = "List")
@XmlElement(name = "Entry")
private final List<V> list = new LinkedList<V>();
public CustomBindList() {
}
public void add(final V obj) {
list.add(obj);
}
public V get(final int index) {
return list.get(index);
}
@Override
public Iterator<V> iterator() {
return list.iterator();
}
public int size() {
return list.size();
}
}
Eu tenho um segredo que me permite evitar estragar os mapeamentos JAXB e fazer com que tudo funcione magicamente.
Uso essa abordagem há anos, nunca passou até 5 minutos se preocupando com o Marshalling/Unarshalling. O segredo é .... não use Jaxb. :)
Na maioria dos meus projetos que usam Jax-Rs, eu configuro Jersey para usar o XStream e deixar o XStream descobrir como marechal/unarshal para mim. (ou Jackson para JSON)
Talvez existam alguns motivos para usar o JAXB em vez de algo como Xstream/Jackson, mas ainda não encontrei nenhum.
Mapear uma lista pode ser feito assim ..
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType
public class TestRootObject {
@XmlElement(name = "testList")
private List<TestObj> testList;
//getter setter
}
Confira Jackson, é muito compatível com as ligações do JAXB e, usando o MappingjsonFactory, você pode realmente usar o Java para XML para Java para JSON para Java.
Eu anotei minhas coleções com @XmlJavaTypeAdapter(value = Adapter.class)
. A classe adaptadora se estende de XmlAdapter<key, value>
A chave é um identificador exclusivo para (un) marechal e o valor é o seu objeto de domínio.
Talvez isso possa ajudá -lo. No entanto, você precisa criar um adaptador para cada objeto de domínio.