Re: XSD validation during unmarshalling

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: XSD validation during unmarshalling

Paul Sandoz
Administrator
Hi Andrew,

Unmarshaller.setValidating is indeed deprecated and you need to set the
Schema object to validate against.

In this respect i am unsure how you can create a general validating
mechanism unless you keep a map of known JAXB class to Schema instance.

You will have to create the Schema instances from the correspondingly
available XSD, more info can be found here [1].

Rather than creating a general validating mechanism it might be better
to have a general mechanism you inherit from for specific validating
purposes i.e. provides the JAXB context and a set of schema.

Paul.

[1]
http://www.java-tips.org/java-ee-tips/java-architecture-for-xml-binding/what-is-new-in-jaxb-2.0.html

Andrew Cole wrote:

> Now that Paul is back, I would like to promote this thread again.  
> Paul-- any help you can provide will be greatly appreciated.
>
> Thanks,
> Andrew
>
> On Mon, Jul 7, 2008 at 2:22 PM, Andrew Cole <[hidden email]
> <mailto:[hidden email]>> wrote:
>
>     While Paul is on vacation, can somebody help illuminate his response
>     to my query below?  Trying to follow his instructions, I have
>     implemented a ContextResolver as follows:
>
>     @Provider
>     public class ValidatingJAXBContextResolver implements
>     ContextResolver<JAXBContext> {
>            public JAXBContext getContext(Class<?> type) {
>                    try {
>                            return new ValidatingJAXBContext(type);
>                    } catch (JAXBException e) {
>                            return null;
>                    }
>            }
>      }
>
>     and a JAXBContext (modeled after the JSONJAXBContext in the jersey
>     source) as:
>
>     public class ValidatingJAXBContext extends JAXBContext {
>            private final JAXBContext jaxbContext;
>
>            public ValidatingJAXBContext(Class... classesToBeBound)
>     throws JAXBException {
>                    jaxbContext = JAXBContext.newInstance(classesToBeBound);
>            }
>
>        public ValidatingJAXBContext(Class[] classesToBeBound, Map<String,
>     Object> properties) throws JAXBException {
>            jaxbContext = JAXBContext.newInstance(classesToBeBound,
>     properties);
>        }
>
>        @Override
>        public Unmarshaller createUnmarshaller() throws JAXBException {
>            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
>            unmarshaller.setValidating(true);
>            return unmarshaller;
>        }
>
>        @Override
>        public Marshaller createMarshaller() throws JAXBException {
>            return jaxbContext.createMarshaller();
>        }
>
>        @Override
>        public Validator createValidator() throws JAXBException {
>            return jaxbContext.createValidator();
>        }
>
>     }
>
>     Now, when I hit a method that would require unmarshalling content from
>     XML, I receive an exception at my call to setValidating:
>     java.lang.UnsupportedOperationException
>            at
>     com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.setValidating(UnmarshallerImpl.java:483)
>            at
>     myCode.ValidatingJAXBContext.createUnmarshaller(ValidatingJAXBContext.java:33)
>            at
>     com.sun.ws.rest.impl.provider.entity.XMLRootElementProvider.readFrom(XMLRootElementProvider.java:58)
>            at
>     com.sun.ws.rest.spi.container.AbstractContainerRequest.getEntity(AbstractContainerRequest.java:179)
>     [stack trace truncated]
>
>     Am I on the right track here?  As I understand it, the call to
>     setValidating is deprecated in JAXB 2.0 and I should use setSchema.
>     Is this correct?  If so, how can I have my ValidatingJAXBContext class
>     create an appropriate javax.xml.validation.Schema object for this
>     call, based on the classToBeBound passed in to the constructor?
>
>     On Thu, Jul 3, 2008 at 10:20 PM, Paul Sandoz <[hidden email]
>     <mailto:[hidden email]>> wrote:
>      >
>      > On Jul 4, 2008, at 1:05 AM, Andrew Cole wrote:
>      >
>      > Hi all
>      >
>      > I'm using Jersey 0.7 and have a number of methods that accept
>     objects unmarshalled from XML via JAXB bindings.  It does not appear
>     that the unmarshalling process is validating the XML against the
>     schema used to create the JAXB bindings.  For instance, I have a
>     pattern restriction on a string element that is not being respected,
>     and I can leave out elements that have a minOccurs of 1.  How can I
>     configure the unmarshaller to validate against my schema?
>      >
>      >
>      > Currently you need to supply your own JAXBContext that returns a
>     validating unmarshaller for unmarshalling the JAXB types that
>     require validation.
>      > See ContextResolver [1].
>      > In this case you would do:
>      >   public class MyContextResolver implements
>     ContextResolver<JAXBContext> {
>      >     JAXBContext getContext(Class<?> type) { ... }
>      >   }
>      > I plan to make this easier so you can use ContextResolver with an
>     Unmarshaller/Marshaller thus you don't have to wrap JAXBContext.
>      > Paul.
>      > [1]
>     https://jsr311.dev.java.net/nonav/releases/0.8/javax/ws/rs/ext/ContextResolver.html
>
>

