JAXB unmarshalling not tolerating whitespace around token enumerations

那年仲夏 提交于 2020-01-15 09:13:00

问题


JAXB 2 (Oracle / Metro version 2.2.7 and I suspect others as well) doesn't seem to tolerate whitespace around values in enumeration elements.

Minimal example follows. Both xmllint and Xerces validate the instance against the schema. The puzzling think is that JAXB validation doesn't complain but returns null when trying to access the value. How can I configure it to return the value properly?

update: I 've tried associating an XmlAdapter to trim the strings, as suggested here, but the result is the same.

update II: And here's the ticket at Metro JAXB Jira.

A.xsd

<xs:schema targetNamespace="foo://a" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema" 
           xmlns="foo://a">

   <xs:element name="type" type="Type"/>

   <xs:simpleType name="Type">
     <xs:restriction base="xs:token">
         <xs:enumeration value="Archive"/>
         <xs:enumeration value="Organisation"/>
       </xs:restriction>
   </xs:simpleType>

</xs:schema>

a.xml

<a:type xmlns:a="foo://a" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="foo://a A.xsd"
>Organisation </a:type>

(notice the whitespace after 'Organisation')

unmarshalling code

public static void main(String args[]) throws Exception {
    SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    JAXBContext payloadContext = JAXBContext.newInstance("a");
    Unmarshaller unmarshaller = payloadContext.createUnmarshaller();
    unmarshaller.setSchema(schemaFactory.newSchema(new Source[]{new StreamSource(new FileInputStream(new File("A.xsd")))}));
    JAXBElement<?> oUnmarshalled = (JAXBElement<?>) unmarshaller.unmarshal(new File("a.xml"));
    Object o = oUnmarshalled.getValue(); // returns NULL
}

回答1:


When I run the following code using the JAXB implementation in JDK 1.7.0_21-b12 for the Mac with the documents from your question I get the enum value as output.

import javax.xml.XMLConstants;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.*;

public class Demo {

    public static void main(String args[]) throws Exception {
        StreamSource xsd = new StreamSource("src/forum17114304/A.xsd");
        StreamSource xml = new StreamSource("src/forum17114304/a.xml");

        SchemaFactory schemaFactory = SchemaFactory
                .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = schemaFactory.newSchema(xsd);
        schema.newValidator().validate(xml);

        JAXBContext payloadContext = JAXBContext.newInstance("a");
        Unmarshaller unmarshaller = payloadContext.createUnmarshaller();
        unmarshaller.setSchema(schema);
        JAXBElement<?> oUnmarshalled = (JAXBElement<?>) unmarshaller
                .unmarshal(xml);
        Object o = oUnmarshalled.getValue(); // returns ORGANISATION
        System.out.println(o);
    }

}

Output

ORGANISATION

UPDATE

There appears to be a bug in EclipseLink JAXB (MOXy) for this use case:

  • http://bugs.eclipse.org/410853

This bug has been fixed in the EclipseLink 2.5.1 and 2.6.0 streams. A nightly download can be obtained from the following link starting June 15, 2013:

  • http://www.eclipse.org/eclipselink/downloads/nightly.php



回答2:


Since (for the time being) I want to stick to JAXB RI (being drawn to the "RI" part alone), in the end I used the replace(., '^\s+|\s+$', '', 'm') in an XSLT 2.0 transformation as suggested here.

Relevant code section is:

    Source input = new StreamSource(new File("a.xml"));
    TransformerFactory factory = TransformerFactory.newInstance();
    Transformer wsTrimmer = factory.newTransformer(new StreamSource(new File("transform-trim-all.xslt")));

    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    wsTrimmer.transform(input, new StreamResult(bos));

    JAXBElement<?> oUnmarshalled = (JAXBElement<?>) unmarshaller.unmarshal(new ByteArrayInputStream(bos.toByteArray()));

The code requires Saxon HE on the runtime path as the XSLT used is , I've used the following ivy dependency:

<dependency org="net.sf.saxon" name="Saxon-HE" rev="9.4"/>

XSLT is:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="xml" omit-xml-declaration="no" indent="yes"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="text()">
       <xsl:sequence select="replace(., '^\s+|\s+$', '', 'm')"/>
    </xsl:template>
</xsl:stylesheet>


来源:https://stackoverflow.com/questions/17114304/jaxb-unmarshalling-not-tolerating-whitespace-around-token-enumerations

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!