unmarshal parse jaxbunmarshaller ejemplo java jaxb

jaxbunmarshaller - parse xml java jaxb



¿Es posible configurar JAXB programáticamente? (1)

Puede crear un objeto Wrapper genérico como el siguiente:

Envoltura

Puede crear una clase contenedora genérica con una propiedad List anotada con @XmlAnyElement(lax=true) . El tipo de objeto utilizado para completar esta lista se basará en su elemento raíz (consulte: http://blog.bdoughan.com/2010/08/using-xmlanyelement-to-build-generic.html ).

package forum13272288; import java.util.*; import javax.xml.bind.annotation.XmlAnyElement; public class Wrapper<T> { private List<T> items = new ArrayList<T>(); @XmlAnyElement(lax=true) public List<T> getItems() { return items; } }

Dirección

Deberá anotar los posibles contenidos de la lista con @XmlRootElement .

package forum13272288; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Address { }

Persona

package forum13272288; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Person { }

Manifestación

El código de demostración siguiente muestra cómo usar la clase Wrapper . Dado que el elemento raíz puede ser diferente, deberá especificar que desea desasignar a la clase contenedora. Alternativamente, puede aprovechar la anotación @XmlElementDecl para asociar varios elementos raíz con la clase contenedora (consulte: http://blog.bdoughan.com/2012/07/jaxb-and-root-elements.html ).

package forum13272288; import javax.xml.bind.*; import javax.xml.transform.stream.StreamSource; public class Demo { public static void main(String[] args) throws Exception { JAXBContext jc = JAXBContext.newInstance(Wrapper.class, Person.class, Address.class); Unmarshaller unmarshaller = jc.createUnmarshaller(); Marshaller marshaller = jc.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); StreamSource personsXML = new StreamSource("src/forum13272288/persons.xml"); JAXBElement<Wrapper> wrapper1 = unmarshaller.unmarshal(personsXML, Wrapper.class); marshaller.marshal(wrapper1, System.out); StreamSource addressesXML = new StreamSource("src/forum13272288/addresses.xml"); JAXBElement<Wrapper> wrapper2 = unmarshaller.unmarshal(addressesXML, Wrapper.class); marshaller.marshal(wrapper2, System.out); } }

Salida

A continuación se muestra el resultado de ejecutar el código de demostración. Los archivos persons.xml y addresses.xml parecen a la salida correspondiente.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <persons> <person/> <person/> </persons> <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <addresses> <address/> <address/> </addresses>

Para más información

Digamos que tengo dos Person y Address JavaBeans.

Si creo una lista de objetos Persona, me gustaría organizar algo como esto:

<persons> <person>...</person> </persons>

Es posible utilizar la técnica que se describe aquí: Usar JAXB para unificar / ordenar una Lista <String>

Anotando JaxbList con @XmlRootElement(name = "persons") y @XmlElement(name = "person") , entonces es posible reunir al XML de arriba.

Pero sería bueno poder reutilizar la misma JaxbList<T> para JaxbList<T> también una lista de objetos de Address . Y en realidad, tendré muchos otros tipos de frijoles. Puedo ir con algo como:

<list> <item xsi:type="person" xmlns:xsi="http://www.w2.org/2001/XmlSchema-instance"></item> </list>

Pero, idealmente, sería bueno tener que reemplazar "lista" con la versión plural del nombre de la clase y "elemento" con el nombre de la clase.

Entonces, ¿es posible configurar programáticamente JaxbContext o algo durante el tiempo de ejecución y básicamente establecer el valor del name dentro de @XmlRootElement y @XmlElement ?

¿O de otra manera para que esto funcione sin tener que escribir una implementación separada de JaxbList para cada tipo de bean? ¿Tal vez XmlJavaTypeAdapter puede lograr este tipo de cosas?

Actualizar la solución de @Blaise Doughan aceptada a continuación funciona muy bien. Para mi caso de uso, tenía que ir directamente del objeto Java al XML, esto es lo que funcionó (tenga en cuenta que esta no es mi implementación completa, es una especie de pseudo código para la demostración):

//JAXBContext is thread safe and so create it in constructor or //setter or wherever: ... JAXBContext jc = JAXBContext.newInstance(Wrapper.class, clazz); ... public String marshal(List<T> things, Class clazz) { //configure JAXB and marshaller Marshaller m = jc.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); //Create wrapper based on generic list of objects Wrapper<T> wrapper = new Wrapper<T>(things); JAXBElement<Wrapper> wrapperJAXBElement = new JAXBElement<Wrapper>(new QName(clazz.getSimpleName().toLowerCase()+"s"), Wrapper.class, wrapper); StringWriter result = new StringWriter(); //marshal! m.marshal(wrapperJAXBElement, result); return result.toString(); }