java - objeto - jaxb marshal unmarshal
¿Cómo transmitir archivos grandes usando JAXB Marshaller? (3)
Como ha descubierto, si una clase no tiene la anotación @XmlRootElement
, entonces no puede pasar una instancia de esa clase al @XmlRootElement
. Sin embargo, hay una manera fácil de evitar esto: envolver el objeto en un JAXBElement
y, en su JAXBElement
, pasarlo al JAXBElement
clasificación.
Ahora JAXBElement
es una bestia bastante torpe, pero lo que hace es que contiene el nombre del elemento y el espacio de nombres del objeto que desea reunir, información que normalmente estaría contenida en la anotación @XmlRootElement
. Siempre que tenga el nombre y el espacio de nombres, puede construir un JAXBElement
para envolver su POJO, y JAXBElement
.
Si sus POJO fueron generados por XJC, entonces también habrá generado una clase ObjectFactory
que contiene métodos de fábrica para construir envolturas de JAXBElement
para usted, haciendo las cosas un poco más fáciles.
Aún tendrás que usar la propiedad JAXB_FRAGMENT
para los elementos internos que se repiten, de lo contrario, JAXB generará cosas como el prólogo XML cada vez, lo que no deseas.
El problema al que me enfrento es cómo reunir una gran lista de objetos en un solo archivo XML, tan grande que no puedo organizar la lista completa en un solo paso. Tengo un método que devuelve estos objetos en trozos, pero luego los reúno utilizando JAXB, el contador de referencias devuelve con la excepción de que estos objetos no son elementos raíz. Esto está bien para el caso normal en el que desea organizar el documento completo en un solo paso, pero también sucede si configuro la propiedad JAXB_FRAGMENT en true.
Esta es la salida XML deseada:
<rootElem>
<startDescription></startDescription>
<repeatingElem></repeatingElem>
<repeatingElem></repeatingElem>...
</rootElem>
Así que asumo que necesito algún tipo de oyente que cargue dinámicamente la siguiente parte de repeatingElements para alimentarlo al comisario antes de que escriba la etiqueta de cierre del elemento root. Pero, ¿cómo hacer eso? Hasta ahora solo he usado JAXB para organizar archivos pequeños y la documentación de JAXB no da muchas pistas para ese caso de uso.
No sé mucho de JAXB, así que no puedo ayudar. Pero si no te importa, tengo una sugerencia.
Escribir XML es mucho más fácil que leerlo, por lo que una solución para su problema podría ser utilizar un enfoque más "de bajo nivel". Simplemente escriba su propio marshaller usando una de las bibliotecas de código abierto disponibles para XML. Creo que puedes hacer fácilmente lo que quieras usando dom4j .
Soy consciente de que esta es una pregunta antigua, pero la encontré mientras buscaba duplicados de otra pregunta similar.
Como sugiere @skaffman, desea activar Marshal con JAXB_FRAGMENT
habilitado y sus objetos envueltos en JAXBElement. A continuación, marque repetidamente cada instancia individual del elemento repetido. Básicamente, suena como si quisieras algo más o menos así:
public class StreamingMarshal<T>
{
private XMLStreamWriter xmlOut;
private Marshaller marshaller;
private final Class<T> type;
public StreamingMarshal(Class<T> type) throws JAXBException
{
this.type = type;
JAXBContext context = JAXBContext.newInstance(type);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
}
public void open(String filename) throws XMLStreamException, IOException
{
xmlOut = XMLOutputFactory.newFactory().createXMLStreamWriter(new FileOutputStream(filename));
xmlOut.writeStartDocument();
xmlOut.writeStartElement("rootElement");
}
public void write(T t) throws JAXBException
{
JAXBElement<T> element = new JAXBElement<T>(QName.valueOf(type.getSimpleName()), type, t);
marshaller.marshal(element, xmlOut);
}
public void close() throws XMLStreamException
{
xmlOut.writeEndDocument();
xmlOut.close();
}
}