问题
I've successfully started Hibernate in an OSGi context, and now I want to add Envers.
The documentation claims that's possible. I don't believe it anymore. There is no documentation of any kind for this subject and nobody seems to have actually done it. Moreover even with a Blueprint implementation I had to hack the classloader to make Hibernate even find Envers:
osgiClassLoader = new org.hibernate.osgi.OsgiClassLoader();
osgiClassLoader.addBundle(requestingBundle);
osgiClassLoader.addBundle(FrameworkUtil.getBundle(SessionFactory.class));
osgiClassLoader.addBundle(FrameworkUtil.getBundle(HibernateEntityManagerFactory.class));
osgiClassLoader.addBundle(FrameworkUtil.getBundle(EnversService.class));
Thread.currentThread().setContextClassLoader(osgiClassLoader);
(I feel like I should be asking: "Is Envers in OSGi even possible?" So if you have a definite answer for that question, please let me know. I've been spending way too much time on these issues.)
However the actual problem has nothing to do with Hibernate / Envers and all with OSGi. Both want to access the entities and enums used. With reflection nonetheless. Of course they can't. And of course I can't add Import-Packages.
The relevant stack trace looks something like this:
Caused by: java.lang.ClassNotFoundException: org.acme.project.MyEnum cannot be found by org.hibernate.core_5.1.0.Final
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:461)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:372)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:364)
at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:161)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at org.hibernate.internal.util.ReflectHelper.classForName(ReflectHelper.java:151)
at org.hibernate.type.EnumType.setParameterValues(EnumType.java:105)
... 62 more
Normally with OSGi-agnostic frameworks I'd just add something like this to the MANIFEST.MF:
// to org.hibernate.core
Eclipse-BuddyPolicy: registered
// to org.acme.project
Eclipse-RegisterBuddy: org.hibernate.core
However I can't add anything to Hibernate's manifest. I tried contributing the line via fragment, but that did not work either.
I even tried adding the entire Hibernate dependencies as JAR into a plug-in to add the above. It won't work.
How to resolve these classloader issues?
回答1:
If your @Audited class references an Enum, org.hibernate.core needs to import the classes package. The best way to do this is to register a fragment bundle.
Also, it is wise to make sure your start level for hibernate bundles is lower than the start levels for entity bundles.
Here is a snippet from a sample Gradle script to create a fragment bundle. Make sure your change the org.hibernate.core bundle version to the one you are using, and also update the 'your.package' to the one that contains your Enum.
/*
When using Envers, entities that reference Enum classes must be imported (Import-Package) by the org.hibernate.core bundle.
*/
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'biz.aQute.bnd:biz.aQute.bnd.gradle:3.2.0'
}
}
apply plugin: 'biz.aQute.bnd.builder'
jar {
manifest {
attributes(
'Fragment-Host': 'org.hibernate.core;' + 'bundle-version=' + '5.2.9.Final',
'Import-Package': 'your.package'
)
}
}
回答2:
Late to the party, but throwing this here in case anyone else needs it:
Hibernate bootstrapping looks fairly different in OSGi than it does in SE/EE land. We have numerous tickets in JIRA tracking enhancements, especially to make things more dynamic and to reduce the brittleness of startup ordering (Steven is absolutely correct that hibernate-core, hibernate-envers, etc. must currently be started first prior to your bundle).
I'd highly advise against the bundle fragment approaches, but I'll comment why on Steven's answer.
Our hibernate-demos project has a few OSGi quickstarts, all of which include Envers setup. This one is probably more of what you're looking for: https://github.com/hibernate/hibernate-demos/tree/master/hibernate-orm/osgi/unmanaged-native
来源:https://stackoverflow.com/questions/45933175/classloader-issues-with-envers-in-osgi