2011-05-16 19 views
5

Tengo problemas para unmarshall xml anidado a continuación. ¿Alguien puede avisar si me falta algo?
body etiqueta puede contener cualquier obj anotado Jaxb.
¿Debo crear un adaptador personalizado para ordenar/desasignar dicho xml?Jaxb complex xml unmarshall

XML de entrada

<?xml version="1.0" encoding="UTF-8"?> 
<serviceRq xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="serviceRq"> 
    <body> 
    <createRq> 
     <id>1234</id> 
    </createRq> 
    </body> 
</serviceRq> 

Mis clases anotado JAXB son:

@XmlRootElement 
@XmlAccessorType(XmlAccessType.FIELD) 
@XmlType(name = "serviceRq") 
public class ServiceRq{  
    private Object body; 
    <!-- getters and setters omitted--> 
} 

Aquí, el cuerpo puede ser cualquier objeto jaxb anotada, en este caso su CreateRq.

@XmlRootElement 
@XmlAccessorType(XmlAccessType.FIELD) 
@XmlType(name = "createRq") 
public class CreateRq{  
    private String id; 
    <!-- getters and setters omitted--> 
} 

Estoy buscando una forma genérica de admitir cualquier objeto anotado Jaxb en el cuerpo de la entrada xml.

Respuesta

6

Se puede usar un @XmlAnyElement(lax=true) y un XmlAdapter para manejar este caso de uso:

ServiceRq

import javax.xml.bind.annotation.XmlAccessorType; 
import javax.xml.bind.annotation.XmlAccessType; 
import javax.xml.bind.annotation.XmlRootElement; 
import javax.xml.bind.annotation.XmlType; 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 

@XmlRootElement 
@XmlAccessorType(XmlAccessType.FIELD) 
@XmlType(name = "serviceRq") 
public class ServiceRq{  

    @XmlJavaTypeAdapter(value=BodyAdapter.class) 
    private Object body; 
    // getters and setters omitted 
} 

BodyAdapter

import javax.xml.bind.annotation.adapters.XmlAdapter; 

public class BodyAdapter extends XmlAdapter<Body, Object>{ 

    @Override 
    public Object unmarshal(Body v) throws Exception { 
     return v.getValue(); 
    } 

    @Override 
    public Body marshal(Object v) throws Exception { 
     Body body = new Body(); 
     body.setValue(v); 
     return body; 
    } 

} 

cuerpo

import javax.xml.bind.annotation.XmlAnyElement; 

public class Body { 

    private Object value; 

    @XmlAnyElement(lax=true) 
    public Object getValue() { 
     return value; 
    } 

    public void setValue(Object value) { 
     this.value = value; 
    } 

} 

CreateRq

import javax.xml.bind.annotation.XmlAccessorType; 
import javax.xml.bind.annotation.XmlAccessType; 
import javax.xml.bind.annotation.XmlRootElement; 
import javax.xml.bind.annotation.XmlType; 

@XmlRootElement 
@XmlAccessorType(XmlAccessType.FIELD) 
@XmlType(name = "createRq") 
public class CreateRq{  
    private String id; 
    // getters and setters omitted 
} 

demostración

import java.io.File; 

import javax.xml.bind.JAXBContext; 
import javax.xml.bind.Marshaller; 
import javax.xml.bind.Unmarshaller; 

public class Demo { 

    public static void main(String[] args) throws Exception { 
     JAXBContext jc = JAXBContext.newInstance(ServiceRq.class); 
     System.out.println(jc); 

     Unmarshaller unmarshaller = jc.createUnmarshaller(); 
     ServiceRq serviceRq = (ServiceRq) unmarshaller.unmarshal(new File("input.xml")); 

     Marshaller marshaller = jc.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
     marshaller.marshal(serviceRq, System.out); 

    } 

} 

Para más información

+0

Gracias que trabajaron. Solo quería agregar que tuve que agregar CreateRq a la inicialización de JAXBContext para que funcione. Gracias por su ayuda – BSingh

+0

Si establecemos lax en false (comportamiento predeterminado), ¿creará un objeto dom a partir del contenido xml y no intentará asignarlo a un objeto conocido? –

2

Puede usar @XmlAnyElement(lax=true) y la extensión @XmlPath en EclipseLink JAXB (MOXy) para manejar este caso de uso (Nota: yo soy el líder de MOXy). Para un enfoque que funcionaría con cualquier implementación de JAXB (Metro, MOXy, JaxMe, etc.) ver: Jaxb complex xml unmarshall.

ServiceRq

import javax.xml.bind.annotation.XmlAccessType; 
import javax.xml.bind.annotation.XmlAccessorType; 
import javax.xml.bind.annotation.XmlAnyElement; 
import javax.xml.bind.annotation.XmlRootElement; 
import javax.xml.bind.annotation.XmlType; 

import org.eclipse.persistence.oxm.annotations.XmlPath; 

@XmlRootElement 
@XmlAccessorType(XmlAccessType.FIELD) 
@XmlType(name = "serviceRq") 
public class ServiceRq{  

    @XmlPath("body/createRq") 
    @XmlAnyElement(lax=true) 
    private Object body; 
    // getters and setters omitted 
} 

CreateRq

import javax.xml.bind.annotation.XmlAccessorType; 
import javax.xml.bind.annotation.XmlAccessType; 
import javax.xml.bind.annotation.XmlRootElement; 
import javax.xml.bind.annotation.XmlType; 

@XmlRootElement 
@XmlAccessorType(XmlAccessType.FIELD) 
@XmlType(name = "createRq") 
public class CreateRq{  
    private String id; 
    // getters and setters omitted 
} 

Demostración

import java.io.File; 

import javax.xml.bind.JAXBContext; 
import javax.xml.bind.Marshaller; 
import javax.xml.bind.Unmarshaller; 

public class Demo { 

    public static void main(String[] args) throws Exception { 
     JAXBContext jc = JAXBContext.newInstance(ServiceRq.class); 

     Unmarshaller unmarshaller = jc.createUnmarshaller(); 
     ServiceRq serviceRq = (ServiceRq) unmarshaller.unmarshal(new File("input.xml")); 

     Marshaller marshaller = jc.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
     marshaller.marshal(serviceRq, System.out); 

    } 
} 

ja xb.properties

Para usar MOXy como su proveedor JAXB debe incluir un archivo llamado jaxb.propiedades en el mismo paquete que el modelo de dominio con la siguiente entrada:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory 

Para más información

Cuestiones relacionadas