Jaxb 2.0 Schema validation problem

13,586

Solution 1

I assume that there might have been a fatalError reported. You didn't provide such information in your question. If this is the case you may read the explanation of your problem in the javadoc of ErrorHandler:

Note, however, that there is no requirement that the parser continue to report additional errors after a call to fatalError. In other words, a SAX driver class may throw an exception after reporting any fatalError.

I hope that this might explain your trouble.

Edit 1: After you posted your schema I think I know bothers you. The validator reports a single error per wrong element. In your case this is:

<xs:element name="destination" type="Destination"/>

The error will be something like (indicates missing stateID):

Error: Line:Col[7:13]:cvc-complex-type.2.4.a: Invalid content was found starting with element 'typeCode'. One of '{stateID}' is expected.

It does not report multiple errors because there is only one error report per complex type. If you change your complex type like this:

<xs:all>

You may get a different message, but again a single one:

Error: Line:Col[9:15]:cvc-complex-type.2.4.b: The content of element 'destination' is not complete. One of '{stateID, countryCode}' is expected.

If you modify your schema to accept multiple destination elements you may get 1 error message per element then.

Cheers!

Solution 2

There are a couple approaches you can leverage to validate your XML document against an XML schema.

javax.xml.validation APIs

The first is to use the javax.xml.validation APIs to validate your document against an XML schema without JAXB.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="destination" type="Destination"/>

  <xs:complexType name="Destination">
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="destinationID" type="xs:string" minOccurs="0"/>
      <xs:element name="shortDescription" type="xs:string" minOccurs="0"/>
      <xs:element name="longDescription" type="xs:string" minOccurs="0"/>
      <xs:element name="stateID" type="xs:string"/>
      <xs:element name="typeCode" type="xs:int"/>
      <xs:element name="countryCode" type="xs:string"/>
      <xs:element name="categories" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>

</xs:schema>

and the XML document:

<?xml version="1.0" encoding="UTF-8"?>
<destination xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="destination.xsd">
  <sd></sd>
  <name>Palampur</name>
  <destinationID>PLP</destinationID>
  <shortDescription>shortDescription</shortDescription>
  <longDescription>longDescription</longDescription>
  <typeCode>ZERO</typeCode>
  <categories>categories</categories>
</destination>

with the following demo code:

import java.io.File;

import javax.xml.XMLConstants;
import javax.xml.transform.sax.SAXSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

public class Demo {

    public static void main(String[] args) throws Exception {
        String xmlFileLocation = "src/validate/blog/input.xml";
        SAXSource source = new SAXSource(new InputSource(xmlFileLocation));

        SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = sf.newSchema(new File("src/validate/blog/customer.xsd"));
        Validator validator = schema.newValidator();
        validator.setErrorHandler(new MyErrorHandler());

        validator.validate(source);
        System.out.println("DONE");
    }

    private static class MyErrorHandler implements ErrorHandler {

        public void error(SAXParseException arg0) throws SAXException {
            System.out.println("ERROR");
            arg0.printStackTrace(System.out);
        }

        public void fatalError(SAXParseException arg0) throws SAXException {
            System.out.println("FATAL ERROR");
            arg0.printStackTrace(System.out);
        }

        public void warning(SAXParseException arg0) throws SAXException {
            System.out.println("WARNING ERROR");
            arg0.printStackTrace(System.out);
        }

    }

}

Will give the following output displaying multiple errors:

