Balaji
Balaji

Reputation: 89

JAXB Eclipse Link Moxy: ClassCastException while Unmarshalling JSON using schema validation

I am using eclipse link(v2.5.1) Dynamic JAXB to convert XML to JSON and viceversa using a multiple schemas. While umarshalling the JSON to XML,I want to validate the JSON(against the XSD) and Dynamic Moxy is unable to validate the generated JSON and results in classcast exception.

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>

sample.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>

The driver program to test is as follows

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();
        }
    }
}

Generated Sample JSON

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

While unmarshalling the below exception was seen

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)

EDIT:Corrected the generated sample json

Question

The intention is to check whether JSON conforms to the XML schema. Does Dynamic JAXB support JSON Validation while unmarshalling? Is this a bug in Dynamic JAXB Moxy?

Upvotes: 2

Views: 1609

Answers (1)

bdoughan
bdoughan

Reputation: 148977

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.

You are hitting the following issue which was fixed in the 2.5.1 (and 2.6.0) streams.

The fix is available in EclipseLink 2.5.1 (and 2.6.0) in the nightly builds starting September 11, 2013 from the following link:


Schema Validation and JSON Unmarshalling

Due to how we need to process the JSON document, validating the JSON input against an XML schema is not guaranteed to work. Below is the exception you will get for your use case once you get the ClassCastException fix.

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

Upvotes: 1

Related Questions