13 Replies Latest reply on Feb 11, 2010 4:48 AM by aloubyansky

    Using generics info in CollectionPropertyHandler

    alesj

      Checking how KernelDeployment handles BeanMetaDataFactorys I came with the following issue:
      - http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4191432#4191432

      I guess CollectionPropertyHandler could include this check

       if (child != null)
       {
       TypeInfo typeInfo = propertyInfo.getType();
       if (typeInfo instanceof ClassInfo)
       {
       ClassInfo classInfo = (ClassInfo)typeInfo;
       TypeInfo componentType = classInfo.getComponentType();
       if (componentType != null)
       {
       TypeInfoFactory tif = componentType.getTypeInfoFactory();
       TypeInfo childTypeInfo = tif.getTypeInfo(child.getClass());
       if (componentType.isAssignableFrom(childTypeInfo) == false)
       throw new IllegalArgumentException("Illegal child type");
       }
       }
       }
      

      probably in a bit more optimized way - not checking for component type every time.

        • 1. Re: Using generics info in CollectionPropertyHandler
          aloubyansky
          • 2. Re: Using generics info in CollectionPropertyHandler
            alesj

            I've added TypeInfo::isInstance(Object) to JBoss Reflect,
            so check if it is already available when you implement this:

            if (componentType != null)
             {
             TypeInfoFactory tif = componentType.getTypeInfoFactory();
             TypeInfo childTypeInfo = tif.getTypeInfo(child.getClass());
             if (componentType.isAssignableFrom(childTypeInfo) == false)
             throw new IllegalArgumentException("Illegal child type");
             }
            

            vs.
            if (componentType != null && componentType.isInstance(child) == false)
             {
             throw new IllegalArgumentException("Illegal child type");
             }
            


            • 3. Re: Using generics info in CollectionPropertyHandler
              alesj

              I'm getting this exception:

              testRepeatedElements(org.jboss.test.xml.RepeatedElementsUnitTestCase) Time elapsed: 0.546 sec <<< ERROR!
              org.jboss.xb.binding.JBossXBException: Failed to parse source: file:/C:/projects/jbossxb/target/test-classes/org/jboss/test/xml/RepeatedElementsUnitTestCase_testRepeatedElements.xml@5,11
               at org.jboss.xb.binding.parser.sax.SaxJBossXBParser.parse(SaxJBossXBParser.java:177)
               at org.jboss.xb.binding.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:119)
               at org.jboss.test.xml.JBossXBTestDelegate.unmarshal(JBossXBTestDelegate.java:146)
               at org.jboss.test.xml.AbstractJBossXBTest.unmarshal(AbstractJBossXBTest.java:227)
               at org.jboss.test.xml.AbstractJBossXBTest.unmarshal(AbstractJBossXBTest.java:193)
               at org.jboss.test.xml.RepeatedElementsUnitTestCase.testRepeatedElements(RepeatedElementsUnitTestCase.java:46)
               at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
               at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
               at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
               at java.lang.reflect.Method.invoke(Method.java:585)
               at junit.framework.TestCase.runTest(TestCase.java:168)
               at junit.framework.TestCase.runBare(TestCase.java:134)
               at junit.framework.TestResult$1.protect(TestResult.java:110)
               at junit.framework.TestResult.runProtected(TestResult.java:128)
               at junit.framework.TestResult.run(TestResult.java:113)
               at junit.framework.TestCase.run(TestCase.java:124)
               at junit.framework.TestSuite.runTest(TestSuite.java:232)
               at junit.framework.TestSuite.run(TestSuite.java:227)
               at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:81)
               at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
               at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
               at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:165)
               at org.apache.maven.surefire.Surefire.run(Surefire.java:107)
               at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
               at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
               at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
               at java.lang.reflect.Method.invoke(Method.java:585)
               at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:289)
               at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:993)
              Caused by: org.jboss.xb.binding.JBossXBRuntimeException: Failed to start {http://www.jboss.org/test/xml/repeatedElements}child: the element is not repeatable, repeatable parent expected to be a model group but got element {http://www.jboss.org/test/xml/repeatedElements}top
               at org.jboss.xb.binding.sunday.unmarshalling.SundayContentHandler.endRepeatableParent(SundayContentHandler.java:703)
               at org.jboss.xb.binding.sunday.unmarshalling.SundayContentHandler.startElement(SundayContentHandler.java:341)
               at org.jboss.xb.binding.parser.sax.SaxJBossXBParser$DelegatingContentHandler.startElement(SaxJBossXBParser.java:401)
               at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown Source)
               at org.apache.xerces.xinclude.XIncludeHandler.startElement(Unknown Source)
               at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
               at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
               at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
               at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
               at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
               at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
               at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
               at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
               at org.jboss.xb.binding.parser.sax.SaxJBossXBParser.parse(SaxJBossXBParser.java:173)
               ... 28 more
              
              

              After reverting my changes it's still there.

              • 4. Re: Using generics info in CollectionPropertyHandler
                aloubyansky

                Yes, it's a known issue. Not your fault.

                • 5. Re: Using generics info in CollectionPropertyHandler
                  alesj

                  I'm having problems creating Map test case,
                  where it would fail when key or value are not instance of.

                  I have this 'metadata' class:

                  @XmlRootElement
                  @JBossXmlSchema(namespace="ns", elementFormDefault=XmlNsForm.QUALIFIED)
                  public class RootWrongKey
                  {
                   private Map<KeyIface, ValueIface> tester;
                  
                   public Map<KeyIface, ValueIface> getTester()
                   {
                   return tester;
                   }
                  
                   @JBossXmlMapKeyElement(name = "key")
                   @JBossXmlMapValueElement(name = "value")
                   public void setTester(Map<KeyIface, ValueIface> tester)
                   {
                   this.tester = tester;
                   }
                  }
                  

                  where KeyIface and ValueIface are empty interfaces.

                  I'm trying to find where I can assign actual (but wrong) type, but w/o success.
                  I'm then getting this exception:
                  java.lang.IllegalArgumentException: No such property for bean org.jboss.test.xb.builder.object.type.map.support.KeyIface available []
                   at org.jboss.beans.info.plugins.AbstractBeanInfo.getProperty(AbstractBeanInfo.java:147)
                   at org.jboss.xb.builder.JBossXBNoSchemaBuilder.generateType(JBossXBNoSchemaBuilder.java:1127)
                   at org.jboss.xb.builder.JBossXBNoSchemaBuilder.generateBean(JBossXBNoSchemaBuilder.java:731)
                   at org.jboss.xb.builder.JBossXBNoSchemaBuilder.generateBean(JBossXBNoSchemaBuilder.java:719)
                   at org.jboss.xb.builder.JBossXBNoSchemaBuilder.generateTypeBinding(JBossXBNoSchemaBuilder.java:475)
                   at org.jboss.xb.builder.JBossXBNoSchemaBuilder.resolveTypeBinding(JBossXBNoSchemaBuilder.java:434)
                   at org.jboss.xb.builder.JBossXBNoSchemaBuilder.bindMapProperty(JBossXBNoSchemaBuilder.java:2182)
                   at org.jboss.xb.builder.JBossXBNoSchemaBuilder.bindProperty(JBossXBNoSchemaBuilder.java:1778)
                   at org.jboss.xb.builder.JBossXBNoSchemaBuilder.generateType(JBossXBNoSchemaBuilder.java:1128)
                   at org.jboss.xb.builder.JBossXBNoSchemaBuilder.generateBean(JBossXBNoSchemaBuilder.java:731)
                   at org.jboss.xb.builder.JBossXBNoSchemaBuilder.generateBean(JBossXBNoSchemaBuilder.java:719)
                   at org.jboss.xb.builder.JBossXBNoSchemaBuilder.generateTypeBinding(JBossXBNoSchemaBuilder.java:475)
                   at org.jboss.xb.builder.JBossXBNoSchemaBuilder.resolveTypeBinding(JBossXBNoSchemaBuilder.java:434)
                   at org.jboss.xb.builder.JBossXBNoSchemaBuilder.createElementBinding(JBossXBNoSchemaBuilder.java:313)
                   at org.jboss.xb.builder.JBossXBNoSchemaBuilder.createRootElementBinding(JBossXBNoSchemaBuilder.java:293)
                   at org.jboss.xb.builder.JBossXBNoSchemaBuilder.createRootElements(JBossXBNoSchemaBuilder.java:273)
                   at org.jboss.xb.builder.JBossXBNoSchemaBuilder.build(JBossXBNoSchemaBuilder.java:197)
                   at org.jboss.xb.builder.JBossXBBuilder.build(JBossXBBuilder.java:118)
                   at org.jboss.test.xb.builder.AbstractBuilderTest.unmarshalObject(AbstractBuilderTest.java:125)
                   at org.jboss.test.xb.builder.AbstractBuilderTest.unmarshalObject(AbstractBuilderTest.java:172)
                   at org.jboss.test.xb.builder.object.type.map.test.KeyValueTypeUnitTestCase.testFailure(KeyValueTypeUnitTestCase.java:68)
                   at org.jboss.test.xb.builder.object.type.map.test.KeyValueTypeUnitTestCase.testWrongKey(KeyValueTypeUnitTestCase.java:50)
                  


                  Any hint on how to produce such failing test? ;-)

                  ps: I managed to do it for Collection. :-)

                  • 6. Re: Using generics info in CollectionPropertyHandler
                    alesj

                     

                    "alesj" wrote:

                    I'm trying to find where I can assign actual (but wrong) type, but w/o success.

                    This is what I did for collection:
                     @XmlElements
                     ({
                     @XmlElement(name="iface", type=SomeImpl.class),
                     @XmlElement(name="impl", type=WrongImpl.class)
                     })
                     @XmlAnyElement
                     public void setIface(List<SomeInterface> iface)
                     {
                     this.iface = iface;
                     }
                    

                    where WrongImpl is not SomeInterface instance.

                    • 7. Re: Using generics info in CollectionPropertyHandler
                      alesj

                      I've committed the code as all previous tests + few new ones pass.
                      It's only KeyValueTypeUnitTestCase that doesn't test things properly.
                      I'll look some more tomorrow on how to make it legally fail. :-)

                      • 8. Re: Using generics info in CollectionPropertyHandler
                        aloubyansky

                        Binding options for maps are not as sophisticated. Which is why this bug is not possible for maps :P
                        I mean:
                        - there is no support for multiple different names for key and value elements/attributes
                        - the Java types for the key and value are determined by the Map type arguments or key and value properties in the entry class. Which is a very weak support.

                        So, you can open Jira issues to enhance support in this area. If you do, please, specify how critical this is. So I can prioritize. Thanks.

                        • 9. Re: Using generics info in CollectionPropertyHandler
                          alesj

                           

                          "alex.loubyansky@jboss.com" wrote:

                          So, you can open Jira issues to enhance support in this area.

                          Not really. :-)
                          As all this Map stuff was a mystery for me from the beginning -
                          see my MC attempts at AbstractMapMetaData. ;-)

                          "alex.loubyansky@jboss.com" wrote:

                          If you do, please, specify how critical this is. So I can prioritize. Thanks.

                          Not really critical, it's just an enhancement (hence feature),
                          to prevent future metadata developers from wildcard-ing wrong types.
                          e.g. throwing exception at parse time, rather than at usage time

                          • 10. Re: Using generics info in CollectionPropertyHandler
                            aloubyansky

                            Now that I'm profiling I see the componentType.convertValue(child) is taking quite a lot of time. Looking at the impl http://fisheye.jboss.org/browse/~raw,r=98934/JBossAS/projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/plugins/ValueConvertor.java it doesn't seem to be useful here.

                            Note, string normalization and property replacement is done by XB anyway. I want to remove it.

                            Or what am I missing?

                            Thanks.

                            • 12. Re: Using generics info in CollectionPropertyHandler
                              alesj
                              Now that I'm profiling I see the componentType.convertValue(child) is taking quite a lot of time. Looking at the impl http://fisheye.jboss.org/browse/~raw,r=98934/JBossAS/projects/jboss-reflect/trunk/src/main/java/org/jboss/reflect/plugins/ValueConvertor.java it doesn't seem to be useful here.

                              Note, string normalization and property replacement is done by XB anyway. I want to remove it.

                              Or what am I missing?

                              Yeah, it could be that this conversion is not needed.

                              I didn't look too much into details when I dropped it in there, sorry.

                               

                              The goal of this change was to check the child type, which was missing before.

                              Leaving that check and removing the convert should be fine then.

                              • 13. Re: Using generics info in CollectionPropertyHandler
                                aloubyansky
                                Thanks. Removed convertValue() https://jira.jboss.org/jira/browse/JBXB-237