Si potrebbe sfruttare un XMLStreamWriter
ed un XmlAdapter
per fare questo:
BobAdapter
cose da notare la XmlAdapter
:
- E 'stateful e fa riferimento a un
XMLStreamWriter
. In seguito sfrutteremo l'abilità di JAXB di impostare uno stato XmlAdapter
su un Marshaller
.
- Converte da
List<String>
a List<String>
, stiamo usando solo uno XmlAdapter
qui per ottenere un evento.
- Il metodo
marshal
è dove noi chiamiamo writeProcessingInstruction
sul 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
Il @XmlJavaTypeAdapter
annotazione viene utilizzato per collegare il XmlAdapter
con il campo/proprietà :
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;
}
}
Demo
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);
}
}
ingresso.xml
<?xml version="1.0" encoding="UTF-8"?>
<alice>
<?array bob?>
<bob>edgar</bob>
<bob>david</bob>
</alice>
uscita
<?xml version='1.0' encoding='UTF-8'?><alice><?array bob?><bob>edgar</bob><bob>david</bob></alice>
Nota
Questo esempio deve essere eseguito con EclipseLink JAXB (MOXy) come JAXB RI getterà la seguente eccezione (sono in vantaggio 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
Per ulteriori informazioni
UPDATE
ho inserito una richiesta di miglioramento (https://bugs.eclipse.org/354286) per aggiungere supporto nativo per le istruzioni di elaborazione. Questo alla fine ti permetterà di specificare quanto segue sulla tua proprietà:
@XmlProcessingInstruction(target="array", value="bob")
public List<String> getBob() {
return bob;
}
Grazie, proverò con MOXy. L'annotazione @ProcessingInstruction sarebbe sicuramente carina.Tuttavia, dato che mi piacerebbe aggiungere un PI per qualsiasi elenco, sarebbe un po 'scomodo aggiungere un'annotazione per tutte le proprietà degli elenchi in un modello. C'è un modo per registrare globalmente un XmlAdapter? – chris
@chris - È possibile registrare XmlAdapters a livello di pacchetto con '@ XmlJavaTypeAdapters' (vedere http://blog.bdoughan.com/2011/05/jaxb-and-joda-time-dates-and-times.html). Tuttavia dal momento che avrai elenchi con diversi tipi di contenuti, questo non funzionerà per te. Inoltre sto indovinando il contenuto del PI sarà diverso per proprietà e il significato di una soluzione per proprietà funzionerebbe meglio. –
OK, grazie. Sfortunatamente, il metodo marshal (...) non ha alcuna informazione sulla proprietà being/element. Ciò significherebbe che dovevo implementare una classe adattatore per ogni proprietà di lista. Hmm ... L'annotazione @ProcessingInstruction sarebbe carina. – chris