简体   繁体   中英

JAXB binding to remove propOrder

I have written an XSD:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
            targetNamespace="http://api.synthesys/models/generated/simple/chat"
            xmlns:drsc="http://api.synthesys/models/generated/simple/chat"
            xmlns:simplify="http://jaxb2-commons.dev.java.net/basic/simplify"
            jaxb:extensionBindingPrefixes="simplify"
            jaxb:version="2.1">
    <xsd:element name="conversation">
        <xsd:complexType>
            <xsd:sequence>

                <xsd:element name="start-time" type="xsd:dateTime" minOccurs="1" maxOccurs="1"/>


                <xsd:choice minOccurs="0" maxOccurs="unbounded">

                    <!-- for code generation, allowing direct and distinct access to the messages and events -->
                    <xsd:annotation>
                        <xsd:appinfo>
                            <simplify:as-element-property/>
                        </xsd:appinfo>
                    </xsd:annotation>

                    <!--messages-->
                    <xsd:element name="message">
                        <xsd:complexType>
                            <xsd:sequence>
                                <xsd:element name="author" minOccurs="1" maxOccurs="1" type="xsd:string"/>
                                <xsd:element name="text" minOccurs="1" maxOccurs="1" type="xsd:string"/>
                            </xsd:sequence>
                        </xsd:complexType>
                    </xsd:element>

                    <!--room events: entering or exiting the room-->
                    <xsd:element name="event">
                        <xsd:complexType>
                            <xsd:sequence>
                                <xsd:element name="who" minOccurs="1" maxOccurs="1" type="xsd:string"/>
                                <xsd:element name="what" minOccurs="1" maxOccurs="1" type="xsd:string"/>
                            </xsd:sequence>
                        </xsd:complexType>
                    </xsd:element>
                </xsd:choice>

                <!--end time millis-->
                <xsd:element name="end-time" type="xsd:dateTime" minOccurs="1" maxOccurs="1"/>

            </xsd:sequence>

        </xsd:complexType>
    </xsd:element>
</xsd:schema>

and I have written a sample XML file:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<mine:conversation xmlns:mine="http://api.synthesys/models/generated/simple/chat">
    <start-time>2017-09-10T12:00:00.000Z</start-time>
    <event>
        <who>John</who>
        <what>entered the room</what>
    </event>
    <message>
        <author>John</author>
        <text>hello</text>
    </message>
    <event>
        <who>Jane</who>
        <what>entered the room</what>
    </event>
    <message>
        <author>Jane</author>
        <text>goodbye, John</text>
    </message>
    <event>
        <who>Jane</who>
        <what>left the room</what>
    </event>
    <event>
        <who>John</who>
        <what>left the room</what>
    </event>
    <end-time>2017-09-10T12:01:00.000Z</end-time>
</mine:conversation>

And with the maven-jaxb2-plugin I have been able to generate a class from this schema like this:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "startTime",
    "messages",
    "events",
    "endTime"
})
@XmlRootElement(name = "conversation")
public class Conversation {

    @XmlElement(name = "start-time", required = true, type = String.class)
    @XmlJavaTypeAdapter(Adapter1 .class)
    @XmlSchemaType(name = "dateTime")
    protected XMLGregorianCalendar startTime;
    @XmlElement(name = "message")
    protected List<Conversation.Message> messages;
    @XmlElement(name = "event")
    protected List<Conversation.Event> events;
    @XmlElement(name = "end-time", required = true, type = String.class)
    @XmlJavaTypeAdapter(Adapter1 .class)
    @XmlSchemaType(name = "dateTime")
    protected XMLGregorianCalendar endTime; 

The problem is that when I try to use JAXB to unmarshall my sample xml file like this:

class MarshalUnmarshalTest extends Specification {
    def "test"(){
        setup:
        SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        JAXBContext context = JAXBContext.newInstance(synthesys.api.models.generated.simple.chat.Conversation.class)
        Marshaller marshaller = context.createMarshaller()
        Unmarshaller unmarshaller = context.createUnmarshaller()
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        context.generateSchema(new StructuredDataUtils.StructuredDataSchemaOutputResolver(bos));
        Schema schema = sf.newSchema(new StreamSource(new ByteArrayInputStream(bos.toByteArray())));
        marshaller.setSchema(schema)
        unmarshaller.setSchema(schema)

        File input = new File("src/test/resources/data/genericChat/simple-valid.xml")


        when:
        def object = unmarshaller.unmarshal(input.newInputStream())

        then:
        object instanceof synthesys.api.models.generated.simple.chat.Conversation
    }
}

I get this error:

    javax.xml.bind.UnmarshalException
 - with linked exception:
[org.xml.sax.SAXParseException; lineNumber: 8; columnNumber: 14; cvc-complex-type.2.4.a: Invalid content was found starting with element 'message'. One of '{event, end-time}' is expected.]
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:335)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:563)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:249)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:204)
    at synthesys.api.models.generated.standard.chat.MarshalUnmarshalTest.test(MarshalUnmarshalTest.groovy:31)
Caused by: org.xml.sax.SAXParseException; lineNumber: 8; columnNumber: 14; cvc-complex-type.2.4.a: Invalid content was found starting with element 'message'. One of '{event, end-time}' is expected.
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:203)
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:134)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:437)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:368)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:325)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator$XSIErrorReporter.reportError(XMLSchemaValidator.java:458)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.reportSchemaError(XMLSchemaValidator.java:3237)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleStartElement(XMLSchemaValidator.java:1796)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.startElement(XMLSchemaValidator.java:746)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorHandlerImpl.startElement(ValidatorHandlerImpl.java:570)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.ValidatingUnmarshaller.startElement(ValidatingUnmarshaller.java:86)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:163)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:509)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:379)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2786)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:117)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:649)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:243)
    ... 4 more

What's really frustrating to me is that this sample file validates when using xmllint --noout --schema path/to/schema.xsd path/to/sample.xml . It seems to me that the main issue is that the generated Conversation class defines a propOrder that is more restrictive than the schema actually is.

Can anyone point me to how I can configure the simplify plugin to not generate this propOrder? Or how I can otherwise leverage bindings to remove that restriction? I do want to maintain the current behavior where my generated class has both a List<Message> messages property and a List<Event> events property, rather than a single List<Object> messagesOrEvents

Disclaimer: I am the author of the JAXB2 Simplify Plugin and JAXB2 Annotate Plugin .

The problem is that simplifying the property (like you did) effectively changes the structure of the XML. It's no longer message , event , end-time in any order. It's some fixed order after the simplification. That's the price you pay for the easier-to-use structure in the Java model.

Can anyone point me to how I can configure the simplify plugin to not generate this propOrder?

No. The simplify plugin does not generate propOrder , XJC does. The simplify plugin only "converts" a heterogeneous property into several simple homogeneous properties. It has nothing to do with propOrder .

It is possible to customize the generated @XmlType annotation using the JAXB2 Annotate Plugin , but I'm not quite sure if propOrder is the problem. To be honest I am somehow surprized that you have problems with the order of elements. I always thought JAXB did not care about the order when unmarshalling.

If you want, please post your minimal sample project under https://github.com/highsource/maven-jaxb2-plugin-support/tree/master/s/simplify , I will take a look.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM