1 2 Previous Next 24 Replies Latest reply on Nov 21, 2008 3:58 AM by Ales Justin

    UnwrapValueUnitTestCase.testCollectionUnwrap failure on comm

    Scott Stark Master

      I set the testFailureIgnore to false since were tyring to get jboss-man to GA, and there is this odd failure showing up when running the mvn test phase, but not under eclipse:

      Caused by: java.lang.IllegalArgumentException: No enum const class org.jboss.test.metatype.values.factory.support.TestEnum.org.jboss.test.metatype.values.factory.support.TestGeneric@be32
       at java.lang.Enum.valueOf(Enum.java:196)
       at org.jboss.reflect.plugins.ValueConvertor.convertValue(ValueConvertor.java:130)
       at org.jboss.reflect.plugins.ValueConvertor.convertValue(ValueConvertor.java:90)
       at org.jboss.reflect.plugins.ValueConvertor.convertValue(ValueConvertor.
      java:75)
       at org.jboss.reflect.plugins.ClassInfoImpl.convertValue(ClassInfoImpl.ja
      va:481)
       at org.jboss.metatype.plugins.values.DefaultMetaValueFactory.convertValue(DefaultMetaValueFactory.java:1029)
       ... 33 more
      


      Something is munging together a class instance toString with the enum class and trying to treat that as an enum string. I'm looking into how.


        • 1. Re: UnwrapValueUnitTestCase.testCollectionUnwrap failure on
          Scott Stark Master

          It looks like whatever the issue is, its random as often the test passes, but when it fails its failing over confusing an enum as another type. In this case it was treated as an Integer:

          Caused by: java.lang.NumberFormatException: For input string: "ONE"
           at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
           at java.lang.Integer.parseInt(Integer.java:447)
           at java.lang.Integer.valueOf(Integer.java:526)
           at java.lang.Integer.decode(Integer.java:919)
           at org.jboss.util.propertyeditor.IntegerEditor.setAsText(IntegerEditor.java:42)
           at org.jboss.reflect.plugins.ValueConvertor.convertValue(ValueConvertor.java:139)
           at org.jboss.reflect.plugins.ValueConvertor.convertValue(ValueConvertor.java:90)
           at org.jboss.reflect.plugins.ValueConvertor.convertValue(ValueConvertor.java:75)
           at org.jboss.reflect.spi.PrimitiveInfo.convertValue(PrimitiveInfo.java:228)
           at org.jboss.metatype.plugins.values.DefaultMetaValueFactory.convertValue(DefaultMetaValueFactory.java:1030)
           ... 33 more
          



          • 2. Re: UnwrapValueUnitTestCase.testCollectionUnwrap failure on
            Ales Justin Master

            You can leave it, and I'll have a look as it's my test.
            But I won't object if you fix it. :-)

            • 3. Re: UnwrapValueUnitTestCase.testCollectionUnwrap failure on
              Scott Stark Master

              The problem is in determining the component type when a java.util.Set generic is passed in. In this case its a Set[TestEnum], but the component type is determined to be java.lang.Integer.

              441 DEBUG [DefaultMetaValueFactory] unwrapCollection, type: ReflectClassInfoImpl@30cb4b{name=java.util.Set}
              441 DEBUG [DefaultMetaValueFactory] unwrapCollection, componentType: java.lang.Integer
              443 DEBUG [DefaultMetaValueFactory] convertValue failure(For input string: "TWO"), value=TWO, value.class: java.lang.String, typeInfo: java.lang.Integer
              


              Just adding a logging statement can change the failure or even fix the problem. Its some issue with reflection on the generic element type that is suspect.


              • 5. Re: UnwrapValueUnitTestCase.testCollectionUnwrap failure on
                Ales Justin Master

                 

                "scott.stark@jboss.org" wrote:
                The problem is in determining the component type when a java.util.Set generic is passed in. In this case its a Set[TestEnum], but the component type is determined to be java.lang.Integer.
                441 DEBUG [DefaultMetaValueFactory] unwrapCollection, type: ReflectClassInfoImpl@30cb4b{name=java.util.Set}
                441 DEBUG [DefaultMetaValueFactory] unwrapCollection, componentType: java.lang.Integer
                443 DEBUG [DefaultMetaValueFactory] convertValue failure(For input string: "TWO"), value=TWO, value.class: java.lang.String, typeInfo: java.lang.Integer
                


                Just adding a logging statement can change the failure or even fix the problem. Its some issue with reflection on the generic element type that is suspect.

                This looks like caching issue.

                See UnwrapValueUnitTestCase::testCollectionUnwrap.
                Before Enums we test Integers.
                Looks like Set.class is mapped to ClassInfo who's component type is
                a leftover from previous Integers testing.

                I'll dig into more.

                • 6. Re: UnwrapValueUnitTestCase.testCollectionUnwrap failure on
                  Ales Justin Master

                   

                  "alesj" wrote:

                  This looks like caching issue.

                  Yup, caching:
                  - https://jira.jboss.org/jira/browse/JBREFLECT-7

                  This is what's actually going on:
                  (code is from WeakTypeCache)

                  1) checkCollection(new HashSet(), getType("Integer", Set.class), i1, i2);

                   protected void put(ParameterizedType type, T result)
                   {
                   Class<?> rawType = (Class<?>) type.getRawType();
                   ClassLoader cl = SecurityActions.getClassLoader(rawType);
                   Map<String, T> classLoaderCache = getClassLoaderCache(cl);
                  
                   synchronized (classLoaderCache)
                   {
                   // TODO JBMICROCONT-131 something better than toString()?
                   classLoaderCache.put(type.toString(), result);
                   }
                   }
                  


                  interface java.util.Set + result are now part of cache

                  2) checkCollection(new HashSet(), getType("Enum", Set.class), one, two, three, one);

                   protected T peek(ParameterizedType type)
                   {
                   Class<?> rawType = (Class<?>) type.getRawType();
                   ClassLoader cl = SecurityActions.getClassLoader(rawType);
                   Map<String, T> classLoaderCache = getClassLoaderCache(cl);
                  
                   synchronized (classLoaderCache)
                   {
                   return classLoaderCache.get(type.toString());
                   }
                   }
                  


                  And you're 'unlucky' that weak value is still cached under "interface java.util.Set".
                  Hence you get integer Set --> Integer component type.

                  So, JBMAN-38 is purely JBREFLECT-7's result.
                  Who's gonna bite into JBREFLECT-7, Adrian? :-)

                  • 7. Re: UnwrapValueUnitTestCase.testCollectionUnwrap failure on
                    Adrian Brock Master

                     

                    "alesj" wrote:

                    So, JBMAN-38 is purely JBREFLECT-7's result.
                    Who's gonna bite into JBREFLECT-7, Adrian? :-)


                    What makes you think JBREFLECT-7 is causing this?

                    The toString() of the parameterized types are clearly different so they
                    shouldn't conflict in the cache.

                    I added some System.out.printlns to DefaultMetaTypeFactory
                    Index: src/main/java/org/jboss/metatype/plugins/types/DefaultMetaTypeFactory.java
                    ===================================================================
                    --- src/main/java/org/jboss/metatype/plugins/types/DefaultMetaTypeFactory.java (revision 81358)
                    +++ src/main/java/org/jboss/metatype/plugins/types/DefaultMetaTypeFactory.java (working copy)
                    @@ -133,10 +133,14 @@
                     {
                     // Generate it
                     result = generate(typeInfo);
                    +
                    +System.out.println(typeInfo + " ==> " + result);
                    
                     // Cache it
                     typeInfo.setAttachment(MetaType.class.getName(), result);
                     }
                    +
                    +System.out.println(typeInfo + " <== " + result);
                    
                     // Return the result
                     return result;
                    


                    And modified the test to just the Set retrieval you point to.
                    The output I get is:
                    0 DEBUG [UnwrapValueUnitTestCase] ==== Starting testCollectionUnwrap ====
                    ReflectClassInfoImpl@3570b0{name=java.lang.Object} ==> MutableCompositeMetaType{java.lang.Object}
                    ReflectClassInfoImpl@3570b0{name=java.lang.Object} <== MutableCompositeMetaType{java.lang.Object}
                    ReflectClassInfoImpl@982589{name=java.util.HashSet} ==> CollectionMetaType{type=java.util.HashSet elementType=MutableCompositeMetaType{java.
                    lang.Object}
                    ReflectClassInfoImpl@982589{name=java.util.HashSet} <== CollectionMetaType{type=java.util.HashSet elementType=MutableCompositeMetaType{java.
                    lang.Object}
                    java.lang.Integer ==> SimpleMetaType:java.lang.Integer
                    java.lang.Integer <== SimpleMetaType:java.lang.Integer
                    ReflectClassInfoImpl@982589{name=java.util.HashSet} <== CollectionMetaType{type=java.util.HashSet elementType=MutableCompositeMetaType{java.
                    lang.Object}
                    java.lang.Integer <== SimpleMetaType:java.lang.Integer
                    ReflectClassInfoImpl@3570b0{name=java.lang.Object} <== MutableCompositeMetaType{java.lang.Object}
                    ReflectClassInfoImpl@a9c09e{name=java.util.Set} ==> CollectionMetaType{type=java.util.Set elementType=MutableCompositeMetaType{java.lang.Obj
                    ect}
                    ReflectClassInfoImpl@a9c09e{name=java.util.Set} <== CollectionMetaType{type=java.util.Set elementType=MutableCompositeMetaType{java.lang.Obj
                    ect}
                    java.lang.Integer <== SimpleMetaType:java.lang.Integer
                    java.lang.Integer <== SimpleMetaType:java.lang.Integer
                    
                    HERE you can see the parameterized type for Set<Integer>
                    
                    ParameterizedClassInfo@a4e743{java.util.Set<java.lang.Integer>} ==> CollectionMetaType{type=java.util.Set elementType=SimpleMetaType:java.la
                    ng.Integer
                    ParameterizedClassInfo@a4e743{java.util.Set<java.lang.Integer>} <== CollectionMetaType{type=java.util.Set elementType=SimpleMetaType:java.la
                    ng.Integer
                    java.lang.Integer <== SimpleMetaType:java.lang.Integer
                    ReflectClassInfoImpl@982589{name=java.util.HashSet} <== CollectionMetaType{type=java.util.HashSet elementType=MutableCompositeMetaType{java.
                    lang.Object}
                    EnumInfoImpl@14c194d{name=org.jboss.test.metatype.values.factory.support.TestEnum} ==> org.jboss.test.metatype.values.factory.support.TestEn
                    um{[ONE, TWO, THREE]}
                    EnumInfoImpl@14c194d{name=org.jboss.test.metatype.values.factory.support.TestEnum} <== org.jboss.test.metatype.values.factory.support.TestEn
                    um{[ONE, TWO, THREE]}
                    EnumInfoImpl@14c194d{name=org.jboss.test.metatype.values.factory.support.TestEnum} <== org.jboss.test.metatype.values.factory.support.TestEn
                    um{[ONE, TWO, THREE]}
                    EnumInfoImpl@14c194d{name=org.jboss.test.metatype.values.factory.support.TestEnum} <== org.jboss.test.metatype.values.factory.support.TestEn
                    um{[ONE, TWO, THREE]}
                    ReflectClassInfoImpl@982589{name=java.util.HashSet} <== CollectionMetaType{type=java.util.HashSet elementType=MutableCompositeMetaType{java.
                    lang.Object}
                    EnumInfoImpl@14c194d{name=org.jboss.test.metatype.values.factory.support.TestEnum} <== org.jboss.test.metatype.values.factory.support.TestEn
                    um{[ONE, TWO, THREE]}
                    EnumInfoImpl@14c194d{name=org.jboss.test.metatype.values.factory.support.TestEnum} <== org.jboss.test.metatype.values.factory.support.TestEn
                    um{[ONE, TWO, THREE]}
                    EnumInfoImpl@14c194d{name=org.jboss.test.metatype.values.factory.support.TestEnum} <== org.jboss.test.metatype.values.factory.support.TestEn
                    um{[ONE, TWO, THREE]}
                    ReflectClassInfoImpl@a9c09e{name=java.util.Set} <== CollectionMetaType{type=java.util.Set elementType=MutableCompositeMetaType{java.lang.Obj
                    ect}
                    EnumInfoImpl@14c194d{name=org.jboss.test.metatype.values.factory.support.TestEnum} <== org.jboss.test.metatype.values.factory.support.TestEn
                    um{[ONE, TWO, THREE]}
                    EnumInfoImpl@14c194d{name=org.jboss.test.metatype.values.factory.support.TestEnum} <== org.jboss.test.metatype.values.factory.support.TestEn
                    um{[ONE, TWO, THREE]}
                    EnumInfoImpl@14c194d{name=org.jboss.test.metatype.values.factory.support.TestEnum} <== org.jboss.test.metatype.values.factory.support.TestEn
                    um{[ONE, TWO, THREE]}
                    EnumInfoImpl@14c194d{name=org.jboss.test.metatype.values.factory.support.TestEnum} <== org.jboss.test.metatype.values.factory.support.TestEn
                    um{[ONE, TWO, THREE]}
                    
                    HERE you can see the parameterized type for Set<TestEnum>
                    
                    ParameterizedClassInfo@1cbfe9d{java.util.Set<org.jboss.test.metatype.values.factory.support.TestEnum>} ==> CollectionMetaType{type=java.util
                    .Set elementType=org.jboss.test.metatype.values.factory.support.TestEnum{[ONE, TWO, THREE]}
                    ParameterizedClassInfo@1cbfe9d{java.util.Set<org.jboss.test.metatype.values.factory.support.TestEnum>} <== CollectionMetaType{type=java.util
                    .Set elementType=org.jboss.test.metatype.values.factory.support.TestEnum{[ONE, TWO, THREE]}
                    EnumInfoImpl@14c194d{name=org.jboss.test.metatype.values.factory.support.TestEnum} <== org.jboss.test.metatype.values.factory.support.TestEn
                    um{[ONE, TWO, THREE]}
                    EnumInfoImpl@14c194d{name=org.jboss.test.metatype.values.factory.support.TestEnum} <== org.jboss.test.metatype.values.factory.support.TestEn
                    um{[ONE, TWO, THREE]}
                    EnumInfoImpl@14c194d{name=org.jboss.test.metatype.values.factory.support.TestEnum} <== org.jboss.test.metatype.values.factory.support.TestEn
                    um{[ONE, TWO, THREE]}
                    88 DEBUG [UnwrapValueUnitTestCase] testCollectionUnwrap took 87ms
                    88 DEBUG [UnwrapValueUnitTestCase] ==== Stopping testCollectionUnwrap ====
                    


                    • 8. Re: UnwrapValueUnitTestCase.testCollectionUnwrap failure on
                      Adrian Brock Master

                       

                      "adrian@jboss.org" wrote:
                      "alesj" wrote:

                      So, JBMAN-38 is purely JBREFLECT-7's result.
                      Who's gonna bite into JBREFLECT-7, Adrian? :-)


                      What makes you think JBREFLECT-7 is causing this?

                      The toString() of the parameterized types are clearly different so they
                      shouldn't conflict in the cache.


                      I agree toString() is not reliable (since it is not documented what format it will have)
                      which is why I raised the FIXME, but it doesn't look to me like it is causing this problem?

                      • 9. Re: UnwrapValueUnitTestCase.testCollectionUnwrap failure on
                        Adrian Brock Master

                         

                        "alesj" wrote:

                        And you're 'unlucky' that weak value is still cached under "interface java.util.Set".
                        Hence you get integer Set --> Integer component type.


                        I don't know that luck comes into it, since AFAIK java requires the
                        ParameterizedType to be held as a strong reference until the testCollectionUnWrap
                        method finishes (that is its scope of definition).

                        Just in case that is not true, I changed the method to ensure that a strong ref is held

                         public void testCollectionUnwrap() throws Exception
                         {
                         Integer i1 = 123;
                         Integer i2 = 123;
                         Type hold = getType("Integer", Set.class);
                         checkCollection(new HashSet<Integer>(), i1, i2);
                         checkCollection(new HashSet<Integer>(), Set.class, i1, i2);
                         checkCollection(new HashSet<Integer>(), hold, i1, i2);
                        
                         TestEnum one = TestEnum.ONE;
                         TestEnum two = TestEnum.TWO;
                         TestEnum three = TestEnum.THREE;
                         checkCollection(new HashSet<TestEnum>(), one, two, three, one);
                         checkCollection(new HashSet<TestEnum>(), Set.class, one, two, three, one);
                         checkCollection(new HashSet<TestEnum>(), getType("Enum", Set.class), one, two, three, one);
                        
                         System.out.println(hold); // We still hold a reference
                         }
                        


                        And I still can't reproduce the problem.

                        • 10. Re: UnwrapValueUnitTestCase.testCollectionUnwrap failure on
                          Ales Justin Master

                           

                          "adrian@jboss.org" wrote:

                          What makes you think JBREFLECT-7 is causing this?

                          Since it has all the symptoms that JBREFLECT-7 might cause. :-)

                          "adrian@jboss.org" wrote:

                          The toString() of the parameterized types are clearly different so they
                          shouldn't conflict in the cache.

                          Yes, I missed this.
                          As I've thought we do toString on raw.

                          But like you say in your fixme,
                          this only shows how it's done in Sun JDK.

                          "adrian@jboss.org" wrote:

                          but it doesn't look to me like it is causing this problem?

                          Dunno what else could.
                          If I was able to reproduce it, things would be a lot easier.


                          • 11. Re: UnwrapValueUnitTestCase.testCollectionUnwrap failure on
                            Ales Justin Master

                             

                            "adrian@jboss.org" wrote:

                            Just in case that is not true, I changed the method to ensure that a strong ref is held
                            ...
                            And I still can't reproduce the problem.

                            Perhaps if Scott does this, he should get exception every time - if PT::toString is really the cause.

                            • 12. Re: UnwrapValueUnitTestCase.testCollectionUnwrap failure on
                              Ales Justin Master

                              What about if we built our own String key?

                              Type type = getType("Integer", Set.class);
                              ParameterizedType pt = ParameterizedType.class.cast(type);
                              System.out.println(pt.getRawType());
                              System.out.println(pt.getOwnerType());
                              System.out.println(Arrays.toString(pt.getActualTypeArguments()));
                              
                              interface java.util.Set
                              null
                              [class java.lang.Integer]
                              


                              • 13. Re: UnwrapValueUnitTestCase.testCollectionUnwrap failure on
                                Adrian Brock Master

                                I think I've found A problem? But I'm still not sure
                                if this is the cause of the problem seen.

                                The issue is that DefaultMetaValueFactory::unwrapCollection() has this

                                 BeanInfo collectionInfo;
                                 // null is not instance of
                                 if (type instanceof ClassInfo)
                                 {
                                 collectionInfo = configuration.getBeanInfo(type);
                                 }
                                


                                Which if you look in AbstractBeanInfoFactory has this caching

                                 public BeanInfo getBeanInfo(ClassAdapter classAdapter, BeanAccessMode accessMode)
                                 {
                                 if (classAdapter == null)
                                 throw new IllegalArgumentException("Null class adapter.");
                                 if (accessMode == null)
                                 accessMode = BeanAccessMode.STANDARD;
                                
                                 synchronized (cache)
                                 {
                                 ClassLoader cl = classAdapter.getClassLoader();
                                 ClassInfo classInfo = classAdapter.getClassInfo();
                                 String className = classInfo.getName();
                                 Map<String, Map<BeanAccessMode, BeanInfo>> map = cache.get(cl);
                                


                                The issue being that for ParameterizedClassInfo, classInfo.getName()
                                effectively maps to getRawType().getName() (actually this is done
                                through the super construction of the DelegateClassInfo).

                                Then the next step in unwrapCollection is to use the ClassInfo of the
                                BeanInfo to get the componentType
                                 ClassInfo classInfo = collectionInfo.getClassInfo();
                                 Collection collection = (Collection)createNewInstance(collectionInfo);
                                
                                 TypeInfo componentType = classInfo.getComponentType();
                                

                                which should be the raw type?

                                Clearly, the caching in AbstractBeanInfoFactory shouldn't be using
                                classInfo.getName() in its caching.

                                Or if it is going to use that, then ParameterizedClassInfo needs to override getName()
                                to return the generic name (but I'm not sure what that would break?).

                                Parameterized types should get their own BeanInfo, e.g.
                                // This is a parameterized type with one Object property "something"
                                public class GenericBean<T>
                                {
                                 private T t;
                                 public T getSomething() { return t; }
                                 public void setSomething(T t) { this.t = t; }
                                }
                                
                                // This is a parameterized type with one **String** property "something"
                                public class StringBean extends GenericBean<String> {}
                                


                                • 14. Re: UnwrapValueUnitTestCase.testCollectionUnwrap failure on
                                  Adrian Brock Master

                                   

                                  "alesj" wrote:
                                  What about if we built our own String key?


                                  The toString() in openjdk looks like this:
                                   public String toString() {
                                   StringBuilder sb = new StringBuilder();
                                  
                                   if (ownerType != null) {
                                   if (ownerType instanceof Class)
                                   sb.append(((Class)ownerType).getName());
                                   else
                                   sb.append(ownerType.toString()); // HERE!
                                  
                                   sb.append(".");
                                  
                                   if (ownerType instanceof ParameterizedTypeImpl) {
                                   // Find simple name of nested type by removing the
                                   // shared prefix with owner.
                                   sb.append(rawType.getName().replace( ((ParameterizedTypeImpl)ownerType).rawType.getName() + "$",
                                   ""));
                                   } else
                                   sb.append(rawType.getName());
                                   } else
                                   sb.append(rawType.getName());
                                  
                                   if (actualTypeArguments != null &&
                                   actualTypeArguments.length > 0) {
                                   sb.append("<");
                                   boolean first = true;
                                   for(Type t: actualTypeArguments) {
                                   if (!first)
                                   sb.append(", ");
                                   if (t instanceof Class)
                                   sb.append(((Class)t).getName());
                                   else
                                   sb.append(t.toString()); // HERE!
                                   first = false;
                                   }
                                   sb.append(">");
                                   }
                                  
                                   return sb.toString();
                                  


                                  But note the the code I've marked HERE! which in turn would also need fixing
                                  if we assume these reflective objects don't have valid toString()s

                                  1 2 Previous Next