HHH-18231 Move listing of persistence.xml files out of PersistenceXmlParser

This commit is contained in:
Yoann Rodière 2024-06-05 18:20:09 +02:00 committed by Steve Ebersole
parent 6883aa2ff2
commit 330ad18288
8 changed files with 67 additions and 133 deletions

View File

@ -6,6 +6,10 @@
*/ */
package org.hibernate.jpa; package org.hibernate.jpa;
import static org.hibernate.internal.HEMLogging.messageLogger;
import java.net.URL;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -18,6 +22,7 @@ import jakarta.persistence.spi.PersistenceUnitInfo;
import jakarta.persistence.spi.ProviderUtil; import jakarta.persistence.spi.ProviderUtil;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.internal.EntityManagerMessageLogger;
import org.hibernate.jpa.boot.spi.PersistenceConfigurationDescriptor; import org.hibernate.jpa.boot.spi.PersistenceConfigurationDescriptor;
import org.hibernate.jpa.boot.spi.PersistenceXmlParser; import org.hibernate.jpa.boot.spi.PersistenceXmlParser;
import org.hibernate.jpa.boot.spi.Bootstrap; import org.hibernate.jpa.boot.spi.Bootstrap;
@ -26,8 +31,6 @@ import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
import org.hibernate.jpa.boot.spi.ProviderChecker; import org.hibernate.jpa.boot.spi.ProviderChecker;
import org.hibernate.jpa.internal.util.PersistenceUtilHelper; import org.hibernate.jpa.internal.util.PersistenceUtilHelper;
import org.jboss.logging.Logger;
/** /**
* The best-ever implementation of a JPA {@link PersistenceProvider}. * The best-ever implementation of a JPA {@link PersistenceProvider}.
* *
@ -36,7 +39,7 @@ import org.jboss.logging.Logger;
* @author Brett Meyer * @author Brett Meyer
*/ */
public class HibernatePersistenceProvider implements PersistenceProvider { public class HibernatePersistenceProvider implements PersistenceProvider {
private static final Logger log = Logger.getLogger( HibernatePersistenceProvider.class ); private static final EntityManagerMessageLogger log = messageLogger( HibernatePersistenceProvider.class );
private final PersistenceUtilHelper.MetadataCache cache = new PersistenceUtilHelper.MetadataCache(); private final PersistenceUtilHelper.MetadataCache cache = new PersistenceUtilHelper.MetadataCache();
@ -75,15 +78,7 @@ public class HibernatePersistenceProvider implements PersistenceProvider {
log.tracef( "Attempting to obtain correct EntityManagerFactoryBuilder for persistenceUnitName : %s", persistenceUnitName ); log.tracef( "Attempting to obtain correct EntityManagerFactoryBuilder for persistenceUnitName : %s", persistenceUnitName );
final Map<?,?> integration = wrap( properties ); final Map<?,?> integration = wrap( properties );
final List<PersistenceUnitDescriptor> units; final Collection<PersistenceUnitDescriptor> units = locatePersistenceUnits( integration, providedClassLoader, providedClassLoaderService );
try {
units = PersistenceXmlParser.create( integration, providedClassLoader, providedClassLoaderService )
.locatePersistenceUnits();
}
catch (Exception e) {
log.debug( "Unable to locate persistence units", e );
throw new PersistenceException( "Unable to locate persistence units", e );
}
log.debugf( "Located and parsed %s persistence units; checking each", units.size() ); log.debugf( "Located and parsed %s persistence units; checking each", units.size() );
@ -130,6 +125,28 @@ public class HibernatePersistenceProvider implements PersistenceProvider {
return properties == null ? Collections.emptyMap() : Collections.unmodifiableMap( properties ); return properties == null ? Collections.emptyMap() : Collections.unmodifiableMap( properties );
} }
// Check before changing: may be overridden in Quarkus
protected Collection<PersistenceUnitDescriptor> locatePersistenceUnits(Map<?, ?> integration, ClassLoader providedClassLoader,
ClassLoaderService providedClassLoaderService) {
final Collection<PersistenceUnitDescriptor> units;
try {
var parser = PersistenceXmlParser.create( integration, providedClassLoader, providedClassLoaderService );
final List<URL> xmlUrls = parser.getClassLoaderService().locateResources( "META-INF/persistence.xml" );
if ( xmlUrls.isEmpty() ) {
log.unableToFindPersistenceXmlInClasspath();
units = List.of();
}
else {
units = parser.parse( xmlUrls ).values();
}
}
catch (Exception e) {
log.debug( "Unable to locate persistence units", e );
throw new PersistenceException( "Unable to locate persistence units", e );
}
return units;
}
/** /**
* {@inheritDoc} * {@inheritDoc}
* <p> * <p>

View File

@ -7,6 +7,7 @@
package org.hibernate.jpa.boot.spi; package org.hibernate.jpa.boot.spi;
import java.net.URL; import java.net.URL;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -66,7 +67,7 @@ public final class Bootstrap {
PersistenceUnitTransactionType transactionType, PersistenceUnitTransactionType transactionType,
Map integration) { Map integration) {
return new EntityManagerFactoryBuilderImpl( return new EntityManagerFactoryBuilderImpl(
PersistenceXmlParser.create( integration ).parse( persistenceXmlUrl, transactionType ).get( persistenceUnitName ), PersistenceXmlParser.create( integration ).parse( List.of( persistenceXmlUrl ), transactionType ).get( persistenceUnitName ),
integration integration
); );
} }

View File

@ -118,53 +118,35 @@ public final class PersistenceXmlParser {
} }
/** /**
* Find all persistence-units from all accessible {@code META-INF/persistence.xml} resources * Generic method to parse specified {@code persistence.xml} files and return a Map of descriptors
*
* @return List of descriptors for all discovered persistence-units.
*/
@SuppressWarnings("removal")
public List<PersistenceUnitDescriptor> locatePersistenceUnits() {
Map<String, PersistenceUnitDescriptor> persistenceUnits = new HashMap<>();
final List<URL> xmlUrls = classLoaderService.locateResources( "META-INF/persistence.xml" );
if ( xmlUrls.isEmpty() ) {
LOG.unableToFindPersistenceXmlInClasspath();
}
else {
parsePersistenceXml( persistenceUnits, xmlUrls, PersistenceUnitTransactionType.RESOURCE_LOCAL );
}
return new ArrayList<>( persistenceUnits.values() );
}
/**
* Generic method to parse a specified {@code persistence.xml} and return a Map of descriptors
* for all discovered persistence-units keyed by the PU name. * for all discovered persistence-units keyed by the PU name.
* *
* @param persistenceXmlUrl The URL of the {@code persistence.xml} to parse * @param persistenceXmlUrls The URL of the {@code persistence.xml} files to parse
* *
* @return Map of persistence-unit descriptors keyed by the PU name * @return Map of persistence-unit descriptors keyed by the PU name
*/ */
@SuppressWarnings("removal") @SuppressWarnings("removal")
public Map<String, PersistenceUnitDescriptor> parse(URL persistenceXmlUrl) { public Map<String, PersistenceUnitDescriptor> parse(List<URL> persistenceXmlUrls) {
Map<String, PersistenceUnitDescriptor> persistenceUnits = new HashMap<>(); Map<String, PersistenceUnitDescriptor> persistenceUnits = new HashMap<>();
parsePersistenceXml( persistenceUnits, persistenceXmlUrl, PersistenceUnitTransactionType.RESOURCE_LOCAL ); parsePersistenceXml( persistenceUnits, persistenceXmlUrls, PersistenceUnitTransactionType.RESOURCE_LOCAL );
return persistenceUnits; return persistenceUnits;
} }
/** /**
* Generic method to parse a specified {@code persistence.xml} and return a Map of descriptors * Generic method to parse specified {@code persistence.xml} files and return a Map of descriptors
* for all discovered persistence-units keyed by the PU name. * for all discovered persistence-units keyed by the PU name.
* *
* @param persistenceXmlUrl The URL of the {@code persistence.xml} to parse * @param persistenceXmlUrls The URLs of the {@code persistence.xml} files to parse
* @param transactionType The specific PersistenceUnitTransactionType to incorporate into the persistence-unit descriptor * @param transactionType The specific PersistenceUnitTransactionType to incorporate into the persistence-unit descriptor
* *
* @return Map of persistence-unit descriptors keyed by the PU name * @return Map of persistence-unit descriptors keyed by the PU name
*/ */
public Map<String, PersistenceUnitDescriptor> parse( public Map<String, PersistenceUnitDescriptor> parse(
URL persistenceXmlUrl, List<URL> persistenceXmlUrls,
@SuppressWarnings("removal") @SuppressWarnings("removal")
PersistenceUnitTransactionType transactionType) { PersistenceUnitTransactionType transactionType) {
Map<String, PersistenceUnitDescriptor> persistenceUnits = new HashMap<>(); Map<String, PersistenceUnitDescriptor> persistenceUnits = new HashMap<>();
parsePersistenceXml( persistenceUnits, persistenceXmlUrl, transactionType ); parsePersistenceXml( persistenceUnits, persistenceXmlUrls, transactionType );
return persistenceUnits; return persistenceUnits;
} }

View File

@ -8,6 +8,7 @@ package org.hibernate.orm.test.jpa.compliance;
import java.net.URL; import java.net.URL;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.hibernate.boot.archive.scan.internal.DisabledScanner; import org.hibernate.boot.archive.scan.internal.DisabledScanner;
@ -52,7 +53,7 @@ public class PersistenceUnitNameTests {
private static EntityManagerFactory loadFactory(String name, ServiceRegistryScope scope) { private static EntityManagerFactory loadFactory(String name, ServiceRegistryScope scope) {
final URL puFile = PersistenceUnitNameTests.class.getClassLoader().getResource( "xml/jakarta/simple/2units.xml" ); final URL puFile = PersistenceUnitNameTests.class.getClassLoader().getResource( "xml/jakarta/simple/2units.xml" );
var descriptors = PersistenceXmlParser.create().parse( puFile ); var descriptors = PersistenceXmlParser.create().parse( List.of( puFile ) );
assertThat( descriptors ).containsKey( name ); assertThat( descriptors ).containsKey( name );
final PersistenceUnitDescriptor descriptor = descriptors.get( name ); final PersistenceUnitDescriptor descriptor = descriptors.get( name );
final EntityManagerFactoryBuilder emfBuilder = Bootstrap.getEntityManagerFactoryBuilder( final EntityManagerFactoryBuilder emfBuilder = Bootstrap.getEntityManagerFactoryBuilder(

View File

@ -70,9 +70,8 @@ public class JakartaXmlSmokeTests {
@Test @Test
public void testLoadingPersistenceXml(ServiceRegistryScope scope) { public void testLoadingPersistenceXml(ServiceRegistryScope scope) {
final ClassLoaderService cls = scope.getRegistry().getService( ClassLoaderService.class ); final ClassLoaderService cls = scope.getRegistry().getService( ClassLoaderService.class );
final URL url = cls.locateResource( "xml/jakarta/simple/persistence.xml" );
final Map<String, PersistenceUnitDescriptor> descriptors = PersistenceXmlParser.create() final Map<String, PersistenceUnitDescriptor> descriptors = PersistenceXmlParser.create()
.parse( url ); .parse( cls.locateResources( "xml/jakarta/simple/persistence.xml" ) );
String expectedPuName = "defaultpar"; String expectedPuName = "defaultpar";
assertThat( descriptors ).containsOnlyKeys( expectedPuName ); assertThat( descriptors ).containsOnlyKeys( expectedPuName );
var descriptor = descriptors.get( expectedPuName ); var descriptor = descriptors.get( expectedPuName );

View File

@ -61,32 +61,14 @@ public class DuplicatePersistenceUnitNameTest extends BaseUnitTestCase {
@Test @Test
public void testDuplicatePersistenceUnitNameLogAWarnMessage() { public void testDuplicatePersistenceUnitNameLogAWarnMessage() {
final Map<String, Object> properties = new HashMap<String, Object>(); PersistenceXmlParser.create().parse( List.of(
properties.put( AvailableSettings.CLASSLOADERS, Arrays.asList( new TestClassLoader() ) ); findAsResource(
PersistenceXmlParser.create( properties ).locatePersistenceUnits(); "org/hibernate/jpa/test/persistenceunit/META-INF/persistence.xml"
),
findAsResource(
"org/hibernate/jpa/test/persistenceunit/META-INF/persistenceUnitForNameDuplicationTest.xml"
)
) );
assertTrue( "The warn HHH015018 has not been logged ", triggerable.wasTriggered() ); assertTrue( "The warn HHH015018 has not been logged ", triggerable.wasTriggered() );
} }
private static class TestClassLoader extends ClassLoader {
final List<URL> urls;
public TestClassLoader() {
urls = Arrays.asList(
findAsResource(
"org/hibernate/jpa/test/persistenceunit/META-INF/persistence.xml"
)
,
findAsResource(
"org/hibernate/jpa/test/persistenceunit/META-INF/persistenceUnitForNameDuplicationTest.xml"
)
);
}
@Override
protected Enumeration<URL> findResources(String name) throws IOException {
return name.equals( "META-INF/persistence.xml" ) ?
Collections.enumeration( urls ) :
Collections.emptyEnumeration();
}
}
} }

View File

@ -6,12 +6,14 @@
*/ */
package org.hibernate.orm.test.jpa.persistenceunit; package org.hibernate.orm.test.jpa.persistenceunit;
import static org.hibernate.internal.util.ConfigHelper.findAsResource;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -47,12 +49,9 @@ public class ExcludeUnlistedClassesTest extends BaseUnitTestCase {
@Test @Test
public void testExcludeUnlistedClasses() { public void testExcludeUnlistedClasses() {
// see src/test/resources/org/hibernate/jpa/test/persistenceunit/persistence.xml final Collection<PersistenceUnitDescriptor> parsedDescriptors = PersistenceXmlParser.create()
.parse( List.of( findAsResource( "org/hibernate/jpa/test/persistenceunit/META-INF/persistence.xml" ) ) )
final Map<String, Object> properties = new HashMap<String, Object>(); .values();
properties.put( AvailableSettings.CLASSLOADERS, Arrays.asList( new TestClassLoader() ) );
final List<PersistenceUnitDescriptor> parsedDescriptors = PersistenceXmlParser.create( properties )
.locatePersistenceUnits();
doTest( parsedDescriptors, "ExcludeUnlistedClassesTest1", false ); doTest( parsedDescriptors, "ExcludeUnlistedClassesTest1", false );
doTest( parsedDescriptors, "ExcludeUnlistedClassesTest2", true ); doTest( parsedDescriptors, "ExcludeUnlistedClassesTest2", true );
@ -60,7 +59,7 @@ public class ExcludeUnlistedClassesTest extends BaseUnitTestCase {
doTest( parsedDescriptors, "ExcludeUnlistedClassesTest4", true ); doTest( parsedDescriptors, "ExcludeUnlistedClassesTest4", true );
} }
private void doTest(List<PersistenceUnitDescriptor> parsedDescriptors, private void doTest(Collection<PersistenceUnitDescriptor> parsedDescriptors,
final String persistenceUnitName, final boolean shouldExclude) { final String persistenceUnitName, final boolean shouldExclude) {
for (final PersistenceUnitDescriptor descriptor : parsedDescriptors) { for (final PersistenceUnitDescriptor descriptor : parsedDescriptors) {
if (descriptor.getName().equals( persistenceUnitName )) { if (descriptor.getName().equals( persistenceUnitName )) {
@ -70,32 +69,4 @@ public class ExcludeUnlistedClassesTest extends BaseUnitTestCase {
} }
fail("Could not find the persistence unit: " + persistenceUnitName); fail("Could not find the persistence unit: " + persistenceUnitName);
} }
private static class TestClassLoader extends ClassLoader {
@Override
protected Enumeration<URL> findResources(String name) throws IOException {
if (name.equals( "META-INF/persistence.xml" )) {
final URL puUrl = ConfigHelper.findAsResource(
"org/hibernate/jpa/test/persistenceunit/META-INF/persistence.xml" );
return new Enumeration<URL>() {
boolean hasMore = true;
@Override
public boolean hasMoreElements() {
return hasMore;
}
@Override
public URL nextElement() {
hasMore = false;
return puUrl;
}
};
}
else {
return java.util.Collections.emptyEnumeration();
}
}
}
} }

View File

@ -18,6 +18,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl; import org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.AvailableSettings;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor; import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
@ -48,10 +49,10 @@ public class PersistenceXmlParserTest {
new TestClassLoader( "pu2" ), new TestClassLoader( "pu2" ),
null null
); );
assertThat( parser.getClassLoaderService() ).isNotNull(); ClassLoaderService clService = parser.getClassLoaderService();
assertThat( parser.locatePersistenceUnits() ) assertThat( clService ).isNotNull();
.extracting( PersistenceUnitDescriptor::getName ) assertThat( parser.parse( clService.locateResources( "META-INF/persistence.xml" ) ) )
.containsExactlyInAnyOrder( "pu1", "pu2" ); .containsOnlyKeys( "pu1", "pu2" );
} }
@Test @Test
@ -64,36 +65,16 @@ public class PersistenceXmlParserTest {
new TestClassLoader( "pu2" ), new TestClassLoader( "pu2" ),
myClassLoaderService myClassLoaderService
); );
assertThat( parser.getClassLoaderService() ).isSameAs( myClassLoaderService ); ClassLoaderService clService = parser.getClassLoaderService();
assertThat( parser.locatePersistenceUnits() ) assertThat( clService ).isSameAs( myClassLoaderService );
.extracting( PersistenceUnitDescriptor::getName ) assertThat( parser.parse( clService.locateResources( "META-INF/persistence.xml" ) ) )
.containsExactlyInAnyOrder( "pu3" ); .containsOnlyKeys( "pu3" );
}
@Test
public void locatePersistenceUnits() {
var parser = PersistenceXmlParser.create(
Map.of(),
new TestClassLoader( "pu1" ),
null
);
assertThat( parser.locatePersistenceUnits() )
.singleElement()
.returns( "pu1", PersistenceUnitDescriptor::getName );
}
@Test
public void locatePersistenceUnits_empty() {
var noFileLog = logInspection.watchForLogMessages( "HHH000318" );
var parser = PersistenceXmlParser.create();
assertThat( parser.locatePersistenceUnits() ).isEmpty();
assertThat( noFileLog.wasTriggered() ).isTrue();
} }
@Test @Test
public void parse() { public void parse() {
var parser = PersistenceXmlParser.create(); var parser = PersistenceXmlParser.create();
var result = parser.parse( findPuResource( "multipu" ) ); var result = parser.parse( List.of( findPuResource( "multipu" ) ) );
assertThat( result ) assertThat( result )
.containsOnlyKeys( "multipu1", "multipu2", "multipu3" ); .containsOnlyKeys( "multipu1", "multipu2", "multipu3" );
assertThat( result.get( "multipu1" ) ) assertThat( result.get( "multipu1" ) )
@ -112,7 +93,7 @@ public class PersistenceXmlParserTest {
@Test @Test
public void parse_defaultTransactionType() { public void parse_defaultTransactionType() {
var parser = PersistenceXmlParser.create(); var parser = PersistenceXmlParser.create();
var result = parser.parse( findPuResource( "multipu" ), PersistenceUnitTransactionType.JTA ); var result = parser.parse( List.of( findPuResource( "multipu" ) ), PersistenceUnitTransactionType.JTA );
assertThat( result.get( "multipu1" ) ) assertThat( result.get( "multipu1" ) )
.returns( "multipu1", PersistenceUnitDescriptor::getName ) .returns( "multipu1", PersistenceUnitDescriptor::getName )
.returns( .returns(