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&...]