2011-08-03 5 views
6

Je voudrais ajouter une instruction de traitement chaque fois qu'une propriété collection/tableau est publié en feuilleton pour obtenir quelque chose commeComment ajouter des instructions de traitement XML au maréchal JAXB

<alice> 
    <? array bob ?> 
    <bob>edgar</bob> 
    <bob>david</bob> 
</alice> 

Est-ce possible avec JAXB? Ou au moins avec une implémentation spécifique de JAXB?

Répondre

6

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; 
} 
+0

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

+0

@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. –

+0

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

Questions connexes