JBoss development,
A new message was posted in the thread "ScopedClassPoolRepositoryImpl and default
ClassPool":
http://community.jboss.org/message/524465#524465
Author : Flavia Rainone
Profile :
http://community.jboss.org/people/flavia.rainone@jboss.com
Message:
--------------------------------------------------------------
While trying to fix the JBoss AOP + AS tests with the new jboss-classpool project, I
bumped into a
https://jira.jboss.org/jira/browse/JBREFLECT-94 involving
ScopedClassPoolRepositoryImpl and DefaultClassPool.
Our factories were using DefaultClassPool to represent null class loaders so that
bootstrap classes could be loaded without duplicates. This turned out to be a problem
because we were seeing duplicates of JBoss normal classes. Take a look at this example:
-> BaseClassLoader vfsfile:xxx/server/all/conf/jboss-service.xml belongs to
DefaultDomain.
When this ClassLoader is requested to load class
org.jboss.jms.client.container.StateCreationAspect, it will delegate to DefaultDomain,
which will in turn find the original BaseClassLoader as a candidate to load that class.
That BaseClassLoader loads the class and the result is returned.
When this example is ported to ClassPool-level, we get a CNFException. The reason for this
is that the BaseClassPool vfsfile:xxx/server/all/conf/jboss-service.xml has a parent that
can find the resource that contains the requested class:
public class TranslatableClassLoaderIsLocalResourcePlugin extends
AbstractIsLocalResourcePlugin
{
public boolean isMyResource(String resourceName)
{
ClassLoader loader = getPool().getClassLoader();
if (loader instanceof Translatable == false)
{
throw new IllegalStateException("ClassLoader of pool " + getPool() +
" is not instance of Translatable " + loader);
}
URL url =
((Translatable)getPool().getClassLoader()).getResourceLocally(resourceName);
if (url == null)
{
return false;
}
RETURNS TRUE -----> if (isSameInParent(resourceName, url))
{
return false;
}
return true;
}
}
This is isSameInParent implementation:
protected boolean isSameInParent(String classResourceName, URL foundURL)
{
ClassPool parent = pool.getParent();
if (parent != null)
{
ClassLoader parentLoader = parent.getClassLoader();
URL parentURL = parentLoader.getResource(classResourceName);
if (parentURL == null)
{
return false;
}
URI parentURI = URI.create(parentURL.toString());
URI foundURI = URI.create(foundURL.toString());
if (parentURI.equals(foundURI))
{
return true;
}
}
return false;
}
And ClassPool.getClassLoader implementation:
public ClassLoader getClassLoader()
{
return getContextClassLoader();
}
In the given example, getClassLoader will return the BaseClassLoader for AOP module, which
can of course find the requested resource, even though it shouldn't.
Another problem I had is that ScopedClassPoolRepositoryImpl edits the classpath of the
DefaultClassPool:
private ScopedClassPoolRepositoryImpl {
classpool = ClassPool.getDefault();
// FIXME This doesn't look correct
ClassLoader cl = Thread.currentThread().getContextClassLoader();
classpool.insertClassPath(new LoaderClassPath(cl));
}
This is similar to the problem explained above, and makes this class pool capable of
loading classes that other classpools should be responsible to load. As a result, we get
duplicates of the same CtClass. Its FIXME tells me that this was already spotted before as
a possible bug.
I worked around this issue by replacing the usage of the Default ClassPool by this
Singleton class:
public class SystemClassPool extends ClassPool
{
private SystemClassPool()
{
super(null);
appendSystemPath();
}
@Override
public ClassLoader getClassLoader()
{
return ClassLoader.getSystemClassLoader();
}
}
Equally to DefaultClassPool, it has the SystemPath appended, but its getClassLoader method
returns the SystemClassLoader, which is the closest I can get to Bootstrap class loader
(take a look at the
http://java.sun.com/javase/7/docs/api/java/lang/ClassLoader.html#getResou...
for more on this).
That didn't solve my problem entirely, because ScopedClassPoolRepositoryImpl has its
own “default” classpool field:
public class ScopedClassPoolRepositoryImpl implements ScopedClassPoolRepository {
/** The default class pool */
protected ClassPool classpool;
/** The factory for creating class pools */
protected ScopedClassPoolFactory factory = new ScopedClassPoolFactoryImpl();
/**
* Get the instance.
*
* @return the instance.
*/
public static ScopedClassPoolRepository getInstance() {
return instance;
}
/**
* Singleton.
*/
private ScopedClassPoolRepositoryImpl() {
classpool = ClassPool.getDefault();
// FIXME This doesn't look correct
ClassLoader cl = Thread.currentThread().getContextClassLoader();
classpool.insertClassPath(new LoaderClassPath(cl));
}
...
}
Differently from what one may have thought, the ClassPoolRepository class (from
jboss-classpool project) is not a subclass of ScopedClassPoolRepositoryImpl, given this
class cannot be subclassed. This has been an issue for me before, because I always thought
my code would be much cleaner if I could extend ScopedClassPoolRepositoryImpl instead of
http://anonsvn.jboss.org/repos/jbossas/projects/jboss-classpool/trunk/cla....
So, what should be done in this regard? I'm opening this thread se we can find an
elegant solution to my problem. Should ScopedClassPoolRepository be singleton? Should we
use ScopedClassPoolFactory at all (the problem with not doing that is that we will have
duplicate code in both classes)? I know that ScopedClassPool and auxiliary classes have
been created to be used as the ClassPool solution to AS, but so many things have changed
ever since that this solution is far from being complete, and that's why we need
jboss-classpool now. So now, I'm not even sure what to do of that.
Regarding ClassPool.getClassLoader()'s implementation, I don't think it is a bug,
even though we are not using this implementation at all (ScopedClassPool overwrites it,
and so does the new SystemClassPool class). I just think that it is a way of doing things
that works with simple standalone scenarios, but that doesnot fulfill our needs with AS.
--------------------------------------------------------------
To reply to this message visit the message page:
http://community.jboss.org/message/524465#524465