Marshalling with XSD choice field in class

2019-07-30 01:44发布

问题:

I use a Java class to generate the WSDL schema dynamically. I have this as one of my fields:

@XmlElements({
    @XmlElement(name = "A", type = String.class),
    @XmlElement(name = "B", type = Integer.class),
    @XmlElement(name = "C", type = String.class),
    @XmlElement(name = "D", type = String.class)
})
protected Object aOrBOrCOrD;

During marshalling, when the single choice property aOrBOrCOrD is set, which tag name(A, B, C or D) would be set in the XML?

Since there's only one field which would contain the data. And String could also mean any 1 of the 3 choice elements. How to get around this?

Can I split the single field in 4 and still maintain the choice property when the WSDL is generated somehow?

回答1:

You could do the following:

Java Model

Foo

Instead of @XmlElements and a property of type Object, you can use @XmlElementRefs and a property of type JAXBElement. A JAXBElement allows you to preserve the element name.

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Foo {

    @XmlElementRefs({
        @XmlElementRef(name = "A", type = JAXBElement.class),
        @XmlElementRef(name = "B", type = JAXBElement.class),
        @XmlElementRef(name = "C", type = JAXBElement.class),
        @XmlElementRef(name = "D", type = JAXBElement.class)
    })
    protected JAXBElement<?> aOrBOrCOrD;

}

ObjectFactory

Along with @XmlElementRef you need to have a corresponding @XmlElementDec annotations on a class annotated with @XmlRegistry.

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
import javax.xml.namespace.QName;

@XmlRegistry
public class ObjectFactory {

    @XmlElementDecl(name="A")
    public JAXBElement<String> createA(String value) {
        return new JAXBElement<String>(new QName("A"), String.class, value);
    }

    @XmlElementDecl(name="B")
    public JAXBElement<Integer> createB(Integer value) {
        return new JAXBElement<Integer>(new QName("B"), Integer.class, value);
    }

    @XmlElementDecl(name="C")
    public JAXBElement<String> createC(String value) {
        return new JAXBElement<String>(new QName("C"), String.class, value);
    }

    @XmlElementDecl(name="D")
    public JAXBElement<String> createD(String value) {
        return new JAXBElement<String>(new QName("D"), String.class, value);
    }

}

Demo Code

Demo

import java.io.StringReader;
import javax.xml.bind.*;

public class Demo {

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

        StringReader xml = new StringReader("<foo><C>Hello World</C></foo>");
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Foo foo = (Foo) unmarshaller.unmarshal(xml);

        JAXBElement<?> aOrBOrCOrD = foo.aOrBOrCOrD;
        System.out.println(aOrBOrCOrD.getName().getLocalPart());
        System.out.println(aOrBOrCOrD.getDeclaredType());
        System.out.println(aOrBOrCOrD.getValue());
    }

}

Output

C
class java.lang.String
Hello World