Usted podría aprovechar un XMLStreamWriter
y un XmlAdapter
Para ello:
BobAdapter
cosas a tener en cuenta sobre la XmlAdapter
:
- Es con estado y hace referencia a un
XMLStreamWriter
. Más adelante aprovecharemos la capacidad de JAXB de establecer un estado XmlAdapter
en un Marshaller
.
- Se convierte de
List<String>
a List<String>
, solo estamos usando XmlAdapter
aquí para tener un evento.
- El método
marshal
es donde llamamos writeProcessingInstruction
en el XMLStreamWriter
:
package forum6931520;
import java.util.List;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.stream.XMLStreamWriter;
public class BobAdapter extends XmlAdapter<List<String>, List<String>> {
private boolean first = true;
private XMLStreamWriter xmlStreamWriter;
public BobAdapter() {
}
public BobAdapter(XMLStreamWriter xmlStreamWriter) {
this();
this.xmlStreamWriter = xmlStreamWriter;
}
@Override
public List<String> marshal(List<String> stringList) throws Exception {
if(first) {
xmlStreamWriter.writeProcessingInstruction("array", "bob");
first = false;
}
return stringList;
}
@Override
public List<String> unmarshal(List<String> stringList) throws Exception {
return stringList;
}
}
Alice
La anotación @XmlJavaTypeAdapter
se utiliza para vincular el XmlAdapter
con el campo/propiedad :
package forum6931520;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement
public class Alice {
private List<String> bob;
@XmlJavaTypeAdapter(BobAdapter.class)
public List<String> getBob() {
return bob;
}
public void setBob(List<String> bob) {
this.bob = bob;
}
}
Demostración
package forum6931520;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamWriter;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Alice.class);
File xml = new File("src/forum6931520/input.xml");
Unmarshaller unmarshaller = jc.createUnmarshaller();
Alice alice = (Alice) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
XMLOutputFactory xof = XMLOutputFactory.newFactory();
XMLStreamWriter xmlStreamWriter = xof.createXMLStreamWriter(System.out);
marshaller.setAdapter(new BobAdapter(xmlStreamWriter));
marshaller.marshal(alice, xmlStreamWriter);
}
}
de entrada.xml
<?xml version="1.0" encoding="UTF-8"?>
<alice>
<?array bob?>
<bob>edgar</bob>
<bob>david</bob>
</alice>
salida
<?xml version='1.0' encoding='UTF-8'?><alice><?array bob?><bob>edgar</bob><bob>david</bob></alice>
Nota
Este ejemplo necesita ser ejecutado con EclipseLink JAXB (MOXy) como el JAXB RI será la excepción siguiente (yo soy el plomo moxy):
Exception in thread "main" com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
java.util.List is an interface, and JAXB can't handle interfaces.
this problem is related to the following location:
at java.util.List
at public java.util.List forum6931520.Alice.getBob()
at forum6931520.Alice
java.util.List does not have a no-arg default constructor.
this problem is related to the following location:
at java.util.List
at public java.util.List forum6931520.Alice.getBob()
at forum6931520.Alice
Para más información
ACTUALIZACIÓN
He entrado en una solicitud de mejora (https://bugs.eclipse.org/354286) para agregar soporte nativo para las instrucciones de procesamiento. Esto eventualmente le permitirá especificar lo siguiente en su propiedad:
@XmlProcessingInstruction(target="array", value="bob")
public List<String> getBob() {
return bob;
}
Gracias, intentaré esto con MOXy. La anotación @ProcessingInstruction definitivamente sería agradable. Sin embargo, como me gustaría agregar un PI para cualquier lista, sería un inconveniente agregar una anotación para todas las propiedades de la lista en un modelo. ¿Hay alguna forma de registrar globalmente un XmlAdapter? – chris
@chris - Puede registrar XmlAdapters a nivel de paquete con '@ XmlJavaTypeAdapters' (vea http://blog.bdoughan.com/2011/05/jaxb-and-joda-time-dates-and-times.html). Sin embargo, dado que tendrá listas con diferentes tipos de contenido, esto no funcionará para usted. También supongo que el contenido del PI será diferente por propiedad, lo que significa que una solución por propiedad funcionaría mejor. –
OK, gracias. Desafortunadamente, el método Marshal (...) no tiene ninguna información sobre la propiedad siendo/elemento. Esto significa que tuve que implementar una clase de adaptador para cada propiedad de la lista. Hmm ... La anotación @ProcessingInstruction sería agradable. – chris