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

    UnwrapValueUnitTestCase.testCollectionUnwrap failure on comm

    starksm64

      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
          starksm64

          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
            alesj

            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
              starksm64

              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.


              • 4. Re: UnwrapValueUnitTestCase.testCollectionUnwrap failure on
                starksm64
                • 5. Re: UnwrapValueUnitTestCase.testCollectionUnwrap failure on
                  alesj

                   

                  "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
                    alesj

                     

                    "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

                       

                      "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@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

                           

                          "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
                            alesj

                             

                            "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
                              alesj

                               

                              "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
                                alesj

                                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

                                  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

                                     

                                    "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