【问题标题】:JAXB Eclipse Link Moxy: ClassCastException while Unmarshalling JSON using schema validationJAXB Eclipse Link Moxy:使用模式验证解组 JSON 时出现 ClassCastException
【发布时间】:2013-09-16 09:48:05
【问题描述】:

我正在使用 eclipse 链接(v2.5.1)动态 JAXB 将 XML 转换为 JSON,反之亦然,使用多个模式。在将 JSON 编组为 XML 时,我想验证 JSON(针对 XSD)并且 Dynamic Moxy 无法验证生成的 JSON 并导致类转换异常。

emp.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:emp="Employee:2:0" targetNamespace="Employee:2:0"
    elementFormDefault="unqualified" attributeFormDefault="unqualified"
    version="2.0">

    <xsd:element name="searchManager" type="emp:SearchManager" />

    <xsd:complexType name="SearchManager">
        <xsd:sequence>
            <xsd:element name="CompanyName" type="xsd:string" />
            <xsd:element name="objects" type="emp:Employee" minOccurs="0" maxOccurs="unbounded" />
        </xsd:sequence>
    </xsd:complexType>


    <xsd:complexType name="Employee">

        <xsd:complexContent>
            <xsd:extension base="emp:Organization">
                <xsd:sequence>
                   <xsd:element name="EmpId" type="xsd:string" minOccurs="0" />
                </xsd:sequence>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>

    <xsd:complexType name="Projects">
        <xsd:complexContent>
            <xsd:extension base="emp:Organization"/>
        </xsd:complexContent>
    </xsd:complexType>

    <xsd:complexType name="Organization">
        <xsd:annotation>
            <xsd:documentation>Abstract base class </xsd:documentation>
        </xsd:annotation>
    </xsd:complexType>
</xsd:schema>

Manager.xsd

<?xml version="1.0" encoding="UTF-8"?>

<xs:schema targetNamespace="Manager:1:0" xmlns:emp="Employee:2:0"
    xmlns:manager="Manager:1:0" xmlns="http://www.w3.org/2001/XMLSchema"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema"
    elementFormDefault="unqualified" attributeFormDefault="unqualified"
    version="1.0">
    <!-- schema imports -->
    <xs:import namespace="Employee:2:0" schemaLocation="emp.xsd" />

    <xs:complexType name="Manager">
        <xs:annotation>
            <xs:documentation>
                Definition of class Employee
            </xs:documentation>
        </xs:annotation>
        <xs:complexContent>
            <xs:extension base="emp:Employee">
                <xs:sequence>
                    <xs:element name="teamSize" type="xsd:int" minOccurs="0" />
                    <xs:element name="project1" type="manager:Project1"
                        minOccurs="0" maxOccurs="unbounded" />
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>


    <xs:complexType name="Project1">
        <xs:complexContent>
            <xs:extension base="manager:Developement">
                <xs:sequence>
                    <xs:element name="type" type="xsd:int" minOccurs="0" />
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>
    <xs:complexType name="Developement">
        <xs:annotation>
            <xs:documentation>
                Abstract base class for an Development
            </xs:documentation>
        </xs:annotation>
        <xs:complexContent>
            <xs:extension base="emp:Projects"/>
        </xs:complexContent>
    </xs:complexType>
</xs:schema>

示例.xml

<emp:searchManager xmlns:emp="Employee:2:0"
    xmlns:manager="Manager:1:0">
    <CompanyName>Test</CompanyName>
    <objects xmlns:ns2="Manager:1:0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:Manager">
        <EmpId>123456</EmpId>
        <teamSize>10</teamSize>
        <project1>
            <type>1</type>
        </project1>
    </objects>
</emp:searchManager>

要测试的驱动程序如下

public class XMLToJSON {

    /**
     * @param args
     */
    public static void main(String[] args) {

        FileInputStream xsdInputStream;
        try {
            xsdInputStream = new FileInputStream("Manager.xsd");
            DynamicJAXBContext jaxbContext = DynamicJAXBContextFactory.createContextFromXSD(xsdInputStream, new MyEntityResolver(), null, null);
            FileInputStream xmlInputStream = new FileInputStream("sample.xml");
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            JAXBElement<DynamicEntity> manager = (JAXBElement) unmarshaller.unmarshal(xmlInputStream);


            Marshaller marshaller = jaxbContext.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            //input xml to print
            marshaller.marshal(manager, System.out);

            Map namespaces = new HashMap();
            namespaces.put("http://www.w3.org/2001/XMLSchema-instance", "xsi");
            namespaces.put("Employee:2:0", "ns1"); 
            namespaces.put("Manager:1:0", "ns2");

            // XML to JSON
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
            marshaller.setProperty(MarshallerProperties.NAMESPACE_PREFIX_MAPPER, namespaces);
            FileOutputStream jsonOutputStream = new FileOutputStream("sample.json");
            marshaller.marshal(manager, jsonOutputStream);
            marshaller.marshal(manager, System.out);

            //JSON to XML
            JAXBUnmarshaller jsonUnmarshaller = jaxbContext.createUnmarshaller();
            jsonUnmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json");
            jsonUnmarshaller.setProperty(UnmarshallerProperties.JSON_NAMESPACE_PREFIX_MAPPER, namespaces);
            jsonUnmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, true);
            jsonUnmarshaller.setProperty(UnmarshallerProperties.JSON_ATTRIBUTE_PREFIX, "@");
            SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 
            Schema schema = sf.newSchema(new File("Manager.xsd")); 
            jsonUnmarshaller.setSchema(schema);
            StreamSource json = new StreamSource("sample.json");
            JAXBElement<DynamicEntity> myroot = (JAXBElement) jsonUnmarshaller.unmarshal(json);
            Marshaller m = jaxbContext.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,true);
            m.marshal(myroot, System.out);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (JAXBException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

生成的示例 JSON

    {
   "ns1.searchManager" : {
      "CompanyName" : "Test",
      "objects" : [ {
         "xsi.type" : "ns2.Manager",
         "EmpId" : "123456",
         "teamSize" : 10,
         "project1" : [ {
            "type" : 1
         } ]
      } ]
   }
}

在解组时发现以下异常

Exception in thread "main" java.lang.ClassCastException: org.eclipse.persistence.internal.oxm.record.XMLReaderAdapter$ExtendedContentHandlerAdapter cannot be cast to org.eclipse.persistence.internal.oxm.record.UnmarshalRecord
    at org.eclipse.persistence.internal.oxm.record.json.JSONReader.isTextValue(JSONReader.java:454)
    at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:350)
    at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:244)
    at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:430)
    at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:299)
    at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parseRoot(JSONReader.java:166)
    at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:125)
    at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:140)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:778)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:666)
    at org.eclipse.persistence.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:593)
    at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:287)
    at XMLToJSON.main(XMLToJSON.java:74)

