2011-08-03 9 views

Respuesta

6

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

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

+0

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

+0

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

Cuestiones relacionadas