JAXB绑定删除propOrder

时间:2017-09-11 21:26:40

标签: xsd jaxb xjc xjb jaxb2-simplify-plugin

我写了一个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>

我写了一个示例XML文件:

<?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>

使用maven-jaxb2-plugin,我已经能够从这个模式生成一个类,如下所示:

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

问题在于,当我尝试使用JAXB来解组我的样本xml文件时:

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

我收到此错误:

    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

对我来说真正令人沮丧的是,此示例文件在使用xmllint --noout --schema path/to/schema.xsd path/to/sample.xml时会生效。在我看来,主要问题是生成的Conversation类定义了propOrder,它比模式实际上更具限制性。

有人能指出我如何配置简化插件以不生成此propOrder?或者我如何利用绑定来消除这种限制?我确实希望保持当前行为,即我生成的类具有List<Message> messages属性和List<Event> events属性,而不是单个List<Object> messagesOrEvents

1 个答案:

答案 0 :(得分:0)

免责声明:我是JAXB2 Simplify PluginJAXB2 Annotate Plugin的作者。

问题是简化属性(就像你一样)有效地改变了XML的结构。它不再是messageeventend-time的任何顺序。简化后它是一些固定的顺序。这是您为Java模型中更易于使用的结构付出的代价。

  

有人能指出我如何配置简化插件以不生成此propOrder吗?

没有。简化插件不会生成propOrder,XJC会生成。仅简化插件&#34;转换&#34;异构属性分为几个简单的同质属性。它与propOrder无关。

可以使用JAXB2 Annotate Plugin自定义生成的@XmlType注释,但我不确定propOrder是否存在问题。说实话,我有点惊讶你的元素顺序有问题。我总是认为JAXB在解组时不关心顺序。

如果您愿意,请在https://github.com/highsource/maven-jaxb2-plugin-support/tree/master/s/simplify下发布您的最小样本项目,我会看看。