Vous pouvez exploiter un XMLStreamWriter
et un XmlAdapter
pour ce faire:
BobAdapter
choses à noter sur le XmlAdapter
:
- Il est stateful et fait référence à un
XMLStreamWriter
. Nous exploiterons plus tard la capacité de JAXB à définir un état XmlAdapter
sur un Marshaller
.
- Il convertit d'un
List<String>
à un List<String>
, nous utilisons simplement un XmlAdapter
ici pour obtenir un événement.
- La méthode
marshal
est l'endroit où nous appelons writeProcessingInstruction
sur le 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
L'annotation @XmlJavaTypeAdapter
est utilisée pour relier le XmlAdapter
avec le champ/la propriété :
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;
}
}
Démo
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);
}
}
entrée .xml
<?xml version="1.0" encoding="UTF-8"?>
<alice>
<?array bob?>
<bob>edgar</bob>
<bob>david</bob>
</alice>
Sortie
<?xml version='1.0' encoding='UTF-8'?><alice><?array bob?><bob>edgar</bob><bob>david</bob></alice>
Remarque
Cet exemple doit être exécuté avec EclipseLink JAXB (MOXy) comme JAXB RI jetteront l'exception suivante (je suis le chef de file 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
Pour plus d'informations
MISE À JOUR
Je suis entré dans une demande d'amélioration (https://bugs.eclipse.org/354286) ajouter un support natif pour les instructions de traitement. Cela vous permettra éventuellement de spécifier ce qui suit sur votre propriété:
@XmlProcessingInstruction(target="array", value="bob")
public List<String> getBob() {
return bob;
}
Merci, je vais essayer avec MOXy. L'annotation @ProcessingInstruction serait certainement agréable. Cependant, comme je voudrais ajouter un PI pour n'importe quelle liste, il serait quelque peu incommode d'ajouter une annotation pour toutes les propriétés de liste dans un modèle. Existe-t-il un moyen d'enregistrer globalement un XmlAdapter? – chris
@chris - Vous pouvez enregistrer XmlAdapters au niveau du paquet avec '@ XmlJavaTypeAdapters' (voir http://blog.bdoughan.com/2011/05/jaxb-and-joda-time-dates-and-times.html). Cependant, puisque vous aurez des listes avec différents types de contenu, cela ne fonctionnera pas pour vous. Aussi, je suppose que le contenu de l'IP sera différent par propriété, ce qui signifie qu'une solution par propriété fonctionnerait mieux. –
OK, merci. Malheureusement, la méthode marshal (...) ne contient aucune information sur la propriété étant/element. Cela signifierait que j'ai dû implémenter une classe d'adaptateur pour chaque propriété de liste. Hmm ... L'annotation @ProcessingInstruction serait bien. – chris