Skip to content

Commit d42a0ec

Browse files
committed
Prototype bootstrapping for ORM 9 based on this work
- More work on bootstrapping orchestration
1 parent c9ac8ad commit d42a0ec

15 files changed

Lines changed: 545 additions & 148 deletions

design/orm-bootstrap-direction.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ The intended flow is:
4848
----
4949
PersistenceUnitDescriptor / HibernatePersistenceConfiguration
5050
-> JpaBootstrapSourceCollector
51+
-> BootstrapSourceContributions
5152
-> AvailableResources
5253
-> DomainModelCategorizer
5354
-> BindingCoordinator
@@ -89,7 +90,7 @@ Inputs:
8990

9091
Output:
9192

92-
* raw source contributions, not yet categorized
93+
* `BootstrapSourceContributions`: source contributions after entry-point source discovery, including scanner results, not yet categorized
9394

9495
== AvailableResources
9596

design/session-factory-bootstrap-plan.adoc

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -265,20 +265,26 @@ The first orchestration shell is:
265265
* link:../src/main/java/org/hibernate/boot/orchestration/SessionFactoryBootstrap.java[`SessionFactoryBootstrap`]
266266
* link:../src/main/java/org/hibernate/boot/orchestration/SessionFactoryBootstrapRequest.java[`SessionFactoryBootstrapRequest`]
267267

268-
The request is intentionally narrow for now:
268+
The request is intentionally early-input oriented for now:
269269

270270
[source,java]
271271
----
272272
record SessionFactoryBootstrapRequest(
273-
AvailableResources availableResources,
274-
MetadataBuildingContext metadataBuildingContext)
273+
BootstrapSourceContributions sourceContributions,
274+
Map<String, Object> configurationValues,
275+
boolean jpaBootstrap,
276+
FetchType defaultToOneFetchType,
277+
ServiceRegistry serviceRegistry)
275278
----
276279

277280
`SessionFactoryBootstrap#buildMetadata` currently owns the phase order:
278281

279282
[source]
280283
----
281-
AvailableResources
284+
BootstrapSourceContributions + configuration values + ServiceRegistry
285+
-> ResolvedBootstrapSettings
286+
-> MetadataBuildingContext
287+
-> AvailableResources
282288
-> DomainModelCategorizer
283289
-> BindingCoordinator
284290
-> order columns

src/main/java/org/hibernate/boot/models/source/AvailableResources.java

Lines changed: 85 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.util.Collection;
1212
import java.util.Collections;
1313
import java.util.List;
14+
import java.util.Map;
1415

1516
import jakarta.persistence.PersistenceConfiguration;
1617
import org.checkerframework.checker.nullness.qual.NonNull;
@@ -20,13 +21,11 @@
2021
import org.hibernate.boot.jaxb.internal.MappingBinder;
2122
import org.hibernate.boot.jaxb.spi.Binding;
2223
import org.hibernate.boot.jaxb.spi.JaxbBindableMappingDescriptor;
23-
import org.hibernate.boot.scan.spi.ScanningResult;
2424
import org.hibernate.boot.settings.BootstrapSettingsResolver;
2525
import org.hibernate.boot.settings.ResolvedBootstrapSettings;
2626
import org.hibernate.internal.util.StringHelper;
2727
import org.hibernate.jpa.HibernatePersistenceConfiguration;
2828
import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
29-
import org.hibernate.models.spi.ModelsContext;
3029
import org.hibernate.models.spi.ClassDetails;
3130

