From 93ea7573820321ca0e3af1c415f7f868c62ebf8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Wed, 5 Jun 2024 15:14:09 +0200 Subject: [PATCH] HHH-18231 Take provided classloader/classloaderservice into account in PersistenceXmlParser --- .../jpa/HibernatePersistenceProvider.java | 3 +- .../boot/internal/PersistenceXmlParser.java | 233 ++++++++---------- .../org/hibernate/jpa/boot/spi/Bootstrap.java | 2 +- .../jpa/jakarta/JakartaXmlSmokeTests.java | 3 +- .../DuplicatePersistenceUnitNameTest.java | 2 +- .../ExcludeUnlistedClassesTest.java | 4 +- 6 files changed, 115 insertions(+), 132 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/HibernatePersistenceProvider.java b/hibernate-core/src/main/java/org/hibernate/jpa/HibernatePersistenceProvider.java index e810f961a2..ad88d1926e 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/HibernatePersistenceProvider.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/HibernatePersistenceProvider.java @@ -78,7 +78,8 @@ public class HibernatePersistenceProvider implements PersistenceProvider { final Map integration = wrap( properties ); final List units; try { - units = PersistenceXmlParser.locatePersistenceUnits( integration ); + units = PersistenceXmlParser.create( integration, providedClassLoader, providedClassLoaderService ) + .locatePersistenceUnits(); } catch (Exception e) { log.debug( "Unable to locate persistence units", e ); diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/PersistenceXmlParser.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/PersistenceXmlParser.java index 26b5ddf077..45352ba52b 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/PersistenceXmlParser.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/PersistenceXmlParser.java @@ -12,11 +12,10 @@ import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; -import java.util.concurrent.ConcurrentHashMap; import javax.xml.transform.stream.StreamSource; import org.hibernate.boot.archive.internal.ArchiveHelper; @@ -51,20 +50,80 @@ public class PersistenceXmlParser { private static final EntityManagerMessageLogger LOG = messageLogger( PersistenceXmlParser.class ); /** - * Find all persistence-units from all accessible {@code META-INF/persistence.xml} resources - * + * @return A {@link PersistenceXmlParser} using no settings at all. + */ + public static PersistenceXmlParser create() { + return new PersistenceXmlParser( Map.of(), null, null ); + } + + /** * @param integration The Map of integration settings + * @return A {@link PersistenceXmlParser} using the provided settings. + */ + public static PersistenceXmlParser create(Map integration) { + return new PersistenceXmlParser( integration, null, null ); + } + + /** + * @param integration The Map of integration settings + * @param providedClassLoader A class loader to use. + * Resources will be retrieved from this classloader in priority, + * before looking into classloaders mentioned in integration settings. + * @param providedClassLoaderService A class loader service to use. + * Takes precedence over classloading settings in {@code integration} + * and over {@code providedClassLoader}. + * @return A {@link PersistenceXmlParser} using the provided settings and classloading configuration. + */ + public static PersistenceXmlParser create(Map integration, ClassLoader providedClassLoader, + ClassLoaderService providedClassLoaderService) { + return new PersistenceXmlParser( integration, providedClassLoader, providedClassLoaderService ); + } + + private final Map integration; + private final ClassLoaderService classLoaderService; + + protected PersistenceXmlParser(Map integration, ClassLoader providedClassLoader, + ClassLoaderService providedClassLoaderService) { + this.integration = integration; + if ( providedClassLoaderService != null ) { + classLoaderService = providedClassLoaderService; + } + else { + final List providedClassLoaders = new ArrayList<>(); + if ( providedClassLoader != null ) { + providedClassLoaders.add( providedClassLoader ); + } + + @SuppressWarnings("unchecked") + final Collection classLoaders = + (Collection) integration.get( AvailableSettings.CLASSLOADERS ); + if ( classLoaders != null ) { + providedClassLoaders.addAll( classLoaders ); + } + + classLoaderService = new ClassLoaderServiceImpl( + providedClassLoaders, + TcclLookupPrecedence.from( integration, TcclLookupPrecedence.AFTER ) + ); + } + } + + /** + * Find all persistence-units from all accessible {@code META-INF/persistence.xml} resources * * @return List of descriptors for all discovered persistence-units. */ - public static List locatePersistenceUnits(Map integration) { - @SuppressWarnings("removal") - final PersistenceXmlParser parser = new PersistenceXmlParser( - fromConfigSettings( integration ), - PersistenceUnitTransactionType.RESOURCE_LOCAL - ); - parser.doResolve( integration ); - return new ArrayList<>( parser.persistenceUnits.values() ); + @SuppressWarnings("removal") + public List locatePersistenceUnits() { + Map persistenceUnits = new HashMap<>(); + final List xmlUrls = classLoaderService.locateResources( "META-INF/persistence.xml" ); + if ( xmlUrls.isEmpty() ) { + LOG.unableToFindPersistenceXmlInClasspath(); + } + else { + parsePersistenceXml( persistenceUnits, xmlUrls, PersistenceUnitTransactionType.RESOURCE_LOCAL ); + } + return new ArrayList<>( persistenceUnits.values() ); } /** @@ -72,13 +131,12 @@ public class PersistenceXmlParser { * persistence-unit. * * @param persistenceXmlUrl The {@code persistence.xml} URL - * @param integration The Map of integration settings * * @return The single persistence-unit descriptor */ @SuppressWarnings("removal") - public static ParsedPersistenceXmlDescriptor locateIndividualPersistenceUnit(URL persistenceXmlUrl, Map integration) { - return locateIndividualPersistenceUnit( persistenceXmlUrl, PersistenceUnitTransactionType.RESOURCE_LOCAL, integration ); + public ParsedPersistenceXmlDescriptor locateIndividualPersistenceUnit(URL persistenceXmlUrl) { + return locateIndividualPersistenceUnit( persistenceXmlUrl, PersistenceUnitTransactionType.RESOURCE_LOCAL ); } /** @@ -87,25 +145,17 @@ public class PersistenceXmlParser { * * @param persistenceXmlUrl The {@code persistence.xml} URL * @param transactionType The specific PersistenceUnitTransactionType to incorporate into the persistence-unit descriptor - * @param integration The Map of integration settings * * @return The single persistence-unit descriptor */ - public static ParsedPersistenceXmlDescriptor locateIndividualPersistenceUnit( + public ParsedPersistenceXmlDescriptor locateIndividualPersistenceUnit( URL persistenceXmlUrl, @SuppressWarnings("removal") - PersistenceUnitTransactionType transactionType, - Map integration) { - final PersistenceXmlParser parser = new PersistenceXmlParser( - fromConfigSettings( integration ), - transactionType - ); - - parser.parsePersistenceXml( persistenceXmlUrl, integration ); - - assert parser.persistenceUnits.size() == 1; - - return parser.persistenceUnits.values().iterator().next(); + PersistenceUnitTransactionType transactionType) { + Map persistenceUnits = new HashMap<>(); + parsePersistenceXml( persistenceUnits, persistenceXmlUrl, transactionType ); + assert persistenceUnits.size() == 1; + return persistenceUnits.values().iterator().next(); } /** @@ -116,22 +166,9 @@ public class PersistenceXmlParser { * * @return The matching persistence-unit descriptor */ - public static ParsedPersistenceXmlDescriptor locateNamedPersistenceUnit(URL persistenceXmlUrl, String name) { - return locateNamedPersistenceUnit( persistenceXmlUrl, name, Collections.emptyMap() ); - } - - /** - * Parse a specific {@code persistence.xml} and return the descriptor for the persistence-unit with matching name - * - * @param persistenceXmlUrl The {@code persistence.xml} URL - * @param name The PU name to match - * @param integration The Map of integration settings - * - * @return The matching persistence-unit descriptor - */ @SuppressWarnings("removal") - public static ParsedPersistenceXmlDescriptor locateNamedPersistenceUnit(URL persistenceXmlUrl, String name, Map integration) { - return locateNamedPersistenceUnit( persistenceXmlUrl, name, PersistenceUnitTransactionType.RESOURCE_LOCAL, integration ); + public ParsedPersistenceXmlDescriptor locateNamedPersistenceUnit(URL persistenceXmlUrl, String name) { + return locateNamedPersistenceUnit( persistenceXmlUrl, name, PersistenceUnitTransactionType.RESOURCE_LOCAL ); } /** @@ -140,39 +177,20 @@ public class PersistenceXmlParser { * @param persistenceXmlUrl The {@code persistence.xml} URL * @param name The PU name to match * @param transactionType The specific PersistenceUnitTransactionType to incorporate into the persistence-unit descriptor - * @param integration The Map of integration settings * * @return The matching persistence-unit descriptor */ - public static ParsedPersistenceXmlDescriptor locateNamedPersistenceUnit( + public ParsedPersistenceXmlDescriptor locateNamedPersistenceUnit( URL persistenceXmlUrl, String name, @SuppressWarnings("removal") - PersistenceUnitTransactionType transactionType, - Map integration) { + PersistenceUnitTransactionType transactionType) { assert StringHelper.isNotEmpty( name ); - final PersistenceXmlParser parser = new PersistenceXmlParser( - fromConfigSettings( integration ), - transactionType - ); - - parser.parsePersistenceXml( persistenceXmlUrl, integration ); - assert parser.persistenceUnits.containsKey( name ); - - return parser.persistenceUnits.get( name ); - } - - /** - * Intended only for use by Hibernate tests! - *

- * Parses a specific persistence.xml file... - */ - @SuppressWarnings("removal") - public static Map parse( - URL persistenceXmlUrl, - PersistenceUnitTransactionType transactionType) { - return parse( persistenceXmlUrl, transactionType, Collections.emptyMap() ); + Map persistenceUnits = new HashMap<>(); + parsePersistenceXml( persistenceUnits, persistenceXmlUrl, transactionType ); + assert persistenceUnits.containsKey( name ); + return persistenceUnits.get( name ); } /** @@ -181,69 +199,30 @@ public class PersistenceXmlParser { * * @param persistenceXmlUrl The URL of the {@code persistence.xml} to parse * @param transactionType The specific PersistenceUnitTransactionType to incorporate into the persistence-unit descriptor - * @param integration The Map of integration settings * * @return Map of persistence-unit descriptors keyed by the PU name */ - public static Map parse( + public Map parse( URL persistenceXmlUrl, @SuppressWarnings("removal") - PersistenceUnitTransactionType transactionType, - Map integration) { - PersistenceXmlParser parser = new PersistenceXmlParser( - fromConfigSettings( integration ), - transactionType - ); - - parser.parsePersistenceXml( persistenceXmlUrl, integration ); - return parser.persistenceUnits; + PersistenceUnitTransactionType transactionType) { + Map persistenceUnits = new HashMap<>(); + parsePersistenceXml( persistenceUnits, persistenceXmlUrl, transactionType ); + return persistenceUnits; } - private final ClassLoaderService classLoaderService; - @SuppressWarnings("removal") - private final PersistenceUnitTransactionType defaultTransactionType; - private final Map persistenceUnits; - - @SuppressWarnings("removal") - protected PersistenceXmlParser(ClassLoaderService classLoaderService, PersistenceUnitTransactionType defaultTransactionType) { - this.classLoaderService = classLoaderService; - this.defaultTransactionType = defaultTransactionType; - this.persistenceUnits = new ConcurrentHashMap<>(); - } - - private static ClassLoaderServiceImpl fromConfigSettings(Map configValues) { - final List providedClassLoaders = new ArrayList<>(); - - @SuppressWarnings("unchecked") - final Collection classLoaders = - (Collection) configValues.get( AvailableSettings.CLASSLOADERS ); - if ( classLoaders != null ) { - providedClassLoaders.addAll( classLoaders ); - } - - return new ClassLoaderServiceImpl( - providedClassLoaders, - TcclLookupPrecedence.from( configValues, TcclLookupPrecedence.AFTER ) - ); - } - - private void doResolve(Map integration) { - final List xmlUrls = classLoaderService.locateResources( "META-INF/persistence.xml" ); - if ( xmlUrls.isEmpty() ) { - LOG.unableToFindPersistenceXmlInClasspath(); - } - else { - parsePersistenceXml( xmlUrls, integration ); - } - } - - private void parsePersistenceXml(List xmlUrls, Map integration) { + private void parsePersistenceXml(Map persistenceUnits, + List xmlUrls, + @SuppressWarnings("removal") + PersistenceUnitTransactionType defaultTransactionType) { for ( URL xmlUrl : xmlUrls ) { - parsePersistenceXml( xmlUrl, integration ); + parsePersistenceXml( persistenceUnits, xmlUrl, defaultTransactionType ); } } - protected void parsePersistenceXml(URL xmlUrl, Map integration) { + @SuppressWarnings("removal") + protected void parsePersistenceXml(Map persistenceUnits, + URL xmlUrl, PersistenceUnitTransactionType defaultTransactionType) { if ( LOG.isTraceEnabled() ) { LOG.tracef( "Attempting to parse persistence.xml file : %s", xmlUrl.toExternalForm() ); } @@ -267,7 +246,7 @@ public class PersistenceXmlParser { // per JPA spec, any settings passed in to PersistenceProvider bootstrap methods should override // values found in persistence.xml - applyIntegrationOverrides( integration, persistenceUnitDescriptor ); + applyIntegrationOverrides( integration, defaultTransactionType, persistenceUnitDescriptor ); persistenceUnits.put( persistenceUnitDescriptor.getName(), persistenceUnitDescriptor ); } @@ -316,8 +295,9 @@ public class PersistenceXmlParser { return false; } - @SuppressWarnings("deprecation") - private void applyIntegrationOverrides(Map integration, ParsedPersistenceXmlDescriptor persistenceUnitDescriptor) { + @SuppressWarnings({"deprecation", "removal"}) + private void applyIntegrationOverrides(Map integration, PersistenceUnitTransactionType defaultTransactionType, + ParsedPersistenceXmlDescriptor persistenceUnitDescriptor) { if ( integration.containsKey( AvailableSettings.JAKARTA_PERSISTENCE_PROVIDER ) ) { persistenceUnitDescriptor.setProviderClassName( (String) integration.get( AvailableSettings.JAKARTA_PERSISTENCE_PROVIDER ) ); } @@ -364,14 +344,15 @@ public class PersistenceXmlParser { persistenceUnitDescriptor.setNonJtaDataSource( integration.get( AvailableSettings.JAKARTA_NON_JTA_DATASOURCE ) ); } - applyTransactionTypeOverride( persistenceUnitDescriptor ); + applyTransactionTypeOverride( persistenceUnitDescriptor, defaultTransactionType ); final Properties properties = persistenceUnitDescriptor.getProperties(); ConfigurationHelper.overrideProperties( properties, integration ); } @SuppressWarnings("removal") - private void applyTransactionTypeOverride(ParsedPersistenceXmlDescriptor persistenceUnitDescriptor) { + private void applyTransactionTypeOverride(ParsedPersistenceXmlDescriptor persistenceUnitDescriptor, + PersistenceUnitTransactionType defaultTransactionType) { // if transaction type is set already, use that value if ( persistenceUnitDescriptor.getTransactionType() == null ) { // else diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/Bootstrap.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/Bootstrap.java index 9582006841..37321ec8cb 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/Bootstrap.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/Bootstrap.java @@ -67,7 +67,7 @@ public final class Bootstrap { PersistenceUnitTransactionType transactionType, Map integration) { return new EntityManagerFactoryBuilderImpl( - PersistenceXmlParser.parse( persistenceXmlUrl, transactionType, integration ).get( persistenceUnitName ), + PersistenceXmlParser.create( integration ).parse( persistenceXmlUrl, transactionType ).get( persistenceUnitName ), integration ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/JakartaXmlSmokeTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/JakartaXmlSmokeTests.java index bcde884e0a..35970d6719 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/JakartaXmlSmokeTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/JakartaXmlSmokeTests.java @@ -71,7 +71,8 @@ public class JakartaXmlSmokeTests { public void testLoadingPersistenceXml(ServiceRegistryScope scope) { final ClassLoaderService cls = scope.getRegistry().getService( ClassLoaderService.class ); final URL url = cls.locateResource( "xml/jakarta/simple/persistence.xml" ); - final ParsedPersistenceXmlDescriptor descriptor = PersistenceXmlParser.locateIndividualPersistenceUnit( url, Collections.emptyMap() ); + final ParsedPersistenceXmlDescriptor descriptor = PersistenceXmlParser.create() + .locateIndividualPersistenceUnit( url ); assertThat( descriptor.getName() ).isEqualTo( "defaultpar" ); assertThat( descriptor.getManagedClassNames() ).contains( "org.hibernate.jpa.test.pack.defaultpar.Lighter" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/persistenceunit/DuplicatePersistenceUnitNameTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/persistenceunit/DuplicatePersistenceUnitNameTest.java index f8bf9f2d91..a2e179d23a 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/persistenceunit/DuplicatePersistenceUnitNameTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/persistenceunit/DuplicatePersistenceUnitNameTest.java @@ -63,7 +63,7 @@ public class DuplicatePersistenceUnitNameTest extends BaseUnitTestCase { public void testDuplicatePersistenceUnitNameLogAWarnMessage() { final Map properties = new HashMap(); properties.put( AvailableSettings.CLASSLOADERS, Arrays.asList( new TestClassLoader() ) ); - PersistenceXmlParser.locatePersistenceUnits( properties ); + PersistenceXmlParser.create( properties ).locatePersistenceUnits(); assertTrue( "The warn HHH015018 has not been logged ", triggerable.wasTriggered() ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/persistenceunit/ExcludeUnlistedClassesTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/persistenceunit/ExcludeUnlistedClassesTest.java index 83a6e719bb..3712eaef37 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/persistenceunit/ExcludeUnlistedClassesTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/persistenceunit/ExcludeUnlistedClassesTest.java @@ -51,8 +51,8 @@ public class ExcludeUnlistedClassesTest extends BaseUnitTestCase { final Map properties = new HashMap(); properties.put( AvailableSettings.CLASSLOADERS, Arrays.asList( new TestClassLoader() ) ); - final List parsedDescriptors = PersistenceXmlParser.locatePersistenceUnits( - properties ); + final List parsedDescriptors = PersistenceXmlParser.create( properties ) + .locatePersistenceUnits(); doTest( parsedDescriptors, "ExcludeUnlistedClassesTest1", false ); doTest( parsedDescriptors, "ExcludeUnlistedClassesTest2", true );