Custom POJO Loading strategy for cglib and javassist
----------------------------------------------------
Key: HHH-5962
URL:
http://opensource.atlassian.com/projects/hibernate/browse/HHH-5962
Project: Hibernate Core
Issue Type: Bug
Components: core
Affects Versions: 3.6.1
Environment: Hibernate 3.6.1, PostgreSQL, OSGi
Reporter: Ilya Samartsev
I use hibernate in OSGi-enabled environment and have found a strange class-loading
behaviour of the initializer proxies. The problem is that it's not possible to define
simple domain-model OSGi bundles which have pojo-based classes to be enhanced by hibernate
without importing org.hibernate.*, net.sf.cglib.proxy.*, javassist.util.proxy.*, etc.
Testing environment:
- A Model bundle with pojos and hibernate HBMs(they used by osgi-hibernate loader to
enhance them). This bundle doesn't actually require any hibernate/cglib/javassist
imports for the reason there are simple pojos in it.
/src/com/example/TestPojoModel.java
/META-INF/mappings/TestPojoModel.hbm.xml
/META-INF/MANIFEST.MF
Expected behaviour:
To have "clean" bundle with pojos without any additional imports(e.g.
org.hibernate.* or cglib/javassist).
Enhance these classes without any errors.
Current behaviour:
These pojo-based model bundles require to import a lot of hibernate and cglib or javassist
stuff to enhance these pojos. The problem is that hibernate uses the same classloader
(from model bundle) to load both pojos and hibernate/codegeneration utility classes.
Otherwise it crushes with ClassNotFoundException.
Code explanation:
Javassist ProxyFactory initialization:
org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer:
ProxyFactory factory = new ProxyFactory();
factory.setSuperclass( interfaces.length == 1 ? persistentClass : null );
factory.setInterfaces( interfaces );
factory.setFilter( FINALIZE_FILTER );
return factory.createClass();
How javassist loads classes by default:
javassist.util.proxy.ProxyFactory:
protected ClassLoader getClassLoader0() {
ClassLoader loader = null;
if (superClass != null &&
!superClass.getName().equals("java.lang.Object"))
loader = superClass.getClassLoader();
else if (interfaces != null && interfaces.length > 0)
...
}
return loader;
}
It actually uses the classloader of the persistent class.
My proposition:
To create advanced classloader for ProxyFactory which has custom behaviour:
1. Firstly it tries to load class using the classloader of the persistent class
2. Secondly it tries to use the classloader of the curent hibernate bundle (which
definitely has access to its own hibernate classes and imports the classes of the
codegeneration libraries)
final ClassLoader platformDelegatingClassLoader = new
ClassLoader(persistentClass.getClassLoader()) {
private final ClassLoader platformClassLoader = getClass().getClassLoader();
// on loadClass() it tries to use parent's classloader(parent =
persistentClass.getClassLoader() - from the constructor)
// if loadClass() didn't find class it tries to findClass() which is actually
overridden to use current context's getClass().getClassLoader()
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
return platformClassLoader.loadClass(name);
}
};
ProxyFactory factory = new ProxyFactory() {
@Override
protected ClassLoader getClassLoader() {
return platformDelegatingClassLoader;
}
};
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
http://opensource.atlassian.com/projects/hibernate/secure/Administrators....
-
For more information on JIRA, see:
http://www.atlassian.com/software/jira