3231
/// Model resources available to categorization.
@@ -77,6 +76,27 @@ public Collection<Binding<? extends JaxbBindableMappingDescriptor>> xmlMappings(
7776
public static AvailableResources from(
7877
PersistenceUnitDescriptor persistenceUnitDescriptor,
7978
AvailableResourcesContext context) {
79+
return from(
80+
persistenceUnitDescriptor,
81+
context,
82+
new BootstrapSettingsResolver().resolve( persistenceUnitDescriptor, Map.of() )
83+
);
84+
}
85+
86+
/// Creates available resources from Hibernate's descriptor for persistence-unit
87+
/// information.
88+
///
89+
/// Managed class names are resolved through the supplied model context. Mapping
90+
/// file names are located through the bootstrap class-loading service and bound
91+
/// immediately when XML mappings are enabled.
92+
///
93+
/// @param persistenceUnitDescriptor The persistence-unit wrapper
94+
/// @param context Context used to resolve model details and load resources
95+
/// @param bootstrapSettings Resolved bootstrap settings used during source collection
96+
public static AvailableResources from(
97+
PersistenceUnitDescriptor persistenceUnitDescriptor,
98+
AvailableResourcesContext context,
99+
ResolvedBootstrapSettings bootstrapSettings) {
80100
var classLoading = context.getClassLoaderService();
81101
var classDetailsRegistry = context.modelsContext().getClassDetailsRegistry();
82102

@@ -93,7 +113,8 @@ public static AvailableResources from(
93113
} );
94114

95115
final List<Binding<? extends JaxbBindableMappingDescriptor>> xmlBindings;
96-
if ( persistenceUnitDescriptor.getMappingFileNames().isEmpty() ) {
116+
if ( !bootstrapSettings.mappingSettings().xmlMappingEnabled()
117+
|| persistenceUnitDescriptor.getMappingFileNames().isEmpty() ) {
97118
xmlBindings = Collections.emptyList();
98119
}
99120
else {
@@ -119,9 +140,9 @@ public static AvailableResources from(
119140
/// Creates available resources from Hibernate's JPA
120141
/// {@link HibernatePersistenceConfiguration} extension.
121142
///
122-
/// Explicit managed classes and mapping files are included. Archive scanning is
123-
/// applied here based on [HibernatePersistenceConfiguration#rootUrl()] and
124-
/// [HibernatePersistenceConfiguration#jarFileUrls()].
143+
/// The configuration is first adapted to [BootstrapSourceContributions], which
144+
/// includes archive scanning based on [HibernatePersistenceConfiguration#rootUrl()]
145+
/// and [HibernatePersistenceConfiguration#jarFileUrls()].
125146
///
126147
/// @param persistenceConfiguration The PersistenceConfiguration
127148
/// @param context Context used to resolve model details and load resources
@@ -138,9 +159,9 @@ public static AvailableResources from(
138159
/// Creates available resources from Hibernate's JPA
139160
/// {@link HibernatePersistenceConfiguration} extension.
140161
///
141-
/// Explicit managed classes and mapping files are included. Archive scanning is
142-
/// applied here based on [HibernatePersistenceConfiguration#rootUrl()] and
143-
/// [HibernatePersistenceConfiguration#jarFileUrls()].
162+
/// The configuration is first adapted to [BootstrapSourceContributions], which
163+
/// includes archive scanning based on [HibernatePersistenceConfiguration#rootUrl()]
164+
/// and [HibernatePersistenceConfiguration#jarFileUrls()].
144165
///
145166
/// @param persistenceConfiguration The PersistenceConfiguration
146167
/// @param context Context used to resolve model details and load resources
@@ -149,45 +170,75 @@ public static AvailableResources from(
149170
HibernatePersistenceConfiguration persistenceConfiguration,
150171
AvailableResourcesContext context,
151172
ResolvedBootstrapSettings bootstrapSettings) {
173+
return from(
174+
BootstrapSourceContributions.from(
175+
persistenceConfiguration,
176+
bootstrapSettings,
177+
context.getClassLoaderService()
178+
),
179+
context,
180+
bootstrapSettings
181+
);
182+
}
183+
184+
/// Creates available resources from neutral bootstrap source contributions.
185+
///
186+
/// Explicit and discovered managed classes, package metadata, and mapping files
187+
/// are included. Source discovery, including archive scanning, is expected to
188+
/// have already happened before these contributions are consumed.
189+
///
190+
/// @param sourceContributions Source declarations from a bootstrap entry point
191+
/// @param context Context used to resolve model details and load resources
192+
/// @param bootstrapSettings Resolved bootstrap settings used during source collection
193+
public static AvailableResources from(
194+
BootstrapSourceContributions sourceContributions,
195+
AvailableResourcesContext context,
196+
ResolvedBootstrapSettings bootstrapSettings) {
152197
final var classLoading = context.getClassLoaderService();
153198
final var classDetailsRegistry = context.modelsContext().getClassDetailsRegistry();
154199
final var mappingFileBinder = context.createMappingBinder();
155200

156201
var managedClassDetails = new ArrayList<ClassDetails>();
157202
var packageDetailsList = new ArrayList<ClassDetails>();
158-
persistenceConfiguration.managedClasses().forEach( (managedClass) -> {
203+
sourceContributions.managedClasses().forEach( (managedClass) -> {
159204
applyClassDetails(
160205
classDetailsRegistry.resolveClassDetails( managedClass.getName() ),
161206
managedClassDetails,
162207
packageDetailsList
163208
);
164209
} );
165-
166-
final ScanningResult scanningResult = HibernatePersistenceConfigurationScanner.performScanning(
167-
persistenceConfiguration,
168-
bootstrapSettings,
169-
classLoading
170-
);
171-
applyDiscoveredClassDetails(
172-
scanningResult,
173-
context.modelsContext(),
174-
managedClassDetails,
175-
packageDetailsList
176-
);
210+
sourceContributions.managedClassNames().forEach( (managedClassName) -> {
211+
applyClassDetails(
212+
classDetailsRegistry.resolveClassDetails( managedClassName ),
213+
managedClassDetails,
214+
packageDetailsList
215+
);
216+
} );
217+
sourceContributions.packageNames().forEach( (packageName) -> {
218+
applyClassDetails(
219+
classDetailsRegistry.resolveClassDetails( packageName + ".package-info" ),
220+
managedClassDetails,
221+
packageDetailsList
222+
);
223+
} );
177224

178225
final var xmlBindings = new ArrayList<Binding<? extends JaxbBindableMappingDescriptor>>();
179-
persistenceConfiguration.mappingFiles().forEach( (mappingFile) -> {
180-
try (var mappingFileStream = classLoading.locateResourceStream( mappingFile )) {
181-
xmlBindings.add( mappingFileBinder.bind(
182-
mappingFileStream,
183-
new Origin( SourceType.RESOURCE, mappingFile )
184-
) );
185-
}
186-
catch (IOException e) {
187-
throw new RuntimeException( "Error accessing mapping file - " + mappingFile, e );
188-
}
189-
} );
190-
applyDiscoveredXmlMappings( scanningResult, mappingFileBinder, xmlBindings );
226+
if ( bootstrapSettings.mappingSettings().xmlMappingEnabled() ) {
227+
sourceContributions.mappingFiles().forEach( (mappingFile) -> {
228+
try (var mappingFileStream = classLoading.locateResourceStream( mappingFile )) {
229+
xmlBindings.add( mappingFileBinder.bind(
230+
mappingFileStream,
231+
new Origin( SourceType.RESOURCE, mappingFile )
232+
) );
233+
}
234+
catch (IOException e) {
235+
throw new RuntimeException( "Error accessing mapping file - " + mappingFile, e );
236+
}
237+
} );
238+
sourceContributions.mappingFileUris().forEach( (mappingFileUri) -> {
239+
xmlBindings.add( bindMappingFile( mappingFileUri, mappingFileBinder ) );
240+
} );
241+
}
191242

192243
return new AvailableResources( managedClassDetails, packageDetailsList, xmlBindings );
193244
}
@@ -302,37 +353,6 @@ else if ( classDetails.getClassName().endsWith( "package-info" ) ) {
302353
}
303354
}
304355

305-
private static void applyDiscoveredClassDetails(
306-
ScanningResult scanningResult,
307-
ModelsContext modelsContext,
308-
Collection<ClassDetails> managedClassDetails,
309-
Collection<ClassDetails> packageDetailsList) {
310-
var classDetailsRegistry = modelsContext.getClassDetailsRegistry();
311-
scanningResult.discoveredClasses().forEach( (className) -> {
312-
applyClassDetails(
313-
classDetailsRegistry.resolveClassDetails( className ),
314-
managedClassDetails,
315-
packageDetailsList
316-
);
317-
} );
318-
scanningResult.discoveredPackages().forEach( (packageName) -> {
319-
applyClassDetails(
320-
classDetailsRegistry.resolveClassDetails( packageName + ".package-info" ),
321-
managedClassDetails,
322-
packageDetailsList
323-
);
324-
} );
325-
}
326-
327-
private static void applyDiscoveredXmlMappings(
328-
ScanningResult scanningResult,
329-
MappingBinder mappingFileBinder,
330-
Collection<Binding<? extends JaxbBindableMappingDescriptor>> xmlBindings) {
331-
scanningResult.mappingFiles().forEach( (mappingFile) -> {
332-
xmlBindings.add( bindMappingFile( mappingFile, mappingFileBinder ) );
333-
} );
334-
}
335-
336356
private static Binding<? extends JaxbBindableMappingDescriptor> bindMappingFile(
337357
URI mappingFile,
338358
MappingBinder mappingFileBinder) {
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.boot.models.source;
6+
7+
import java.net.URI;
8+
import java.util.Collection;
9+
import java.util.List;
10+
11+
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
12+
import org.hibernate.boot.scan.spi.ScanningResult;
13+
import org.hibernate.boot.settings.ResolvedBootstrapSettings;
14+
import org.hibernate.jpa.HibernatePersistenceConfiguration;
15+
16+
/// Mapping-source contributions collected from a bootstrap entry point.
17+
///
18+
/// This type intentionally carries source declarations only: managed classes,
19+
/// discovered class and package names, and XML mappings. Settings resolution
20+
/// remains a separate concern handled by the orchestration layer, and scanning is
21+
/// performed by entry-point adapters before this descriptor is consumed.
22+
///
23+
/// @author Steve Ebersole
24+
public record BootstrapSourceContributions(
25+
/// Managed Java classes explicitly contributed by the entry point.
26+
List<Class<?>> managedClasses,
27+
28+
/// Managed Java class names discovered or explicitly contributed without
29+
/// loading the class.
30+
List<String> managedClassNames,
31+
32+
/// Package names discovered or explicitly contributed for package-level
33+
/// metadata.
34+
List<String> packageNames,
35+
36+
/// XML mapping resources explicitly contributed by the entry point.
37+
List<String> mappingFiles,
38+
39+
/// XML mapping files discovered during archive scanning.
40+
List<URI> mappingFileUris) {
41+
42+
public BootstrapSourceContributions {
43+
managedClasses = managedClasses == null ? List.of() : List.copyOf( managedClasses );
44+
managedClassNames = managedClassNames == null ? List.of() : List.copyOf( managedClassNames );
45+
packageNames = packageNames == null ? List.of() : List.copyOf( packageNames );
46+
mappingFiles = mappingFiles == null ? List.of() : List.copyOf( mappingFiles );
47+
mappingFileUris = mappingFileUris == null ? List.of() : List.copyOf( mappingFileUris );
48+
}
49+
50+
public BootstrapSourceContributions(
51+
Collection<Class<?>> managedClasses,
52+
Collection<String> mappingFiles) {
53+
this( managedClasses, List.of(), List.of(), mappingFiles, List.of() );
54+
}
55+
56+
public BootstrapSourceContributions(
57+
Collection<Class<?>> managedClasses,
58+
Collection<String> managedClassNames,
59+
Collection<String> packageNames,
60+
Collection<String> mappingFiles,
61+
Collection<URI> mappingFileUris) {
62+
this(
63+
managedClasses == null ? List.of() : List.copyOf( managedClasses ),
64+
managedClassNames == null ? List.of() : List.copyOf( managedClassNames ),
65+
packageNames == null ? List.of() : List.copyOf( packageNames ),
66+
mappingFiles == null ? List.of() : List.copyOf( mappingFiles ),
67+
mappingFileUris == null ? List.of() : List.copyOf( mappingFileUris )
68+
);
69+
}
70+
71+
/// Adapts Hibernate's programmatic JPA bootstrap configuration to neutral
72+
/// source contributions, including archive scanning.
73+
public static BootstrapSourceContributions from(
74+
HibernatePersistenceConfiguration persistenceConfiguration,
75+
ResolvedBootstrapSettings bootstrapSettings,
76+
ClassLoaderService classLoaderService) {
77+
final ScanningResult scanningResult = HibernatePersistenceConfigurationScanner.performScanning(
78+
persistenceConfiguration,
79+
bootstrapSettings,
80+
classLoaderService
81+
);
82+
return new BootstrapSourceContributions(
83+
persistenceConfiguration.managedClasses(),
84+
scanningResult.discoveredClasses(),
85+
scanningResult.discoveredPackages(),
86+
persistenceConfiguration.mappingFiles(),
87+
scanningResult.mappingFiles()
88+
);
89+
}
90+
}

0 commit comments

Comments
 (0)