ERROR
org.xml.sax.SAXParseException: cvc-complex-type.2.4.a: Invalid content was found starting with element 'sd'. One of '{name}' is expected.
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator$XSIErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.reportSchemaError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleStartElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.startElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorHandlerImpl.startElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorHandlerImpl.validate(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorImpl.validate(Unknown Source)
    at javax.xml.validation.Validator.validate(Unknown Source)
    at validate.blog.Demo.main(Demo.java:27)
ERROR
org.xml.sax.SAXParseException: cvc-datatype-valid.1.2.1: 'ZERO' is not a valid value for 'integer'.
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator$XSIErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.reportSchemaError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.elementLocallyValidType(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.processElementContent(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleEndElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.endElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorHandlerImpl.endElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorHandlerImpl.validate(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorImpl.validate(Unknown Source)
    at javax.xml.validation.Validator.validate(Unknown Source)
    at validate.blog.Demo.main(Demo.java:27)
ERROR
org.xml.sax.SAXParseException: cvc-type.3.1.3: The value 'ZERO' of element 'typeCode' is not valid.
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator$XSIErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.reportSchemaError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.elementLocallyValidType(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.processElementContent(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleEndElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.endElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorHandlerImpl.endElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorHandlerImpl.validate(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorImpl.validate(Unknown Source)
    at javax.xml.validation.Validator.validate(Unknown Source)
    at validate.blog.Demo.main(Demo.java:27)
DONE

JAXB APIs

The second approach is to validate while performing an unmarshal operation with JAXB.

import java.io.File;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.xml.sax.InputSource;

public class JaxbDemo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Destination.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();

        SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = sf.newSchema(new File("src/validate/blog/customer.xsd"));
        unmarshaller.setSchema(schema);
        unmarshaller.setEventHandler(new MyValidationEventHandler());

        String xmlFileLocation = "src/validate/blog/input.xml";
        unmarshaller.unmarshal(new InputSource(xmlFileLocation));

    }

    private static class MyValidationEventHandler implements ValidationEventHandler {

        public boolean handleEvent(ValidationEvent arg0) {
            System.out.println(arg0.getSeverity());
            return true;
        }

    }

}

For More Information:

Share:
13,586
Umesh Awasthi
Author by

Umesh Awasthi

Updated on June 04, 2022

Comments

  • Umesh Awasthi
    Umesh Awasthi almost 2 years

    I am working with Jaxb 2.x and was trying to validate XML document with the given XSD using the following tutorial

    Tutorial Link

    hers is the code i have written

    unmarshaller.setSchema(schema);
            SAXSource source = new SAXSource(new InputSource(xmlFileLocation));
            Validator validator = schema.newValidator();
            validator.setErrorHandler(new XMLErrorHandler<Object>());
             try {
                    validator.validate(source);
                } catch (SAXException e) {
    

    and my XMLErrorHanlder class have following signature

    public class XMLErrorHandler<T> implements ErrorHandler {
    public void error(SAXParseException exception) throws SAXException {
            xmlUnmarshaller.setValidationFlag(true);
            log.error(
                    "Line:Col[" + exception.getLineNumber()
                    + ":" + exception.getColumnNumber()
                    + "]:" + exception.getMessage());
    
    
            exception.printStackTrace();
    
        }
                           }
    
    }
    

    code for warning and fatal has been removed now its validating the XML with XSD but it only showing the first encountered error while i want to get print on colsole all errors and warning on console

    i am not sure where i am doing wrong any help in this will be helpful

    Edit1 here is the portion of XSD file

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    
      <xs:element name="destination" type="Destination"/>
    
      <xs:complexType name="Destination">
        <xs:sequence>
          <xs:element name="name" type="xs:string"/>
          <xs:element name="destinationID" type="xs:string" minOccurs="0"/>
          <xs:element name="shortDescription" type="xs:string" minOccurs="0"/>
          <xs:element name="longDescription" type="xs:string" minOccurs="0"/>
          <xs:element name="stateID" type="xs:string"/>
          <xs:element name="typeCode" type="xs:int"/>
          <xs:element name="countryCode" type="xs:string"/>
          <xs:element name="categories" type="xs:string"/>
          <xs:element name="transport" type="Transport" minOccurs="0" maxOccurs="1"/>
          <xs:element name="cultures" type="Cultures" minOccurs="0"/>
          <xs:element name="events" type="Events" minOccurs="0" maxOccurs="1"/>
          <xs:element name="placesToVisit" type="PlacesToVisit" minOccurs="0" maxOccurs="1"/>
          <xs:element name="contacts" type="Contact" minOccurs="0" maxOccurs="1"/>
          <xs:element name="addresses" type="address" minOccurs="0" maxOccurs="1"/>
        </xs:sequence>
      </xs:complexType>
    

    and the XML file is

    <destination xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="destination.xsd">
      <name>Palampur</name>
      <destinationID>PLP</destinationID>
      <shortDescription>shortDescription</shortDescription>
      <longDescription>longDescription</longDescription>
      <typeCode>0</typeCode>
      <categories>categories</categories>
    

    what my assumption after doing some R&D is that there is some issue with XSD structure or the generated XML but i am not sure abt it

  • Umesh Awasthi
    Umesh Awasthi about 13 years
    @lucho: i am handling fatal error also in my code and stack trace is not sjowing any such error
  • Lachezar Balev
    Lachezar Balev about 13 years
    Then you'd better post the contents of your XML file (located at xmlFileLocation). If the xsd is not the same as in the tutorial post it too. The tutorial works as expected :/
  • Lachezar Balev
    Lachezar Balev about 13 years
    And what about this? :) -> xmlUnmarshaller.setValidationFlag(true); You should not need it.
  • Lachezar Balev
    Lachezar Balev about 13 years
    @umesh awasthi: see my update corresponding to your update :-)
  • Umesh Awasthi
    Umesh Awasthi about 13 years
    @Lucho:agree thats is what currently happening i have stateID and typeCode as required fields now if both tags are missing from the XML it will only report that expected tag stateID is missing but no error flag for other missing tag typeCode. in second case if stateId is missing and typeCode containg invalid data it will complian about stateId missing and data type but will say nothing for any other missing tags.I want it should show all error of the XML if any tag missing or any invalid data in XML.
  • Umesh Awasthi
    Umesh Awasthi about 13 years
    Blaise:i tried your way but noted a strange way countryCode is also a required filed in the XML as per XSD but the validation said nothing about the this field absence in the XML.also if i remove typeCode validation will say nothing about this missing field at all it than compliant only about stateID and will exist and will not point any other missing filed or invalid data.i was expecting that validator should come up with one run what tags are missing and what invalid data in any is in XML.i don't want user to show one error at time rather want all error at one go so that he can correct once
  • Lachezar Balev
    Lachezar Balev about 13 years
    I'm afraid (though I do not guarantee) that this is not possible with the standard parser and your XSD. Maybe you can change the XSD but this is pointless.
  • bdoughan
    bdoughan about 13 years
    Umesh - For the specific details of when javax.xml.validation APIs throw an exception you may need to consult the JAXP specification or post a non-JAXB example to Stack Overflow to get a wider Java/XML audience.
  • Vishal Zanzrukia
    Vishal Zanzrukia almost 9 years
    Hi @BlaiseDoughan, what is the reason behind that error. I am getting same error, but not getting the reason :( Also why DONE has been printed at last even if error has been thrown..!