HHH-13022 Allow to fall back to the OSGi-provided TCCL during bootstrap
We previously erased that class loader, which is not a great idea, in particular when we use libraries such as JAXB which rely on the TCCL, to some extent. Without this patch, we cannot make the OSGi integration work correctly with Java 9 and above, because the JAXB APIs won't find the JAXB runtime.
This commit is contained in:
parent
6ef94f3ba7
commit
bf7f56e004
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.boot.registry.classloading.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
public class AggregatedClassLoader extends ClassLoader {
|
||||
private final ClassLoader[] individualClassLoaders;
|
||||
private final TcclLookupPrecedence tcclLookupPrecedence;
|
||||
|
||||
public AggregatedClassLoader(final LinkedHashSet<ClassLoader> orderedClassLoaderSet, TcclLookupPrecedence precedence) {
|
||||
super( null );
|
||||
individualClassLoaders = orderedClassLoaderSet.toArray( new ClassLoader[orderedClassLoaderSet.size()] );
|
||||
tcclLookupPrecedence = precedence;
|
||||
}
|
||||
|
||||
private Iterator<ClassLoader> newClassLoaderIterator() {
|
||||
final ClassLoader threadClassLoader = locateTCCL();
|
||||
if ( tcclLookupPrecedence == TcclLookupPrecedence.NEVER || threadClassLoader == null ) {
|
||||
return newTcclNeverIterator();
|
||||
}
|
||||
else if ( tcclLookupPrecedence == TcclLookupPrecedence.AFTER ) {
|
||||
return newTcclAfterIterator(threadClassLoader);
|
||||
}
|
||||
else if ( tcclLookupPrecedence == TcclLookupPrecedence.BEFORE ) {
|
||||
return newTcclBeforeIterator(threadClassLoader);
|
||||
}
|
||||
else {
|
||||
throw new RuntimeException( "Unknown precedence: "+tcclLookupPrecedence );
|
||||
}
|
||||
}
|
||||
|
||||
private Iterator<ClassLoader> newTcclBeforeIterator(final ClassLoader threadContextClassLoader) {
|
||||
final ClassLoader systemClassLoader = locateSystemClassLoader();
|
||||
return new Iterator<ClassLoader>() {
|
||||
private int currentIndex = 0;
|
||||
private boolean tcCLReturned = false;
|
||||
private boolean sysCLReturned = false;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if ( !tcCLReturned ) {
|
||||
return true;
|
||||
}
|
||||
else if ( currentIndex < individualClassLoaders.length ) {
|
||||
return true;
|
||||
}
|
||||
else if ( !sysCLReturned && systemClassLoader != null ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader next() {
|
||||
if ( !tcCLReturned ) {
|
||||
tcCLReturned = true;
|
||||
return threadContextClassLoader;
|
||||
}
|
||||
else if ( currentIndex < individualClassLoaders.length ) {
|
||||
currentIndex += 1;
|
||||
return individualClassLoaders[ currentIndex - 1 ];
|
||||
}
|
||||
else if ( !sysCLReturned && systemClassLoader != null ) {
|
||||
sysCLReturned = true;
|
||||
return systemClassLoader;
|
||||
}
|
||||
throw new IllegalStateException( "No more item" );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Iterator<ClassLoader> newTcclAfterIterator(final ClassLoader threadContextClassLoader) {
|
||||
final ClassLoader systemClassLoader = locateSystemClassLoader();
|
||||
return new Iterator<ClassLoader>() {
|
||||
private int currentIndex = 0;
|
||||
private boolean tcCLReturned = false;
|
||||
private boolean sysCLReturned = false;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if ( currentIndex < individualClassLoaders.length ) {
|
||||
return true;
|
||||
}
|
||||
else if ( !tcCLReturned ) {
|
||||
return true;
|
||||
}
|
||||
else if ( !sysCLReturned && systemClassLoader != null ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader next() {
|
||||
if ( currentIndex < individualClassLoaders.length ) {
|
||||
currentIndex += 1;
|
||||
return individualClassLoaders[ currentIndex - 1 ];
|
||||
}
|
||||
else if ( !tcCLReturned ) {
|
||||
tcCLReturned = true;
|
||||
return threadContextClassLoader;
|
||||
}
|
||||
else if ( !sysCLReturned && systemClassLoader != null ) {
|
||||
sysCLReturned = true;
|
||||
return systemClassLoader;
|
||||
}
|
||||
throw new IllegalStateException( "No more item" );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Iterator<ClassLoader> newTcclNeverIterator() {
|
||||
final ClassLoader systemClassLoader = locateSystemClassLoader();
|
||||
return new Iterator<ClassLoader>() {
|
||||
private int currentIndex = 0;
|
||||
private boolean sysCLReturned = false;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if ( currentIndex < individualClassLoaders.length ) {
|
||||
return true;
|
||||
}
|
||||
else if ( !sysCLReturned && systemClassLoader != null ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader next() {
|
||||
if ( currentIndex < individualClassLoaders.length ) {
|
||||
currentIndex += 1;
|
||||
return individualClassLoaders[ currentIndex - 1 ];
|
||||
}
|
||||
else if ( !sysCLReturned && systemClassLoader != null ) {
|
||||
sysCLReturned = true;
|
||||
return systemClassLoader;
|
||||
}
|
||||
throw new IllegalStateException( "No more item" );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<URL> getResources(String name) throws IOException {
|
||||
final LinkedHashSet<URL> resourceUrls = new LinkedHashSet<URL>();
|
||||
final Iterator<ClassLoader> clIterator = newClassLoaderIterator();
|
||||
while ( clIterator.hasNext() ) {
|
||||
final ClassLoader classLoader = clIterator.next();
|
||||
final Enumeration<URL> urls = classLoader.getResources( name );
|
||||
while ( urls.hasMoreElements() ) {
|
||||
resourceUrls.add( urls.nextElement() );
|
||||
}
|
||||
}
|
||||
|
||||
return new Enumeration<URL>() {
|
||||
final Iterator<URL> resourceUrlIterator = resourceUrls.iterator();
|
||||
|
||||
@Override
|
||||
public boolean hasMoreElements() {
|
||||
return resourceUrlIterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL nextElement() {
|
||||
return resourceUrlIterator.next();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected URL findResource(String name) {
|
||||
final Iterator<ClassLoader> clIterator = newClassLoaderIterator();
|
||||
while ( clIterator.hasNext() ) {
|
||||
final ClassLoader classLoader = clIterator.next();
|
||||
final URL resource = classLoader.getResource( name );
|
||||
if ( resource != null ) {
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
return super.findResource( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
final Iterator<ClassLoader> clIterator = newClassLoaderIterator();
|
||||
while ( clIterator.hasNext() ) {
|
||||
final ClassLoader classLoader = clIterator.next();
|
||||
try {
|
||||
return classLoader.loadClass( name );
|
||||
}
|
||||
catch (Exception ignore) {
|
||||
}
|
||||
catch (LinkageError ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
throw new ClassNotFoundException( "Could not load requested class : " + name );
|
||||
}
|
||||
|
||||
private static ClassLoader locateSystemClassLoader() {
|
||||
try {
|
||||
return ClassLoader.getSystemClassLoader();
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static ClassLoader locateTCCL() {
|
||||
try {
|
||||
return Thread.currentThread().getContextClassLoader();
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.boot.registry.classloading.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
@ -17,7 +16,6 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -126,224 +124,6 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
|
|||
}
|
||||
}
|
||||
|
||||
private static ClassLoader locateSystemClassLoader() {
|
||||
try {
|
||||
return ClassLoader.getSystemClassLoader();
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static ClassLoader locateTCCL() {
|
||||
try {
|
||||
return Thread.currentThread().getContextClassLoader();
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class AggregatedClassLoader extends ClassLoader {
|
||||
private final ClassLoader[] individualClassLoaders;
|
||||
private final TcclLookupPrecedence tcclLookupPrecedence;
|
||||
|
||||
private AggregatedClassLoader(final LinkedHashSet<ClassLoader> orderedClassLoaderSet, TcclLookupPrecedence precedence) {
|
||||
super( null );
|
||||
individualClassLoaders = orderedClassLoaderSet.toArray( new ClassLoader[orderedClassLoaderSet.size()] );
|
||||
tcclLookupPrecedence = precedence;
|
||||
}
|
||||
|
||||
private Iterator<ClassLoader> newClassLoaderIterator() {
|
||||
final ClassLoader threadClassLoader = locateTCCL();
|
||||
if ( tcclLookupPrecedence == TcclLookupPrecedence.NEVER || threadClassLoader == null ) {
|
||||
return newTcclNeverIterator();
|
||||
}
|
||||
else if ( tcclLookupPrecedence == TcclLookupPrecedence.AFTER ) {
|
||||
return newTcclAfterIterator(threadClassLoader);
|
||||
}
|
||||
else if ( tcclLookupPrecedence == TcclLookupPrecedence.BEFORE ) {
|
||||
return newTcclBeforeIterator(threadClassLoader);
|
||||
}
|
||||
else {
|
||||
throw new RuntimeException( "Unknown precedence: "+tcclLookupPrecedence );
|
||||
}
|
||||
}
|
||||
|
||||
private Iterator<ClassLoader> newTcclBeforeIterator(final ClassLoader threadContextClassLoader) {
|
||||
final ClassLoader systemClassLoader = locateSystemClassLoader();
|
||||
return new Iterator<ClassLoader>() {
|
||||
private int currentIndex = 0;
|
||||
private boolean tcCLReturned = false;
|
||||
private boolean sysCLReturned = false;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if ( !tcCLReturned ) {
|
||||
return true;
|
||||
}
|
||||
else if ( currentIndex < individualClassLoaders.length ) {
|
||||
return true;
|
||||
}
|
||||
else if ( !sysCLReturned && systemClassLoader != null ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader next() {
|
||||
if ( !tcCLReturned ) {
|
||||
tcCLReturned = true;
|
||||
return threadContextClassLoader;
|
||||
}
|
||||
else if ( currentIndex < individualClassLoaders.length ) {
|
||||
currentIndex += 1;
|
||||
return individualClassLoaders[ currentIndex - 1 ];
|
||||
}
|
||||
else if ( !sysCLReturned && systemClassLoader != null ) {
|
||||
sysCLReturned = true;
|
||||
return systemClassLoader;
|
||||
}
|
||||
throw new IllegalStateException( "No more item" );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Iterator<ClassLoader> newTcclAfterIterator(final ClassLoader threadContextClassLoader) {
|
||||
final ClassLoader systemClassLoader = locateSystemClassLoader();
|
||||
return new Iterator<ClassLoader>() {
|
||||
private int currentIndex = 0;
|
||||
private boolean tcCLReturned = false;
|
||||
private boolean sysCLReturned = false;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if ( currentIndex < individualClassLoaders.length ) {
|
||||
return true;
|
||||
}
|
||||
else if ( !tcCLReturned ) {
|
||||
return true;
|
||||
}
|
||||
else if ( !sysCLReturned && systemClassLoader != null ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader next() {
|
||||
if ( currentIndex < individualClassLoaders.length ) {
|
||||
currentIndex += 1;
|
||||
return individualClassLoaders[ currentIndex - 1 ];
|
||||
}
|
||||
else if ( !tcCLReturned ) {
|
||||
tcCLReturned = true;
|
||||
return threadContextClassLoader;
|
||||
}
|
||||
else if ( !sysCLReturned && systemClassLoader != null ) {
|
||||
sysCLReturned = true;
|
||||
return systemClassLoader;
|
||||
}
|
||||
throw new IllegalStateException( "No more item" );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Iterator<ClassLoader> newTcclNeverIterator() {
|
||||
final ClassLoader systemClassLoader = locateSystemClassLoader();
|
||||
return new Iterator<ClassLoader>() {
|
||||
private int currentIndex = 0;
|
||||
private boolean sysCLReturned = false;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if ( currentIndex < individualClassLoaders.length ) {
|
||||
return true;
|
||||
}
|
||||
else if ( !sysCLReturned && systemClassLoader != null ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader next() {
|
||||
if ( currentIndex < individualClassLoaders.length ) {
|
||||
currentIndex += 1;
|
||||
return individualClassLoaders[ currentIndex - 1 ];
|
||||
}
|
||||
else if ( !sysCLReturned && systemClassLoader != null ) {
|
||||
sysCLReturned = true;
|
||||
return systemClassLoader;
|
||||
}
|
||||
throw new IllegalStateException( "No more item" );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<URL> getResources(String name) throws IOException {
|
||||
final LinkedHashSet<URL> resourceUrls = new LinkedHashSet<URL>();
|
||||
final Iterator<ClassLoader> clIterator = newClassLoaderIterator();
|
||||
while ( clIterator.hasNext() ) {
|
||||
final ClassLoader classLoader = clIterator.next();
|
||||
final Enumeration<URL> urls = classLoader.getResources( name );
|
||||
while ( urls.hasMoreElements() ) {
|
||||
resourceUrls.add( urls.nextElement() );
|
||||
}
|
||||
}
|
||||
|
||||
return new Enumeration<URL>() {
|
||||
final Iterator<URL> resourceUrlIterator = resourceUrls.iterator();
|
||||
|
||||
@Override
|
||||
public boolean hasMoreElements() {
|
||||
return resourceUrlIterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL nextElement() {
|
||||
return resourceUrlIterator.next();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected URL findResource(String name) {
|
||||
final Iterator<ClassLoader> clIterator = newClassLoaderIterator();
|
||||
while ( clIterator.hasNext() ) {
|
||||
final ClassLoader classLoader = clIterator.next();
|
||||
final URL resource = classLoader.getResource( name );
|
||||
if ( resource != null ) {
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
return super.findResource( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
final Iterator<ClassLoader> clIterator = newClassLoaderIterator();
|
||||
while ( clIterator.hasNext() ) {
|
||||
final ClassLoader classLoader = clIterator.next();
|
||||
try {
|
||||
return classLoader.loadClass( name );
|
||||
}
|
||||
catch (Exception ignore) {
|
||||
}
|
||||
catch (LinkageError ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
throw new ClassNotFoundException( "Could not load requested class : " + name );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public <T> Class<T> classForName(String className) {
|
||||
|
|
|
@ -49,7 +49,7 @@ dependencies {
|
|||
// this dependency wasn't there in the 5.2.x bundles so ignoring it for now
|
||||
// we might reintroduce it at some point if users complain about it
|
||||
exclude module: 'javax.activation-api'
|
||||
// TODO HHH-13022 Find a way to include JAXB in the OSGi feature
|
||||
// JAXB is included in the Karaf distribution
|
||||
exclude module: 'jaxb-api'
|
||||
exclude module: 'jaxb-runtime'
|
||||
}
|
||||
|
|
|
@ -6,7 +6,11 @@
|
|||
*/
|
||||
package org.hibernate.osgi;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.boot.registry.classloading.internal.AggregatedClassLoader;
|
||||
import org.hibernate.boot.registry.classloading.internal.TcclLookupPrecedence;
|
||||
import org.hibernate.jpa.HibernateEntityManagerFactory;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
|
@ -52,7 +56,13 @@ public class OsgiPersistenceProviderService implements ServiceFactory {
|
|||
// ClassLoaderService now.
|
||||
|
||||
final ClassLoader originalTccl = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader( osgiClassLoader );
|
||||
LinkedHashSet<ClassLoader> newTcclDelegates = new LinkedHashSet<>();
|
||||
newTcclDelegates.add( osgiClassLoader );
|
||||
newTcclDelegates.add( originalTccl );
|
||||
final ClassLoader newTccl = new AggregatedClassLoader(
|
||||
newTcclDelegates, TcclLookupPrecedence.NEVER
|
||||
);
|
||||
Thread.currentThread().setContextClassLoader( newTccl );
|
||||
try {
|
||||
return new OsgiPersistenceProvider( osgiClassLoader, osgiJtaPlatform, osgiServiceUtil, requestingBundle );
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ import org.hibernate.boot.registry.BootstrapServiceRegistry;
|
|||
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.boot.registry.classloading.internal.AggregatedClassLoader;
|
||||
import org.hibernate.boot.registry.classloading.internal.TcclLookupPrecedence;
|
||||
import org.hibernate.boot.registry.selector.StrategyRegistrationProvider;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.integrator.spi.Integrator;
|
||||
|
@ -26,6 +28,7 @@ import org.osgi.framework.ServiceRegistration;
|
|||
import org.osgi.framework.wiring.BundleWiring;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
/**
|
||||
* Hibernate 4.2 and 4.3 still heavily rely on TCCL for ClassLoading. Although
|
||||
|
@ -78,7 +81,13 @@ public class OsgiSessionFactoryService implements ServiceFactory {
|
|||
// ClassLoaderService now.
|
||||
|
||||
final ClassLoader originalTccl = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader( osgiClassLoader );
|
||||
LinkedHashSet<ClassLoader> newTcclDelegates = new LinkedHashSet<>();
|
||||
newTcclDelegates.add( osgiClassLoader );
|
||||
newTcclDelegates.add( originalTccl );
|
||||
final ClassLoader newTccl = new AggregatedClassLoader(
|
||||
newTcclDelegates, TcclLookupPrecedence.NEVER
|
||||
);
|
||||
Thread.currentThread().setContextClassLoader( newTccl );
|
||||
try {
|
||||
return buildSessionFactory( requestingBundle, osgiClassLoader );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue