HHH-14306 - Passed TcclLookupPrecedence parameter in JPA properties is ignored

This commit is contained in:
Steve Ebersole 2023-08-11 08:19:41 -05:00
parent 317334f14d
commit 4666d774e4
3 changed files with 100 additions and 54 deletions

View File

@ -41,7 +41,7 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
private static final String CLASS_PATH_SCHEME = "classpath://";
private final ConcurrentMap<Class, AggregatedServiceLoader<?>> serviceLoaders = new ConcurrentHashMap<>();
private final ConcurrentMap<Class<?>, AggregatedServiceLoader<?>> serviceLoaders = new ConcurrentHashMap<>();
private volatile AggregatedClassLoader aggregatedClassLoader;
/**
@ -110,7 +110,10 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
providedClassLoaders.addAll( classLoaders );
}
return new ClassLoaderServiceImpl( providedClassLoaders,TcclLookupPrecedence.AFTER );
return new ClassLoaderServiceImpl(
providedClassLoaders,
TcclLookupPrecedence.from( configValues, TcclLookupPrecedence.AFTER )
);
}
@Override
@ -119,10 +122,7 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
try {
return (Class<T>) Class.forName( className, true, getAggregatedClassLoader() );
}
catch (Exception e) {
throw new ClassLoadingException( "Unable to load class [" + className + "]", e );
}
catch (LinkageError e) {
catch (Exception | LinkageError e) {
throw new ClassLoadingException( "Unable to load class [" + className + "]", e );
}
}

View File

@ -6,6 +6,10 @@
*/
package org.hibernate.boot.registry.classloading.internal;
import java.util.Map;
import org.hibernate.cfg.AvailableSettings;
/**
* Defines when the lookup in the current thread context {@link ClassLoader} should be
* done according to the other ones.
@ -30,5 +34,40 @@ public enum TcclLookupPrecedence {
* the former hasn't been found in the other {@code ClassLoader}s.
* This is the default value.
*/
AFTER
AFTER;
/**
* Resolves the precedence from a Map of settings.
*
* @return The precedence, or {@code null} if none was specified.
* @throws IllegalArgumentException If there is a setting defined for
* precedence, but it is not a legal value
*/
public static TcclLookupPrecedence from(Map<?,?> settings) {
return from( settings, null );
}
/**
* Resolves the precedence from a Map of settings
*
* @return The precedence, or {@code defaultValue} if none was specified.
* @throws IllegalArgumentException If there is a setting defined for
* precedence, but it is not a legal value
*/
public static TcclLookupPrecedence from(Map<?,?> settings, TcclLookupPrecedence defaultValue) {
final String explicitSetting = (String) settings.get( AvailableSettings.TC_CLASSLOADER );
if ( explicitSetting == null ) {
return defaultValue;
}
if ( NEVER.name().equalsIgnoreCase( explicitSetting ) ) {
return NEVER;
}
if ( BEFORE.name().equalsIgnoreCase( explicitSetting ) ) {
return BEFORE;
}
throw new IllegalArgumentException( "Unknown TcclLookupPrecedence - " + explicitSetting );
}
}

View File

