Skip to content

Commit d8e1c7a

Browse files
committed
HHH-16548 more flexible / robust way to specify root URL and jar file URLs for PersistenceConfiguration
1 parent 9d958d7 commit d8e1c7a

File tree

4 files changed

+147
-40
lines changed

4 files changed

+147
-40
lines changed

hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/ScanningCoordinator.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,16 @@ private static Scanner buildScanner(BootstrapContext bootstrapContext, ClassLoad
9494
.loadJavaServices( ScannerFactory.class )
9595
.iterator();
9696
if ( iterator.hasNext() ) {
97-
// todo: check for multiple scanner and in case raise a warning?
9897
final ScannerFactory factory = iterator.next();
99-
return factory.getScanner( archiveDescriptorFactory );
98+
final Scanner scanner = factory.getScanner( archiveDescriptorFactory );
99+
if ( iterator.hasNext() ) {
100+
log.warn("Multiple ScannerFactory services available; using '"
101+
+ scanner.getClass().getName() + "'");
102+
}
103+
return scanner;
100104
}
101105
else {
102-
if ( bootstrapContext.getScanOptions().canDetectUnlistedClassesInRoot() ) {
103-
throw new IllegalStateException( "No ScannerFactory available"
104-
+ " (add 'hibernate-scan-jandex' dependency or disable 'hibernate.archive.autodetection')" );
105-
}
106+
log.debug("No ScannerFactory available; add 'hibernate-scan-jandex' dependency to enable scanning");
106107
return new DisabledScanner();
107108
}
108109
}

hibernate-core/src/main/java/org/hibernate/jpa/HibernatePersistenceConfiguration.java

Lines changed: 117 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44
*/
55
package org.hibernate.jpa;
66

7+
import java.net.URL;
8+
import java.util.ArrayList;
79
import java.util.Collection;
810
import java.util.Collections;
11+
import java.util.List;
912
import java.util.Map;
1013
import java.util.Objects;
1114

