Jaxb complex xml unmarshall

前端 未结 2 2039
情书的邮戳
情书的邮戳 2021-02-10 03:07

I am having issues to unmarshall nested xml below. Can someone please advise if I am missing something.
body tag can contain any Jaxb anotated obj.
Do I hav

相关标签:
2条回答
  • 2021-02-10 04:06

    You could use a @XmlAnyElement(lax=true) and an XmlAdapter to handle this use case:

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

    Body

    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
    }
    

    Demo

    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);
    
        }
    
    }
    

    For More Information

    • http://bdoughan.blogspot.com/2010/08/using-xmlanyelement-to-build-generic.html
    • http://bdoughan.blogspot.com/2010/07/xmladapter-jaxbs-secret-weapon.html
    • http://bdoughan.blogspot.com/2010/12/jaxb-and-immutable-objects.html
    • http://bdoughan.blogspot.com/2010/12/represent-string-values-as-element.html
    0 讨论(0)
  • 2021-02-10 04:11

    You could use @XmlAnyElement(lax=true) and the @XmlPath extension in EclipseLink JAXB (MOXy) to handle this use case (Note: I'm the MOXy lead). For an approach that would work with any JAXB implementation (Metro, MOXy, JaxMe, etc) see: 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
    }
    

    Demo

    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);
    
        }
    }
    

    jaxb.properties

    To use MOXy as your JAXB provider you must include a file named jaxb.properties in the same package as your domain model with the following entry:

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

    For More Information

    • http://bdoughan.blogspot.com/2010/08/using-xmlanyelement-to-build-generic.html
    • http://bdoughan.blogspot.com/2011/05/specifying-eclipselink-moxy-as-your.html
    • http://bdoughan.blogspot.com/2010/09/xpath-based-mapping-geocode-example.html
    • http://bdoughan.blogspot.com/2011/03/map-to-element-based-on-attribute-value.html
    0 讨论(0)
提交回复
热议问题