1

I have an XML schema that restricts movie ratings to have a value between 1 and 10 inclusive. However the JAXB Binding allows me save a movie with a rating of 11. Is there a way to get JAXB to throw an exception during the marshal if a value does not adhere to the restrictions in the XSD?

Here is the XSD:

<?xml version="1.0"?>
<xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

    <xsd:simpleType name="RatingType">
        <xsd:annotation>
            <xsd:documentation xml:lang="en">A rating between 1 and 10 inclusive</xsd:documentation>
        </xsd:annotation>
        <xsd:restriction base="xsd:float">
            <xsd:minInclusive value="1.0" />
            <xsd:maxInclusive value="10.0" />
        </xsd:restriction>
    </xsd:simpleType>

    <xsd:complexType name="MovieRatingType">
        <xsd:sequence>
            <xsd:element name="Title" type="xsd:string" minOccurs="1" maxOccurs="1" />
            <xsd:element name="Rating" type="RatingType" minOccurs="1" maxOccurs="1" />
        </xsd:sequence>
    </xsd:complexType>

    <xsd:complexType name="MoviesListType">
        <xsd:sequence>
            <xsd:element name="Movie" type="MovieRatingType" maxOccurs="unbounded" />
        </xsd:sequence>
    </xsd:complexType>

    <xsd:element name="Movies" type="MoviesListType" />

</xsd:schema>

Here is the code:

import generated.MovieRatingType;
import generated.MoviesListType;
import generated.ObjectFactory;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

public class RestrictionTest {

    public static void main(String[] args) {

        ObjectFactory factory = new ObjectFactory();

        MovieRatingType movie = new MovieRatingType();
        movie.setTitle("Terminator");
        movie.setRating(11.3f); //<--- rating set to higher than the allowed value

        MoviesListType movieList = factory.createMoviesListType();
        movieList.getMovie().add(movie);

        JAXBElement<MoviesListType> moviesListJAXB = factory.createMovies(movieList);

        try {

            File file = new File("C:\\Users\\perezsmithf\\Desktop\\dev\\java\\scratch\\src\\output.xml");
            JAXBContext jaxbContext = JAXBContext.newInstance(MoviesListType.class);
            Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

            // output pretty printed
            jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

            jaxbMarshaller.marshal(moviesListJAXB, file); //<--- at this point it should throw an exception because the rating is too high
            jaxbMarshaller.marshal(moviesListJAXB, System.out);

        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }
}
Fidel
  • 7,027
  • 11
  • 57
  • 81

1 Answers1

1

You need to register a ValidationEventHandler which gets notified on errors:

SchemaFactory f = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = f.newSchema(new File("schema.xsd")); 

marshaller.setSchema(schema);
marshaller.setEventHandler(new MyValidationEventHandler());

In your ValidationEventHandler you can handle the validation events as required:

public class MyValidationEventHandler implements ValidationEventHandler {
    public boolean handleEvent(ValidationEvent event) {
        // handle validation events
        // if you return false the marshal operation is stopped
    }    
}
Sebastian
  • 16,813
  • 4
  • 49
  • 56