@@ -17,6 +20,7 @@
1720
import org.hibernate.cfg.JdbcSettings;
1821
import org.hibernate.cfg.JpaComplianceSettings;
1922
import org.hibernate.cfg.MappingSettings;
23+
import org.hibernate.cfg.PersistenceSettings;
2024
import org.hibernate.cfg.SchemaToolingSettings;
2125
import org.hibernate.cfg.StatisticsSettings;
2226
import org.hibernate.resource.jdbc.spi.StatementInspector;
@@ -67,11 +71,12 @@
6771
* <li>properties specified in {@code hibernate.properties}.
6872
* </ul>
6973
* <p>
70-
* When {@linkplain org.hibernate.cfg.PersistenceSettings#SCANNER_DISCOVERY
71-
* entity discovery} is explicitly enabled, and {@code hibernate-scan-jandex}
72-
* or some other {@link org.hibernate.boot.archive.scan.spi.ScannerFactory}
73-
* service is available, the current working directly is scanned for entity
74-
* classes, alleviating the program of the need to call {@link #managedClass}.
74+
* When a {@linkplain #rootUrl() root URL} is supplied, or when at least
75+
* one {@linkplain #jarFileUrls() JAR file URL} is supplied, and when
76+
* {@code hibernate-scan-jandex} or some other service implementing
77+
* {@link org.hibernate.boot.archive.scan.spi.ScannerFactory} is available,
78+
* the current working directly is scanned for entity classes, alleviating
79+
* the program of the need to call {@link #managedClass}.
7580
*
7681
* @apiNote The specification explicitly encourages implementors to extend
7782
* {@link PersistenceConfiguration} to accommodate vendor-specific
@@ -84,6 +89,10 @@
8489
* @since 7.0
8590
*/
8691
public class HibernatePersistenceConfiguration extends PersistenceConfiguration {
92+
93+
private URL rootUrl;
94+
private final List<URL> jarFileUrls = new ArrayList<>();
95+
8796
/**
8897
* Create a new empty configuration. An empty configuration does not
8998
* typically hold enough information for successful invocation of
@@ -96,6 +105,49 @@ public HibernatePersistenceConfiguration(String name) {
96105
super( name );
97106
}
98107

108+
/**
109+
* Create a new empty configuration with a given {@linkplain #rootUrl root URL}
110+
* used for {@linkplain PersistenceSettings#SCANNER_DISCOVERY entity discovery}
111+
* via scanning.
112+
* <p>
113+
* The module {@code hibernate-scan-jandex} must be added as a dependency,
114+
* or some other implementation of the service
115+
* {@link org.hibernate.boot.archive.scan.spi.ScannerFactory} must be made
116+
* available.
117+
*
118+
* @param name the name of the persistence unit, which may be used by
119+
* the persistence provider for logging and error reporting
120+
* @param rootURL the root URL of the persistence unit
121+
*
122+
* @since 7.1
123+
*/
124+
public HibernatePersistenceConfiguration(String name, URL rootURL) {
125+
super( name );
126+
this.rootUrl = rootURL;
127+
}
128+
129+
/**
130+
* Create a new empty configuration with the {@linkplain #rootUrl root URL}
131+
* inferred from the given class file and used for
132+
* {@linkplain PersistenceSettings#SCANNER_DISCOVERY entity discovery}
133+
* via scanning.
134+
* <p>
135+
* The module {@code hibernate-scan-jandex} must be added as a dependency,
136+
* or some other implementation of the service
137+
* {@link org.hibernate.boot.archive.scan.spi.ScannerFactory} must be made
138+
* available.
139+
*
140+
* @param name the name of the persistence unit, which may be used by
141+
* the persistence provider for logging and error reporting
142+
* @param classFromRootUrl a class loaded from the root URL of the
143+
* persistence unit
144+
*
145+
* @since 7.1
146+
*/
147+
public HibernatePersistenceConfiguration(String name, Class<?> classFromRootUrl) {
148+
this( name, classFromRootUrl.getProtectionDomain().getCodeSource().getLocation() );
149+
}
150+
99151
/**
100152
* Create a new {@link SessionFactory} based on this configuration.
101153
*/
@@ -464,7 +516,7 @@ public HibernatePersistenceConfiguration managedClasses(Collection<Class<?>> man
464516
/**
465517
* Add the specified resource names as {@linkplain #mappingFiles() mapping files}.
466518
*
467-
* @see #mappingFiles
519+
* @see #mappingFiles()
468520
*/
469521
public HibernatePersistenceConfiguration mappingFiles(String... names) {
470522
Collections.addAll( mappingFiles(), names );
@@ -474,13 +526,43 @@ public HibernatePersistenceConfiguration mappingFiles(String... names) {
474526
/**
475527
* Add the specified resource names as {@linkplain #mappingFiles() mapping files}.
476528
*
477-
* @see #mappingFiles
529+
* @see #mappingFiles()
478530
*/
479531
public HibernatePersistenceConfiguration mappingFiles(Collection<String> names) {
480532
mappingFiles().addAll( names );
481533
return this;
482534
}
483535

536+
/**
537+
* Add the specified URL as a {@linkplain #jarFileUrls() JAR file}.
538+
*
539+
* @see #jarFileUrls()
540+
*/
541+
public HibernatePersistenceConfiguration jarFileUrl(URL url) {
542+
jarFileUrls.add( url );
543+
return this;
544+
}
545+
546+
/**
547+
* Add the specified URLs as {@linkplain #jarFileUrls() JAR files}.
548+
*
549+
* @see #jarFileUrls()
550+
*/
551+
public HibernatePersistenceConfiguration jarFileUrls(URL... urls) {
552+
Collections.addAll( jarFileUrls, urls );
553+
return this;
554+
}
555+
556+
/**
557+
* Add the specified URLs as {@linkplain #jarFileUrls() JAR files}.
558+
*
559+
* @see #jarFileUrls()
560+
*/
561+
public HibernatePersistenceConfiguration jarFileUrls(Collection<URL> urls) {
562+
jarFileUrls.addAll( urls );
563+
return this;
564+
}
565+
484566
/**
485567
* Specify the {@linkplain Action action} to take in terms of automatic
486568
* database schema tooling.
@@ -549,4 +631,32 @@ public HibernatePersistenceConfiguration property(String name, Object value) {
549631
public HibernatePersistenceConfiguration properties(Map<String, ?> properties) {
550632
return (HibernatePersistenceConfiguration) super.properties( properties );
551633
}
634+
635+
/**
636+
* URLs of JAR files.
637+
* When {@linkplain org.hibernate.cfg.PersistenceSettings#SCANNER_DISCOVERY
638+
* entity discovery} is enabled, the JAR files will be scanned for entities.
639+
*
640+
* @see org.hibernate.cfg.PersistenceSettings#SCANNER_DISCOVERY
641+
* @see jakarta.persistence.spi.PersistenceUnitInfo#getJarFileUrls
642+
*
643+
* @since 7.1
644+
*/
645+
public List<URL> jarFileUrls() {
646+
return jarFileUrls;
647+
}
648+
649+
/**
650+
* Root URL of the persistence unit.
651+
* When {@linkplain org.hibernate.cfg.PersistenceSettings#SCANNER_DISCOVERY
652+
* entity discovery} is enabled, this root URL will be scanned for entities.
653+
*
654+
* @see org.hibernate.cfg.PersistenceSettings#SCANNER_DISCOVERY
655+
* @see jakarta.persistence.spi.PersistenceUnitInfo#getPersistenceUnitRootUrl
656+
*
657+
* @since 7.1
658+
*/
659+
public URL rootUrl() {
660+
return rootUrl;
661+
}
552662
}

hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/PersistenceConfigurationDescriptor.java

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
*/
55
package org.hibernate.jpa.boot.spi;
66

7-
import java.io.File;
8-
import java.net.MalformedURLException;
97
import java.net.URL;
108
import java.util.List;
119
import java.util.Properties;
@@ -14,6 +12,7 @@
1412
import org.hibernate.bytecode.spi.ClassTransformer;
1513
import org.hibernate.cfg.AvailableSettings;
1614
import org.hibernate.internal.util.collections.CollectionHelper;
15+
import org.hibernate.jpa.HibernatePersistenceConfiguration;
1716
import org.hibernate.jpa.HibernatePersistenceProvider;
1817

1918
import jakarta.persistence.PersistenceConfiguration;
@@ -61,8 +60,9 @@ public boolean isUseQuotedIdentifiers() {
6160

6261
@Override
6362
public boolean isExcludeUnlistedClasses() {
64-
// because we do not know the root url nor jar files we cannot do scanning
65-
return true;
63+
// if we do not know the root url nor jar files we cannot do scanning
64+
return !(persistenceConfiguration instanceof HibernatePersistenceConfiguration configuration)
65+
|| configuration.rootUrl() == null && configuration.jarFileUrls().isEmpty();
6666
}
6767

6868
@Override @SuppressWarnings("removal")
@@ -127,18 +127,15 @@ public ClassTransformer getClassTransformer() {
127127

128128
@Override
129129
public URL getPersistenceUnitRootUrl() {
130-
// When hibernate.archive.autodetection=class
131-
// scan the CWD for entities (useful for tests)
132-
try {
133-
return new File( System.getProperty("user.dir") ).toURI().toURL();
134-
}
135-
catch ( MalformedURLException e ) {
136-
return null;
137-
}
130+
return persistenceConfiguration instanceof HibernatePersistenceConfiguration configuration
131+
? configuration.rootUrl()
132+
: null;
138133
}
139134

140135
@Override
141136
public List<URL> getJarFileUrls() {
142-
return null;
137+
return persistenceConfiguration instanceof HibernatePersistenceConfiguration configuration
138+
? configuration.jarFileUrls()
139+
: null;
143140
}
144141
}

hibernate-scan-jandex/src/main/java/org/hibernate/archive/scan/spi/AbstractScannerImpl.java

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import java.net.URL;
88
import java.util.HashMap;
9+
import java.util.List;
910
import java.util.Map;
1011

1112
import org.hibernate.archive.scan.internal.NoopEntryHandler;
@@ -37,18 +38,19 @@ protected AbstractScannerImpl(ArchiveDescriptorFactory archiveDescriptorFactory)
3738
public ScanResult scan(ScanEnvironment environment, ScanOptions options, ScanParameters parameters) {
3839
final ScanResultCollector collector = new ScanResultCollector( environment, options, parameters );
3940

40-
if ( environment.getNonRootUrls() != null ) {
41+
final List<URL> nonRootUrls = environment.getNonRootUrls();
42+
if ( nonRootUrls != null ) {
4143
final ArchiveContext context = new ArchiveContextImpl( false, collector );
42-
for ( URL url : environment.getNonRootUrls() ) {
43-
final ArchiveDescriptor descriptor = buildArchiveDescriptor( url, environment, false );
44-
descriptor.visitArchive( context );
44+
for ( URL url : nonRootUrls ) {
45+
buildArchiveDescriptor( url, environment, false )
46+
.visitArchive( context );
4547
}
4648
}
4749

48-
if ( environment.getRootUrl() != null ) {
49-
final ArchiveContext context = new ArchiveContextImpl( true, collector );
50-
final ArchiveDescriptor descriptor = buildArchiveDescriptor( environment.getRootUrl(), environment, true );
51-
descriptor.visitArchive( context );
50+
final URL rootUrl = environment.getRootUrl();
51+
if ( rootUrl != null ) {
52+
buildArchiveDescriptor( rootUrl, environment, true )
53+
.visitArchive( new ArchiveContextImpl( true, collector ) );
5254
}
5355

5456
return collector.toScanResult();
@@ -62,14 +64,11 @@ private ArchiveDescriptor buildArchiveDescriptor(
6264
final ArchiveDescriptor descriptor;
6365
final ArchiveDescriptorInfo descriptorInfo = archiveDescriptorCache.get( url );
6466
if ( descriptorInfo == null ) {
65-
if ( !isRootUrl && archiveDescriptorFactory instanceof JarFileEntryUrlAdjuster ) {
66-
url = ( (JarFileEntryUrlAdjuster) archiveDescriptorFactory ).adjustJarFileEntryUrl( url, environment.getRootUrl() );
67+
if ( !isRootUrl && archiveDescriptorFactory instanceof JarFileEntryUrlAdjuster jarFileEntryUrlAdjuster ) {
68+
url = jarFileEntryUrlAdjuster.adjustJarFileEntryUrl( url, environment.getRootUrl() );
6769
}
6870
descriptor = archiveDescriptorFactory.buildArchiveDescriptor( url );
69-
archiveDescriptorCache.put(
70-
url,
71-
new ArchiveDescriptorInfo( descriptor, isRootUrl )
72-
);
71+
archiveDescriptorCache.put( url, new ArchiveDescriptorInfo( descriptor, isRootUrl ) );
7372
}
7473
else {
7574
validateReuse( descriptorInfo, isRootUrl );

0 commit comments

Comments
 (0)