[jboss-user] [JBoss Microcontainer Development] - JBREFLECT-5 - Implementing generics in JavassistClassInfo

Kabir Khan do-not-reply at jboss.com
Mon Apr 26 13:44:07 EDT 2010


Kabir Khan [http://community.jboss.org/people/kabir.khan%40jboss.com] replied to the discussion

"JBREFLECT-5 - Implementing generics in JavassistClassInfo"

To view the discussion, visit: http://community.jboss.org/message/539587#539587

--------------------------------------------------------------
After a few false starts I have managed to reproduce the error described in my last post, and while doing so found another problem to do with caching. Both of these problems are related and have to do with difficulties in determining the correct classloader to use for ParamerizedType.

1 - Other problem
> Kabir Khan wrote:
> 
> > alesj wrote:
> > 
> > As all of the stuff in Reflect works this way, why is this here a problem?
> Not really a problem, I just wanted to check if the object equality is required. It seems to work that way normally, so I'll do that for this instead as well.
The problem here is that if I generate some classes in classloader so they don't exist in the main classloader. I generate this set of classes twice in two different classloaders

public class SomeValue{}
 
public class SomeSignature
{
   public java.util.Set<SomeValue> signature
   {
      return null;
   } 
}


I generate the classes twice, now if I do something along the lines of

public void testClasses()
{
 
   ClassInfo infoA = getSignatureMethodReturnTypeForClass(loaderA); //One of the loaders loading the classes
   ClassInfo infoB = getSignatureMethodReturnTypeForClass(loaderB); //Another loader loading the classes
 
   //These all pass
   assertEquals(ClassLoader.getSystemClassLoader(), infoA.getRawType().getClassLoader());
   assertEquals(ClassLoader.getSystemClassLoader(), infoB.getRawType().getClassLoader());
   assertEquals(loaderA, infoA.getActualTypeArguments[0].getClassLoader());
 
   //Fails - loader is loaderA
   assertEquals(loaderB, infoB.getActualTypeArguments[0].getClassLoader());
 
 
 
}
 
 
 
private void getSignatureMethodReturnTypeForClass(ClassLoader loader)
 
{
 
generateClasses(getPoolForLoader(loader));
 
Class clazz = loader.loadClass("SomeSignature");
 
Method m = loader.getMethod("signature");
 
Type t = m.getGenericReturnType();  //instance of java.lang.reflect.ParameterizedType
 
return getTypeInfoFactory().getTypeInfo(t);
 
}
 


The reason this fails is that the parameterized classinfo is cached against the string representation of the name, i.e. "java.lang.String<SomeValue>". This fails with both the introspection and javassist implementations. 


The root of the problem is this in the entry point to both implementations of TypeInfoFactory, and that ParameterizedType has no getClassLoader() method, so it is currently guessed by defaulting to the one for the raw type. The implementations look something like

   public TypeInfo getTypeInfo(Type type)
   {
      if (type == null)
         throw new IllegalArgumentException("Null type");
 
      if (type instanceof ParameterizedType)
         return getParameterizedType((ParameterizedType) type);
      ...
    }
 
 
    public void getParameterizedType(ParameterizedType type)
    {
        //Check cache
        ClassLoader loader = type.getRawType().getClassLoader();  // 1
        TypeInfo cached = checkLoaderCacheForParameterizedType(loader, getName(type)); 
        if (cached != null)
           return true;
 
        //Create parameterized type wrapper
        TypeInfo rawType = getTypeInfo(type.getRawType());
        TypeInfo args = new TypeInfo[type.getActualTypeArguments().length];
        for (int i = 0 ; i < args.length ; i++)
        {
           args[i] = getTypeInfo(type.getActualTypeArguments()[i];
        }
        ClassInfo info = createParameterizedClassInfo(rawType, args);
 
        //Cache the lookup
        cacheParameterizedTypeForLoader(loader, info);
        return info;
    }


So what happens is when we try to get the parameterized type for Set<SomeValue> with loaderA it gets cached, but against the classloader of Set, which is the system classloader. When we try to get it with loaderB, it is found, but from the cache for Set's classloader, i.e. the system classloader. 

So maybe caching should be turned off for parameterized types? I have not yet checked what the implications of this would be, but it would mean that object equality checks if used will not work for parameterized types created this way. Or maybe they should be cached against the context classloader instead?

--------------------------------------------------------------

Reply to this message by going to Community
[http://community.jboss.org/message/539587#539587]

Start a new discussion in JBoss Microcontainer Development at Community
[http://community.jboss.org/choose-container!input.jspa?contentType=1&containerType=14&container=2115]

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/jboss-user/attachments/20100426/52d6e407/attachment.html 


More information about the jboss-user mailing list