8 Replies Latest reply on Jul 3, 2009 8:08 AM by thomas.diesler

    JBossXB does not assign schema defined attribute defaults

    thomas.diesler

       

      [tdiesler@tdvaio blueprint]$ mvn -Dtest=BasicRootParserTestCase install
      
      -------------------------------------------------------------------------------
      Test set: org.jboss.test.osgi.blueprint.parser.BasicRootParserTestCase
      -------------------------------------------------------------------------------
      Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 1.001 sec <<< FAILURE!
      testBlueprintDefaultAttributes(org.jboss.test.osgi.blueprint.parser.BasicRootParserTestCase) Time elapsed: 0.935 sec <<< FAILURE!
      java.lang.AssertionError: default-lazy-init: FALSE expected:<false> but was:<null>
       at org.junit.Assert.fail(Assert.java:92)
       at org.junit.Assert.failNotEquals(Assert.java:689)
       at org.junit.Assert.assertEquals(Assert.java:127)
       at org.jboss.test.osgi.blueprint.parser.BasicRootParserTestCase.testBlueprintDefaultAttributes(BasicRootParserTestCase.java:56)
      


      on TBlueprint I have an attribute declaration like this

       @XmlAttribute(name = "default-lazy-init")
       public Boolean isDefaultLazyInit()
       {
       return defaultLazyInit;
       }
      


      which should probably not even be necessary.

      This works with the SchemaBindingParser, which gets the binding annotation from the schema.


        • 1. Re: JBossXB does not assign schema defined attribute default
          aloubyansky

          The problem comes from the XML parser. Since binding is based on Java annotations, we don't parse the XSD and don't know anything about it, even whether it exists.

          So, in this case, XML parser (e.g. xerces in our case) should include default attribute values and make them available through SAX API.

          For that, XSD schema must be resolvable by the XML parser. Which means EntityResolver should know the schema location. And also validation should be enabled.

          • 2. Re: JBossXB does not assign schema defined attribute default
            thomas.diesler

            I think I provide this information here

            http://anonsvn.jboss.org/repos/jbossas/projects/jboss-osgi/trunk/blueprint/impl/src/main/java/org/jboss/osgi/blueprint/parser/SchemaResolverParser.java

             static class BlueprintSchemaResolver extends DefaultSchemaResolver
             {
             private LogService log;
            
             public BlueprintSchemaResolver(BlueprintContext context)
             {
             this.log = context.getLog();
            
             try
             {
             addSchemaLocation(XMLNS_BLUEPRINT, "blueprint.xsd");
             addClassBinding(BlueprintContext.XMLNS_BLUEPRINT, TBlueprint.class);
             }
             catch (RuntimeException rte)
             {
             throw rte;
             }
             catch (Exception ex)
             {
             log.log(LogService.LOG_ERROR, "Cannot create schema resolver", ex);
             }
             }
             }
            


            The DefaultSchemaResolver sais

             /**
             * Uses the JBossEntityResolver.resolveEntity by:
             *
             * 1. Using the nsUri as the systemID
             * 2. Using the schemaLocation as the systemID
             * 3. If that fails, the baseURI is not null, the xsd is located using URL(baseURL, schemaLocation)
             * 4. If the baseURI is null, the xsd is located using URL(schemaLocation)
             */
             public SchemaBinding resolve(String nsURI, String baseURI, String schemaLocation)
            


            but (in my case) it actually generates the schema from a binding class

            schema = JBossXBBuilder.build(bindingClass);
            


            AFAICS, it generates the schema rather than use the one that I provide.

            • 3. Re: JBossXB does not assign schema defined attribute default
              aloubyansky

              The SchemaBinding is generated from the class, yes. But the attribute value should come from the schema during parsing of the XML. I am going to add a testcase for that (tomorrow probably).

              • 4. Re: JBossXB does not assign schema defined attribute default
                aloubyansky

                I've committed the testcase here
                http://anonsvn.jboss.org/repos/common/jbossxb/trunk/src/test/java/org/jboss/test/xb/builder/object/attribute/test/SchemaDefaultAttributeValueUnitTestCase.java
                and the xml and xsd are here
                http://anonsvn.jboss.org/repos/common/jbossxb/trunk/src/test/resources/org/jboss/test/xb/builder/object/attribute/test/

                As mentioned above, the problem is the XML parser cannot resolve the XSD.

                addSchemaLocation(XMLNS_BLUEPRINT, "blueprint.xsd");
                won't help. This will configure XsdBinder to resolve schema to class mapping (i.e. this is binding layer) but it has nothing to do with the XML parser.
                So, here is the testcase I committed
                UnmarshallerFactory unmarshallerFactory = UnmarshallerFactory.newInstance();
                 Unmarshaller unmarshaller = unmarshallerFactory.newUnmarshaller();
                
                 // this is to make the SAX parser parse the XSD as well and include default attribute values in the startElement
                 unmarshaller.setSchemaValidation(true);
                
                 // this is EntityResolver that SAX parser (xerces) will use to resolve XSD location for the XML being parsed
                 JBossEntityResolver xmlResolver = new JBossEntityResolver();
                 // Here we map schema location specified in the XML file to the local schema location,
                 // which is a path relative to the resources directory visible in the classpath.
                 // Note, we have to specify here and XML the complete URL including the protocol part into the schemaLocation.
                 // The reason is that if we specify schemaLocation in XML as just a filename,
                 // the SAX parser will compose its schemaLocation by adding the protocol, baseURI (which will depend on the
                 // environment the code is run in) and the schemaLocation we specified in the XML and then
                 // will pass this new schemaLocation to the resolver.
                 xmlResolver.registerLocalEntity("http://www.hostame.org/SchemaDefaultAttributeValue.xsd", "org/jboss/test/xb/builder/object/attribute/test/SchemaDefaultAttributeValue.xsd");
                 unmarshaller.setEntityResolver(xmlResolver);
                
                 // this is to resolve namespace to class mapping and build the SchemaBinding from the class
                 MultiClassSchemaResolver schemaBindingResolver = new MultiClassSchemaResolver();
                 schemaBindingResolver.mapURIToClass("xb:test:default-attribute", DefaultAttribute.class);
                 // the reason we configured a separate EntityResolver for unmarshaller above instead of
                 // calling schemaBindingResolver.mapSchemaLocation(nsURI, location) is that
                 // entity resolution inside schemaBindingResolver is used only for nsURI to class resolution (by XsdBinder)
                 // and is not related to SAX parser entity resolution and XML validation.
                
                 String xml = findXML("SchemaDefaultAttributeValue.xml");
                 Object result = unmarshaller.unmarshal(xml, schemaBindingResolver);


                XSD
                <xsd:schema
                 targetNamespace="xb:test:default-attribute"
                 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                 elementFormDefault="qualified"
                 attributeFormDefault="unqualified">
                
                 <xsd:element name="default-attribute">
                 <xsd:complexType>
                 <xsd:attribute name="attribute" type="xsd:int" default="123" />
                 </xsd:complexType>
                 </xsd:element>
                </xsd:schema>


                XML
                <default-attribute xmlns="xb:test:default-attribute"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="xb:test:default-attribute http://www.hostame.org/SchemaDefaultAttributeValue.xsd"/>


                I agree, XSD resolution and its configuration is confusing. That's something we could work on and make simpler.

                • 5. Re: JBossXB does not assign schema defined attribute default
                  thomas.diesler

                  I updated to jbossxb-2.0.1.GA

                  It seems that the 'default-lazy-init' attribute does not get bound

                  [tdiesler@tdvaio blueprint]$ cat testsuite/target/test.log | grep default
                  2009-07-03 09:58:10,649 TRACE [org.jboss.xb.builder.JBossXBBuilder:885] Checking property defaultLazyInit for org.jboss.osgi.blueprint.parser.xb.TBlueprint type=java.lang.Boolean
                  2009-07-03 09:58:10,651 TRACE [org.jboss.xb.builder.JBossXBBuilder:885] Checking property defaultDestroyMethod for org.jboss.osgi.blueprint.parser.xb.TBlueprint type=java.lang.String
                  2009-07-03 09:58:10,660 TRACE [org.jboss.xb.builder.JBossXBBuilder:938] Bound attribute default-destroy-method type=org.jboss.osgi.blueprint.parser.xb.TBlueprint property=defaultDestroyMethod propertyType=ReflectClassInfoImpl@a9255c{name=java.lang.String}, normalizeSpace=false
                  2009-07-03 09:58:10,661 TRACE [org.jboss.xb.builder.JBossXBBuilder:885] Checking property defaultAvailability for org.jboss.osgi.blueprint.parser.xb.TBlueprint type=org.jboss.osgi.blueprint.parser.xb.TAvailability
                  2009-07-03 09:58:10,673 TRACE [org.jboss.xb.builder.JBossXBBuilder:938] Bound attribute default-availability type=org.jboss.osgi.blueprint.parser.xb.TBlueprint property=defaultAvailability propertyType=EnumInfoImpl@16d2702{name=org.jboss.osgi.blueprint.parser.xb.TAvailability}, normalizeSpace=false
                  2009-07-03 09:58:10,674 TRACE [org.jboss.xb.builder.JBossXBBuilder:885] Checking property defaultInitMethod for org.jboss.osgi.blueprint.parser.xb.TBlueprint type=java.lang.String
                  2009-07-03 09:58:10,676 TRACE [org.jboss.xb.builder.JBossXBBuilder:938] Bound attribute default-init-method type=org.jboss.osgi.blueprint.parser.xb.TBlueprint property=defaultInitMethod propertyType=ReflectClassInfoImpl@a9255c{name=java.lang.String}, normalizeSpace=false
                  2009-07-03 09:58:10,677 TRACE [org.jboss.xb.builder.JBossXBBuilder:885] Checking property defaultTimeout for org.jboss.osgi.blueprint.parser.xb.TBlueprint type=java.math.BigInteger
                  2009-07-03 09:58:10,679 TRACE [org.jboss.xb.builder.JBossXBBuilder:938] Bound attribute default-timeout type=org.jboss.osgi.blueprint.parser.xb.TBlueprint property=defaultTimeout propertyType=ReflectClassInfoImpl@659db7{name=java.math.BigInteger}, normalizeSpace=false
                  2009-07-03 09:58:10,756 TRACE [org.jboss.xb.binding.sunday.unmarshalling.AttributesHandler:73] Attribute is not bound: element owner {http://www.osgi.org/xmlns/blueprint/v1.0.0}blueprint, attribute default-lazy-init
                  2009-07-03 09:58:10,769 TRACE [org.jboss.xb.builder.runtime.PropertyHandler:94] QName default-timeout handle java.math.BigInteger@edf730 to org.jboss.osgi.blueprint.parser.xb.TBlueprint@16749745 property=defaultTimeout
                  2009-07-03 09:58:10,770 TRACE [org.jboss.xb.builder.runtime.PropertyHandler:94] QName default-availability handle org.jboss.osgi.blueprint.parser.xb.TAvailability@17b0998 to org.jboss.osgi.blueprint.parser.xb.TBlueprint@16749745 property=defaultAvailability
                  2009-07-03 09:58:10,874 TRACE [org.jboss.xb.binding.sunday.unmarshalling.AttributesHandler:73] Attribute is not bound: element owner {http://www.osgi.org/xmlns/blueprint/v1.0.0}blueprint, attribute default-lazy-init
                  2009-07-03 09:58:10,874 TRACE [org.jboss.xb.builder.runtime.PropertyHandler:94] QName default-timeout handle java.math.BigInteger@faa550 to org.jboss.osgi.blueprint.parser.xb.TBlueprint@24864323 property=defaultTimeout
                  2009-07-03 09:58:10,875 TRACE [org.jboss.xb.builder.runtime.PropertyHandler:94] QName default-availability handle org.jboss.osgi.blueprint.parser.xb.TAvailability@17b0998 to org.jboss.osgi.blueprint.parser.xb.TBlueprint@24864323 property=defaultAvailability
                  


                   @XmlAttribute
                   public Boolean isDefaultLazyInit()
                   {
                   return defaultLazyInit;
                   }
                  


                  I also tried

                  @XmlAttribute(name = "default-lazy-init")
                  @XmlAttribute(name = "default-lazy-init", namespace = BlueprintContext.XMLNS_BLUEPRINT)
                  


                  • 6. Re: JBossXB does not assign schema defined attribute default
                    aloubyansky

                    The attribute shouldn't be bound into the blueprint namespace of course.

                    The issue is actually with jboss-reflect. Apparently, propertyInfo.getUnderlyingAnnotation(annotationType) doesn't work for 'is'-methods (i.e. it returns null even if the method is annotated). If you move @XmlAttribute to setDefaultLazyInit(...) it'll work.

                    • 7. Re: JBossXB does not assign schema defined attribute default
                      alesj

                       

                      "alex.loubyansky@jboss.com" wrote:

                      The issue is actually with jboss-reflect. Apparently, propertyInfo.getUnderlyingAnnotation(annotationType) doesn't work for 'is'-methods (i.e. it returns null even if the method is annotated).

                      Nope, not a Reflect issue.

                      It's by the spec, that only primitive boolean' getter should be isX,
                      where as in this case - with Boolean - it should be getX.
                      public class AbstractBeanInfoFactory implements BeanInfoFactory
                      {
                       /** The cache */
                       protected Map<ClassLoader, Map<ClassInfo, Map<BeanAccessMode, BeanInfo>>> cache = new WeakHashMap<ClassLoader, Map<ClassInfo, Map<BeanAccessMode, BeanInfo>>>();
                      
                       protected static boolean isGetter(MethodInfo minfo)
                       {
                       String name = minfo.getName();
                       TypeInfo returnType = minfo.getReturnType();
                       TypeInfo[] parameters = minfo.getParameterTypes();
                       if ((name.length() > 3 && name.startsWith("get")) || (name.length() > 2 && name.startsWith("is")))
                       {
                       // isBoolean() is not a getter for java.lang.Boolean
                       if (name.startsWith("is") && PrimitiveInfo.BOOLEAN.equals(returnType) == false)
                       return false;
                       if (parameters.length == 0 && PrimitiveInfo.VOID.equals(returnType) == false)
                       return true;
                       }
                       return false;
                       }
                      


                      • 8. Re: JBossXB does not assign schema defined attribute default
                        thomas.diesler

                        This works

                         @XmlAttribute
                         public Boolean getDefaultLazyInit()
                        


                        many thanks ;-)

                        Ales, you might want to issue a warning with respect to

                         @XmlAttribute
                         public Boolean isFoo()