--
| ? + ? = To question
----------------\
    Paul Sandoz
         x38109
+33-4-76188109

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: XSD validation during unmarshalling

Andrew Cole
Thanks for your dedication to the list, Paul.  We have resolved this issue without needing to maintain a map of JAXB classes.  We implemented a ValidationEventCollector, and set this to handle validation events coming from the unmarshaller.  Our ValidationEventCollector throws an unchecked exception (JAXBParserException) which we then handle with ExceptionMapper.  The code is below.

@Provider
public class ValidatingJAXBContextResolver implements ContextResolver<JAXBContext> {
    public JAXBContext getContext(Class<?> type) {
        try {
            return new ValidatingJAXBContext(type);
        } catch (JAXBException e) {
            System.out.println("Caught an exception validation jaxb context");
            return null;
        }
    }
  }

public class ValidatingJAXBContext extends JAXBContext {
    private final JAXBContext jaxbContext;

   
    private static class MyValidationEventCollector extends ValidationEventCollector
    {
        @Override
        public boolean handleEvent(ValidationEvent event) throws RuntimeException
        {
            ValidationEventLocator vel = event.getLocator();
            if (event.getSeverity() == event.ERROR || event.getSeverity() == event.FATAL_ERROR)
            {
                String error = "XML Validation Exception:  " + event.getMessage() + " at row: " + vel.getLineNumber() + " column: " + vel.getColumnNumber();
                throw new JAXBParserException(error); // this is just a simple unchecked exception
                // use ExceptionMapper to do whatever you want with it
            }
            return true;
        }
    }
   
   
    public ValidatingJAXBContext(Class... classesToBeBound) throws JAXBException {
        jaxbContext = JAXBContext.newInstance(classesToBeBound);
    }
   
    public ValidatingJAXBContext(Class[] classesToBeBound, Map<String, Object> properties) throws JAXBException {
        jaxbContext = JAXBContext.newInstance(classesToBeBound, properties);
    }
   
    @Override
    public Unmarshaller createUnmarshaller() throws JAXBException {
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        MyValidationEventCollector vec = new MyValidationEventCollector();
        unmarshaller.setEventHandler( vec );
        return unmarshaller;
    }

   
    @Override
    public Marshaller createMarshaller() throws JAXBException {
        return jaxbContext.createMarshaller();
    }

    @Override
    public Validator createValidator() throws JAXBException {
        return jaxbContext.createValidator();
    }
   
}

On Tue, Jul 22, 2008 at 8:26 AM, Paul Sandoz <[hidden email]> wrote:
Hi Andrew,

Unmarshaller.setValidating is indeed deprecated and you need to set the Schema object to validate against.

In this respect i am unsure how you can create a general validating mechanism unless you keep a map of known JAXB class to Schema instance.

You will have to create the Schema instances from the correspondingly available XSD, more info can be found here [1].

Rather than creating a general validating mechanism it might be better to have a general mechanism you inherit from for specific validating purposes i.e. provides the JAXB context and a set of schema.

Paul.

[1] http://www.java-tips.org/java-ee-tips/java-architecture-for-xml-binding/what-is-new-in-jaxb-2.0.html

Andrew Cole wrote:
Now that Paul is back, I would like to promote this thread again.  Paul-- any help you can provide will be greatly appreciated.

Thanks,
Andrew