@ -13,7 +13,6 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
@ -120,7 +119,6 @@ import static org.hibernate.cfg.AvailableSettings.PASS;
import static org.hibernate.cfg.AvailableSettings.PERSISTENCE_UNIT_NAME;
import static org.hibernate.cfg.AvailableSettings.SCANNER_DISCOVERY;
import static org.hibernate.cfg.AvailableSettings.SESSION_FACTORY_NAME;
import static org.hibernate.cfg.AvailableSettings.TC_CLASSLOADER;
import static org.hibernate.cfg.AvailableSettings.TRANSACTION_COORDINATOR_STRATEGY;
import static org.hibernate.cfg.AvailableSettings.URL;
import static org.hibernate.cfg.AvailableSettings.USER;
@ -468,55 +466,64 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
}
}
// ClassLoaders ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NOTE: See BootstrapServiceRegistryBuilder#build. providedClassLoaderService and providedClassLoaders are
// mutually exclusive concepts, with priority given to the former
if ( providedClassLoaderService != null ) {
bsrBuilder.applyClassLoaderService( providedClassLoaderService );
}
else {
if ( persistenceUnit.getClassLoader() != null ) {
bsrBuilder.applyClassLoader( persistenceUnit.getClassLoader() );
}
if ( providedClassLoader != null ) {
bsrBuilder.applyClassLoader( providedClassLoader );
}
final Object classLoadersSetting = integrationSettings.get( CLASSLOADERS );
if ( classLoadersSetting != null ) {
if ( classLoadersSetting instanceof Collection) {
@SuppressWarnings("unchecked")
Collection<ClassLoader> classLoaders = (Collection<ClassLoader>) classLoadersSetting;
for ( ClassLoader classLoader : classLoaders ) {
bsrBuilder.applyClassLoader( classLoader );
}
}
else if ( classLoadersSetting.getClass().isArray() ) {
for ( ClassLoader classLoader : (ClassLoader[]) classLoadersSetting ) {
bsrBuilder.applyClassLoader( classLoader );
}
}
else if ( classLoadersSetting instanceof ClassLoader ) {
bsrBuilder.applyClassLoader( (ClassLoader) classLoadersSetting );
}
}
//configurationValues not assigned yet, using directly the properties of the PU
Properties puProperties = persistenceUnit.getProperties();
if( puProperties != null ) {
final String tcclLookupPrecedence = puProperties.getProperty( TC_CLASSLOADER );
if( tcclLookupPrecedence != null ) {
bsrBuilder.applyTcclLookupPrecedence( TcclLookupPrecedence.valueOf( tcclLookupPrecedence.toUpperCase( Locale.ROOT ) ) );
}
}
}
configureClassLoading( integrationSettings, providedClassLoader, providedClassLoaderService, bsrBuilder );
return bsrBuilder.build();
}
/**
* @implNote {@code providedClassLoaderService} and {@code providedClassLoaders}
* are mutually exclusive concepts, with priority given to the former.
*
* @see BootstrapServiceRegistryBuilder#build
*/
private void configureClassLoading(
Map<?, ?> integrationSettings,
ClassLoader providedClassLoader,
ClassLoaderService providedClassLoaderService,
BootstrapServiceRegistryBuilder bsrBuilder) {
if ( providedClassLoaderService != null ) {
bsrBuilder.applyClassLoaderService( providedClassLoaderService );
return;
}
if ( persistenceUnit.getClassLoader() != null ) {
bsrBuilder.applyClassLoader( persistenceUnit.getClassLoader() );
}
if ( providedClassLoader != null ) {
bsrBuilder.applyClassLoader( providedClassLoader );
}
final Object classLoadersSetting = integrationSettings.get( CLASSLOADERS );
if ( classLoadersSetting != null ) {
if ( classLoadersSetting instanceof Collection) {
@SuppressWarnings("unchecked")
Collection<ClassLoader> classLoaders = (Collection<ClassLoader>) classLoadersSetting;
for ( ClassLoader classLoader : classLoaders ) {
bsrBuilder.applyClassLoader( classLoader );
}
}
else if ( classLoadersSetting.getClass().isArray() ) {
for ( ClassLoader classLoader : (ClassLoader[]) classLoadersSetting ) {
bsrBuilder.applyClassLoader( classLoader );
}
}
else if ( classLoadersSetting instanceof ClassLoader ) {
bsrBuilder.applyClassLoader( (ClassLoader) classLoadersSetting );
}
}
//configurationValues not assigned yet, using directly the properties of the PU
final Properties puProperties = persistenceUnit.getProperties();
if ( puProperties != null ) {
final TcclLookupPrecedence tcclLookupPrecedence = TcclLookupPrecedence.from( puProperties );
if ( tcclLookupPrecedence != null ) {
bsrBuilder.applyTcclLookupPrecedence( tcclLookupPrecedence );
}
}
}
private void applyIntegrationProvider(Map<?,?> integrationSettings, BootstrapServiceRegistryBuilder bsrBuilder) {
Object integrationSetting = integrationSettings.get( INTEGRATOR_PROVIDER );
if ( integrationSetting == null ) {