2011-08-03 14 views

risposta

6

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

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

+0

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

+0

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

Problemi correlati