1 2 Previous Next 17 Replies Latest reply on Mar 5, 2008 8:00 AM by aloubyansky

    How to force strict validation?

    rob.stryker

      I've been trying this out for a while... no success.

      Schema:

      <xsd:schema xmlns:jbxb="http://www.jboss.org/xml/ns/jbxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <xsd:element name="garbageRoot" type="root-type"/>
      <xsd:complexType name="root-type">
      <xsd:annotation>
      <xsd:appinfo>
      <jbxb:class impl="garbage.XbGarbageRoot"/>
      </xsd:appinfo>
      </xsd:annotation>
      <xsd:attribute name="name" type="xsd:string" use="required" />
      </xsd:complexType>
      </xsd:schema>


      XbGarbageRoot (POJO):

      public class XbGarbageRoot {
      private String name;
      public XbGarbageRoot() {
      }
      public String getName() {
      return name;
      }
      public void setName(String name) {
      this.name = name;
      }
      }

      Test case:

      public class ParseTest extends TestCase {
      private static final String SCHEMA = "/home/rob/apps/eclipse/workspaces/work/garbage/src/schema.xsd";
      private static final String DATA = "/home/rob/apps/eclipse/workspaces/work/garbage/data/test.xml";
      public void testABC() {
      try {
      File f = new File(SCHEMA);
      InputStream stream = new FileInputStream(f);
      SchemaBinding binding = XsdBinder.bind(stream, "UTF-8", null);
      stream.close();
      Unmarshaller unmarshaller = UnmarshallerFactory.newInstance().newUnmarshaller();
      binding.setStrictSchema(true);

      FileInputStream dataStream = new FileInputStream(new File(DATA));
      Object xmlObject = unmarshaller.unmarshal(dataStream, binding);
      System.out.println("object is " + xmlObject);
      } catch( Exception e ) {
      // GOOD! I want XB to fail!
      return;
      }
      fail("data file should not have validated!");
      }
      }

      Clearly, i'm setting that it should use a strict schema... but it's not throwing an exception. Any ideas?

        • 1. Re: How to force strict validation?
          aloubyansky

          Strict means that every XML component must be represented in the Java model. I don't see why your test should fail.

          • 2. Re: How to force strict validation?
            aloubyansky

            I meant, I don't see why there should be an exception as you expect.

            • 3. Re: How to force strict validation?
              rob.stryker

              I'm sorry, Alexey. I forgot the most important part:

              <?xml version="1.0" encoding="UTF-8"?>
              
              <!-- Should Fail to validate -->
              <garbageRoot>
              </garbageRoot>
              


              That's the data file I'm reading which is clearly missing the REQUIRED attribute "name".

              <xsd:attribute name="name" type="xsd:string" use="required" />
              


              So this *should* fail, yes? It's not failing. =/

              • 4. Re: How to force strict validation?
                rob.stryker

                The version I'm using in JBoss Tools / JBDS is "jbossxb-1.0.1.TEST.jar", which was found somewhere in our repository (internal?) but has been used in the tooling for a while. Should I be using a newer version?

                • 5. Re: How to force strict validation?
                  rob.stryker

                  Ok clearly some of my text didn't post. Let me try that again with obvious changes

                  [garbageRoot]
                  [/garbageRoot]

                  • 6. Re: How to force strict validation?
                    aloubyansky

                    I think, you should use [ code ] [ /code ] tags for XML.

                    This is not the strictness that is supposed to be enforced by strictSchema.
                    It's a bit confusing. This is XML validation issue. And is supposed to be the responsibility of the XML parser. Although, XB validates model groups (order of elements) to some extent.

                    StrictSchema would affect unmarshalling if for example XbGarbageRoot didn't have name property and the name attribute was present in the XML.

                    • 7. Re: How to force strict validation?
                      rob.stryker

                      So is there any part of jboss xb which *can* validate as such and fail when a required attribute is *not* present?

                      • 8. Re: How to force strict validation?
                        aloubyansky

                        You should be able to configure the underlying xml parser to validate the xml. There are methods in the Unmarshaller to do that: setValidation() and setFeature(). In addition you should make sure that the XML schema can be resolved by the xml parser, so it knows what to validate against.

                        • 9. Re: How to force strict validation?
                          aloubyansky

                          You may need to configure EntityResolver for that or set your own.

                          • 10. Re: How to force strict validation?

                             

                            "rob.stryker@jboss.com" wrote:
                            So is there any part of jboss xb which *can* validate as such and fail when a required attribute is *not* present?


                            It's not really the job of xml binding to validate the schema/dtd.
                            e.g. compare the JAXB spec.

                            The binding framework has been revised significantly since JAXB 1.0.
                            Significant changes include:
                            ...
                            • unmarshal/marshal time validation deferring to JAXP 1.3 validation.


                            If you want validation, configure the xml parser to do it (which are options
                            on the unmarshaller).

                            Example from the deployers:
                            http://viewvc.jboss.org/cgi-bin/viewvc.cgi/jbossas/projects/microcontainer/trunk/deployers-vfs-spi/src/main/org/jboss/deployers/vfs/spi/deployer/SchemaResolverDeployer.java?revision=69994&view=markup

                            The JAXP parser needs to be able to resolve the schema document
                            to actually do the validation as Alex says. :-)

                            • 11. Re: How to force strict validation?
                              rob.stryker

                              Thanks for the replies:

                              Just setting validation and schema validation to true did not accomplish what I needed it to do. I still was unable to access the parser to set the properties needed. I ended up cloning UnmarshallerImpl and making the getParser() method public (rather than package private) to do what I needed it to.

                              public class ParseTest extends TestCase {
                               private static final String SCHEMA = "/home/rob/apps/eclipse/workspaces/work/garbage/src/schema.xsd";
                               private static final String DATA = "/home/rob/apps/eclipse/workspaces/work/garbage/data/test.xml";
                               public void testABC() {
                               try {
                               File f = new File(SCHEMA);
                               InputStream stream = new FileInputStream(f);
                               SchemaBinding binding = XsdBinder.bind(stream, "UTF-8", (String)null);
                               stream.close();
                               binding.setStrictSchema(true);
                               UnmarshallerImpl unmarshaller = new UnmarshallerImpl();
                               String schemaLocation = new File("/home/rob/apps/eclipse/workspaces/work/garbage/src/schema.xsd").toURI().toURL().toExternalForm();
                               unmarshaller.setValidation(true);
                               unmarshaller.getParser().setFeature("http://apache.org/xml/features/validation/schema", true);
                               unmarshaller.getParser().setProperty("http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation",
                               schemaLocation);
                               FileInputStream dataStream = new FileInputStream(new File(DATA));
                               Object xmlObject = unmarshaller.unmarshal(dataStream, binding);
                               System.out.println("object is " + xmlObject);
                               } catch( Exception e ) {
                               // GOOD! I want XB to fail!
                               return;
                               }
                               fail("data file should not have validated!");
                               }
                              }
                              



                              Now I'm just looking via APIs to find a similar way to enforce strict validation when writing / marshalling the files as well ;)

                              Again, thanks for the help.

                              • 12. Re: How to force strict validation?
                                rob.stryker

                                Ok... well... for writing a file, it's obvious to me that JBoss XB cannot validate the object conforms to schema until either a) its done marshalling the object, or b) doing it while serializing.

                                I'm currently using XercesXSMarshaller to serialize my object, and after tracing through, it doesn't seem to check any data structure at all to see if any required attributes are missing.

                                I notice that around line 492 in XercesXSMarshaller, it gets a list of attributes that can be there, but after browsing that data structure in eclipse's debugger, I don't see any reference to whether that attribute is optional or required.

                                if I were able to find which data structure in xerces holds that critical information, I could provide either a patch or a new class (ValidatingXercesXSMarshaller?) that would be able to validate while marshalling the object (or throw an XB Exception if it were to fail validation.)

                                Is this reasonable? I think it seems like a good idea to have a marshaller that can validate while marshalling or throw an exception upon failure.

                                Otherwise, I'd most likely need to force my GenericObjectModelProvider implementation do the validation itself inside the getAttributeValue(etc) method, which would then need to be manually changed if the schema were to change.

                                Thoughts?

                                • 13. Re: How to force strict validation?
                                  aloubyansky

                                  W/o changing APIs you could do something like this:

                                  final String xsd =
                                   "<xsd:schema" +
                                   " xmlns:jbxb='http://www.jboss.org/xml/ns/jbxb'" +
                                   " xmlns:xsd='http://www.w3.org/2001/XMLSchema'>" +
                                   " <xsd:element name='root' type='root-type'/>" +
                                   " <xsd:complexType name='root-type'>" +
                                   " <xsd:annotation>" +
                                   " <xsd:appinfo>" +
                                   " <jbxb:class impl='" + E.class.getName() + "'/>" +
                                   " </xsd:appinfo>" +
                                   " </xsd:annotation>" +
                                   " <xsd:attribute name='unqualified' type='xsd:string' use='required'/>" +
                                   " </xsd:complexType>" +
                                   "</xsd:schema>";
                                  
                                   String xml = "<root xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:noNamespaceSchemaLocation='testns'/>";
                                  
                                   org.xml.sax.EntityResolver resolver = new org.xml.sax.EntityResolver()
                                   {
                                   public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException
                                   {
                                   if(systemId != null && systemId.endsWith("testns"))
                                   return new org.xml.sax.InputSource(new StringReader(xsd));
                                   return null;
                                   }
                                   };
                                  
                                  /*
                                   Validator.assertValidXml(xml, new org.xml.sax.EntityResolver()
                                   {
                                   public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException
                                   {
                                   if(systemId != null && systemId.endsWith("testns"))
                                   return new org.xml.sax.InputSource(new StringReader(xsd));
                                   return null;
                                   }
                                   });
                                  */
                                  
                                   SchemaBinding schema = XsdBinder.bind(new StringReader(xsd), null);
                                   Unmarshaller unmarshaller = UnmarshallerFactory.newInstance().newUnmarshaller();
                                   unmarshaller.setEntityResolver(resolver);
                                   unmarshaller.setSchemaValidation(true);
                                  
                                   Object o = unmarshaller.unmarshal(new StringReader(xml), schema);
                                   assertTrue(o instanceof E);


                                  This will throw the exception you expect. The difference is that I had to add noNamespaceSchemaLocation into the xml instead of setting it on the parser.
                                  It might still be useful to expose setProperty() or the parser itself though.

                                  • 14. Re: How to force strict validation?
                                    aloubyansky

                                    Later XB versions should check the presence of required attributes during marshalling. Xerces-based marshaller is deprecated. org.jboss.xb.binding.sunday.marshalling.MarshallerImpl is the recommended one. It's based on SchemaBinding.

                                    1 2 Previous Next