On Mon, Jul 7, 2008 at 2:22 PM, Andrew Cole <[hidden email] <mailto:[hidden email]>> wrote:

   While Paul is on vacation, can somebody help illuminate his response
   to my query below?  Trying to follow his instructions, I have
   implemented a ContextResolver as follows:

   @Provider
   public class ValidatingJAXBContextResolver implements
   ContextResolver<JAXBContext> {
          public JAXBContext getContext(Class<?> type) {
                  try {
                          return new ValidatingJAXBContext(type);
                  } catch (JAXBException e) {
                          return null;
                  }
          }
    }

   and a JAXBContext (modeled after the JSONJAXBContext in the jersey
   source) as:

   public class ValidatingJAXBContext extends JAXBContext {
          private final JAXBContext jaxbContext;

          public ValidatingJAXBContext(Class... classesToBeBound)
   throws JAXBException {
                  jaxbContext = JAXBContext.newInstance(classesToBeBound);
          }

      public ValidatingJAXBContext(Class[] classesToBeBound, Map<String,
   Object> properties) throws JAXBException {
          jaxbContext = JAXBContext.newInstance(classesToBeBound,
   properties);
      }

      @Override
      public Unmarshaller createUnmarshaller() throws JAXBException {
          Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
          unmarshaller.setValidating(true);
          return unmarshaller;
      }

      @Override
      public Marshaller createMarshaller() throws JAXBException {
          return jaxbContext.createMarshaller();
      }

      @Override
      public Validator createValidator() throws JAXBException {
          return jaxbContext.createValidator();
      }

   }

   Now, when I hit a method that would require unmarshalling content from
   XML, I receive an exception at my call to setValidating:
   java.lang.UnsupportedOperationException
          at
   com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.setValidating(UnmarshallerImpl.java:483)
          at
   myCode.ValidatingJAXBContext.createUnmarshaller(ValidatingJAXBContext.java:33)
          at
   com.sun.ws.rest.impl.provider.entity.XMLRootElementProvider.readFrom(XMLRootElementProvider.java:58)
          at
   com.sun.ws.rest.spi.container.AbstractContainerRequest.getEntity(AbstractContainerRequest.java:179)
   [stack trace truncated]

   Am I on the right track here?  As I understand it, the call to
   setValidating is deprecated in JAXB 2.0 and I should use setSchema.
   Is this correct?  If so, how can I have my ValidatingJAXBContext class
   create an appropriate javax.xml.validation.Schema object for this
   call, based on the classToBeBound passed in to the constructor?

   On Thu, Jul 3, 2008 at 10:20 PM, Paul Sandoz <[hidden email]
   <mailto:[hidden email]>> wrote:
    >
    > On Jul 4, 2008, at 1:05 AM, Andrew Cole wrote:
    >
    > Hi all
    >
    > I'm using Jersey 0.7 and have a number of methods that accept
   objects unmarshalled from XML via JAXB bindings.  It does not appear
   that the unmarshalling process is validating the XML against the
   schema used to create the JAXB bindings.  For instance, I have a
   pattern restriction on a string element that is not being respected,
   and I can leave out elements that have a minOccurs of 1.  How can I
   configure the unmarshaller to validate against my schema?
    >
    >
    > Currently you need to supply your own JAXBContext that returns a
   validating unmarshaller for unmarshalling the JAXB types that
   require validation.
    > See ContextResolver [1].
    > In this case you would do:
    >   public class MyContextResolver implements
   ContextResolver<JAXBContext> {
    >     JAXBContext getContext(Class<?> type) { ... }
    >   }
    > I plan to make this easier so you can use ContextResolver with an
   Unmarshaller/Marshaller thus you don't have to wrap JAXBContext.
    > Paul.
    > [1]
   https://jsr311.dev.java.net/nonav/releases/0.8/javax/ws/rs/ext/ContextResolver.html



--
| ? + ? = To question
----------------\
  Paul Sandoz
       x38109
+33-4-76188109

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: XSD validation during unmarshalling

Paul Sandoz
Administrator
Hi Andrew,

Great! Glad you managed to resolve it. So in this case you did not
require a schema and i presume are relying on the underlying data-type
validation of JAXB (which provides very loose validation of structure
and data types).

Paul.

Andrew Cole wrote:

> Thanks for your dedication to the list, Paul.  We have resolved this
> issue without needing to maintain a map of JAXB classes.  We implemented
> a ValidationEventCollector, and set this to handle validation events
> coming from the unmarshaller.  Our ValidationEventCollector throws an
> unchecked exception (JAXBParserException) which we then handle with
> ExceptionMapper.  The code is below.
>
> @Provider
> public class ValidatingJAXBContextResolver implements
> ContextResolver<JAXBContext> {
>     public JAXBContext getContext(Class<?> type) {
>         try {
>             return new ValidatingJAXBContext(type);
>         } catch (JAXBException e) {
>             System.out.println("Caught an exception validation jaxb
> context");
>             return null;
>         }
>     }
>   }
>
> public class ValidatingJAXBContext extends JAXBContext {
>     private final JAXBContext jaxbContext;
>
>    
>     private static class MyValidationEventCollector extends
> ValidationEventCollector
>     {
>         @Override
>         public boolean handleEvent(ValidationEvent event) throws
> RuntimeException
>         {
>             ValidationEventLocator vel = event.getLocator();
>             if (event.getSeverity() == event.ERROR ||
> event.getSeverity() == event.FATAL_ERROR)
>             {
>                 String error = "XML Validation Exception:  " +
> event.getMessage() + " at row: " + vel.getLineNumber() + " column: " +
> vel.getColumnNumber();
>                 throw new JAXBParserException(error); // this is just a
> simple unchecked exception
>                 // use ExceptionMapper to do whatever you want with it
>             }
>             return true;
>         }
>     }
>    
>    
>     public ValidatingJAXBContext(Class... classesToBeBound) throws
> JAXBException {
>         jaxbContext = JAXBContext.newInstance(classesToBeBound);
>     }
>    
>     public ValidatingJAXBContext(Class[] classesToBeBound, Map<String,
> Object> properties) throws JAXBException {
>         jaxbContext = JAXBContext.newInstance(classesToBeBound, properties);
>     }
>    
>     @Override
>     public Unmarshaller createUnmarshaller() throws JAXBException {
>         Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
>         MyValidationEventCollector vec = new MyValidationEventCollector();
>         unmarshaller.setEventHandler( vec );
>         return unmarshaller;
>     }
>
>    
>     @Override
>     public Marshaller createMarshaller() throws JAXBException {
>         return jaxbContext.createMarshaller();
>     }
>
>     @Override
>     public Validator createValidator() throws JAXBException {
>         return jaxbContext.createValidator();
>     }
>    
> }
>
> On Tue, Jul 22, 2008 at 8:26 AM, Paul Sandoz <[hidden email]
> <mailto:[hidden email]>> wrote:
>
>     Hi Andrew,
>
>     Unmarshaller.setValidating is indeed deprecated and you need to set
>     the Schema object to validate against.
>
>     In this respect i am unsure how you can create a general validating
>     mechanism unless you keep a map of known JAXB class to Schema instance.
>
>     You will have to create the Schema instances from the
>     correspondingly available XSD, more info can be found here [1].
>
>     Rather than creating a general validating mechanism it might be
>     better to have a general mechanism you inherit from for specific
>     validating purposes i.e. provides the JAXB context and a set of schema.
>
>     Paul.
>
>     [1]
>     http://www.java-tips.org/java-ee-tips/java-architecture-for-xml-binding/what-is-new-in-jaxb-2.0.html
>
>     Andrew Cole wrote:
>
>         Now that Paul is back, I would like to promote this thread
>         again.  Paul-- any help you can provide will be greatly appreciated.
>
>         Thanks,
>         Andrew
>
>         On Mon, Jul 7, 2008 at 2:22 PM, Andrew Cole <[hidden email]
>         <mailto:[hidden email]> <mailto:[hidden email]
>         <mailto:[hidden email]>>> wrote:
>
>            While Paul is on vacation, can somebody help illuminate his
>         response
>            to my query below?  Trying to follow his instructions, I have
>            implemented a ContextResolver as follows:
>
>            @Provider
>            public class ValidatingJAXBContextResolver implements
>            ContextResolver<JAXBContext> {
>                   public JAXBContext getContext(Class<?> type) {
>                           try {
>                                   return new ValidatingJAXBContext(type);
>                           } catch (JAXBException e) {
>                                   return null;
>                           }
>                   }
>             }
>
>            and a JAXBContext (modeled after the JSONJAXBContext in the
>         jersey
>            source) as:
>
>            public class ValidatingJAXBContext extends JAXBContext {
>                   private final JAXBContext jaxbContext;
>
>                   public ValidatingJAXBContext(Class... classesToBeBound)
>            throws JAXBException {
>                           jaxbContext =
>         JAXBContext.newInstance(classesToBeBound);
>                   }
>
>               public ValidatingJAXBContext(Class[] classesToBeBound,
>         Map<String,
>            Object> properties) throws JAXBException {
>                   jaxbContext = JAXBContext.newInstance(classesToBeBound,
>            properties);
>               }
>
>               @Override
>               public Unmarshaller createUnmarshaller() throws
>         JAXBException {
>                   Unmarshaller unmarshaller =
>         jaxbContext.createUnmarshaller();
>                   unmarshaller.setValidating(true);
>                   return unmarshaller;
>               }
>
>               @Override
>               public Marshaller createMarshaller() throws JAXBException {
>                   return jaxbContext.createMarshaller();
>               }
>
>               @Override
>               public Validator createValidator() throws JAXBException {
>                   return jaxbContext.createValidator();
>               }
>
>            }
>
>            Now, when I hit a method that would require unmarshalling
>         content from
>            XML, I receive an exception at my call to setValidating:
>            java.lang.UnsupportedOperationException
>                   at
>          
>          com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.setValidating(UnmarshallerImpl.java:483)
>                   at
>          
>          myCode.ValidatingJAXBContext.createUnmarshaller(ValidatingJAXBContext.java:33)
>                   at
>          
>          com.sun.ws.rest.impl.provider.entity.XMLRootElementProvider.readFrom(XMLRootElementProvider.java:58)
>                   at
>          
>          com.sun.ws.rest.spi.container.AbstractContainerRequest.getEntity(AbstractContainerRequest.java:179)
>            [stack trace truncated]
>
>            Am I on the right track here?  As I understand it, the call to
>            setValidating is deprecated in JAXB 2.0 and I should use
>         setSchema.
>            Is this correct?  If so, how can I have my
>         ValidatingJAXBContext class
>            create an appropriate javax.xml.validation.Schema object for this
>            call, based on the classToBeBound passed in to the constructor?
>
>            On Thu, Jul 3, 2008 at 10:20 PM, Paul Sandoz
>         <[hidden email] <mailto:[hidden email]>
>            <mailto:[hidden email] <mailto:[hidden email]>>> wrote:
>             >
>             > On Jul 4, 2008, at 1:05 AM, Andrew Cole wrote:
>             >
>             > Hi all
>             >
>             > I'm using Jersey 0.7 and have a number of methods that accept
>            objects unmarshalled from XML via JAXB bindings.  It does not
>         appear
>            that the unmarshalling process is validating the XML against the
>            schema used to create the JAXB bindings.  For instance, I have a
>            pattern restriction on a string element that is not being
>         respected,
>            and I can leave out elements that have a minOccurs of 1.  How
>         can I
>            configure the unmarshaller to validate against my schema?
>             >
>             >
>             > Currently you need to supply your own JAXBContext that
>         returns a
>            validating unmarshaller for unmarshalling the JAXB types that
>            require validation.
>             > See ContextResolver [1].
>             > In this case you would do:
>             >   public class MyContextResolver implements
>            ContextResolver<JAXBContext> {
>             >     JAXBContext getContext(Class<?> type) { ... }
>             >   }
>             > I plan to make this easier so you can use ContextResolver
>         with an
>            Unmarshaller/Marshaller thus you don't have to wrap JAXBContext.
>             > Paul.
>             > [1]
>          
>          https://jsr311.dev.java.net/nonav/releases/0.8/javax/ws/rs/ext/ContextResolver.html
>
>
>
>     --
>     | ? + ? = To question
>     ----------------\
>       Paul Sandoz
>            x38109
>     +33-4-76188109
>
>     ---------------------------------------------------------------------
>     To unsubscribe, e-mail: [hidden email]
>     <mailto:[hidden email]>
>     For additional commands, e-mail: [hidden email]
>     <mailto:[hidden email]>
>
>

--
| ? + ? = To question
----------------\
    Paul Sandoz
         x38109
+33-4-76188109

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Loading...