编辑:更正了生成的示例 json

问题

目的是检查 JSON 是否符合 XML 模式。 Dynamic JAXB 在解组时是否支持 JSON 验证?这是 Dynamic JAXB Moxy 中的错误吗?

【问题讨论】:

    标签: eclipselink moxy


    【解决方案1】:

    注意:我是EclipseLink JAXB (MOXy) 的负责人,也是JAXB (JSR-222) 专家组的成员。

    您遇到了以下问题,该问题已在 2.5.1(和 2.6.0)流中修复。

    从 2013 年 9 月 11 日开始,EclipseLink 2.5.1(和 2.6.0)的夜间版本中提供了该修复程序,链接如下:


    架构验证和 JSON 解组

    由于我们需要处理 JSON 文档,因此无法保证根据 XML 模式验证 JSON 输入。以下是获得 ClassCastException 修复后您的用例将获得的例外情况。

    javax.xml.bind.UnmarshalException
     - with linked exception:
    [Exception [EclipseLink-25004] (Eclipse Persistence Services - @VERSION@.@QUALIFIER@): org.eclipse.persistence.exceptions.XMLMarshalException
    Exception Description: An error occurred unmarshalling the document
    Internal Exception: org.xml.sax.SAXParseException; cvc-complex-type.2.4.d: Invalid content was found starting with element 'teamSize'. No child element is expected at this point.]
        at org.eclipse.persistence.jaxb.JAXBUnmarshaller.handleXMLMarshalException(JAXBUnmarshaller.java:980)
        at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:290)
        at forum18824990.XMLToJSON.main(XMLToJSON.java:63)
    Caused by: Exception [EclipseLink-25004] (Eclipse Persistence Services - @VERSION@.@QUALIFIER@): org.eclipse.persistence.exceptions.XMLMarshalException
    Exception Description: An error occurred unmarshalling the document
    Internal Exception: org.xml.sax.SAXParseException; cvc-complex-type.2.4.d: Invalid content was found starting with element 'teamSize'. No child element is expected at this point.
        at org.eclipse.persistence.exceptions.XMLMarshalException.unmarshalException(XMLMarshalException.java:115)
        at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:144)
        at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:784)
        at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:666)
        at org.eclipse.persistence.internal.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:566)
        at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:287)
        ... 1 more
    Caused by: org.xml.sax.SAXParseException; cvc-complex-type.2.4.d: Invalid content was found starting with element 'teamSize'. No child element is expected at this point.
        at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:198)
        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:453)
        at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.reportSchemaError(XMLSchemaValidator.java:3232)
        at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleStartElement(XMLSchemaValidator.java:1795)
        at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.startElement(XMLSchemaValidator.java:741)
        at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorHandlerImpl.startElement(ValidatorHandlerImpl.java:565)
        at org.eclipse.persistence.internal.oxm.record.XMLReader$ValidatingContentHandler.startElement(XMLReader.java:431)
        at org.eclipse.persistence.internal.oxm.record.XMLReaderAdapter$ExtendedContentHandlerAdapter.startElement(XMLReaderAdapter.java:178)
        at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:302)
        at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:436)
        at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:418)
        at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:244)
        at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:436)
        at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:303)
        at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parseRoot(JSONReader.java:166)
        at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:125)
        at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:140)
        ... 5 more
    

    【讨论】:

    • 我使用了该修复程序,现在没有 classcastexception,而是您上面提到的新 SAX 异常。您能解释一下到底是什么问题吗?(例如,多个命名空间/多个 XSD 有问题吗?)有什么解决方法吗?在服务器端,我从客户端收到一个 JSON,我只有 XSD,我想使用它来验证 JSON。是否将输入 JSON 分离到它们各自的命名空间中,然后针对支持的单个 XSD 验证此片段 JSON?还有其他解决方案吗?
    猜你喜欢
    • 1970-01-01
    • 2014-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-25
    • 1970-01-01
    • 2015-10-19
    • 1970-01-01
    相关资源
    最近更新 更多