HHH-17460 - Ongoing JPA 32 work

- org.hibernate.boot.spi.AdditionalMappingContributions.contributeManagedClass
This commit is contained in:
Steve Ebersole 2024-03-25 19:58:55 -05:00
parent 66d03336db
commit 05b01d10cb
5 changed files with 126 additions and 1 deletions

View File

@ -653,6 +653,7 @@ public class MetadataBuildingProcess {
private final EntityHierarchyBuilder hierarchyBuilder = new EntityHierarchyBuilder();
private List<Class<?>> additionalEntityClasses;
private List<ClassDetails> additionalClassDetails;
private List<JaxbEntityMappingsImpl> additionalJaxbMappings;
private boolean extraHbmXml = false;
@ -681,6 +682,17 @@ public class MetadataBuildingProcess {
additionalEntityClasses.add( entityType );
}
@Override
public void contributeManagedClass(ClassDetails classDetails) {
if ( additionalClassDetails == null ) {
additionalClassDetails = new ArrayList<>();
}
additionalClassDetails.add( classDetails );
metadataCollector.getSourceModelBuildingContext()
.getClassDetailsRegistry()
.addClassDetails( classDetails );
}
@Override
public void contributeBinding(InputStream xmlStream) {
final Origin origin = new Origin( SourceType.INPUT_STREAM, null );
@ -752,6 +764,7 @@ public class MetadataBuildingProcess {
if ( additionalEntityClasses != null || additionalJaxbMappings != null ) {
AnnotationMetadataSourceProcessorImpl.processAdditionalMappings(
additionalEntityClasses,
additionalClassDetails,
additionalJaxbMappings,
rootMetadataBuildingContext,
options

View File

@ -19,20 +19,25 @@ import org.hibernate.boot.jaxb.spi.Binding;
import org.hibernate.boot.jaxb.spi.JaxbBindableMappingDescriptor;
import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
import org.hibernate.boot.model.process.spi.ManagedResources;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.models.spi.ClassDetails;
/**
* @author Steve Ebersole
*/
public class AdditionalManagedResourcesImpl implements ManagedResources {
private final Collection<Class<?>> knownClasses;
private final Collection<ClassDetails> classDetails;
private final Collection<String> packageNames;
private final Collection<Binding<JaxbBindableMappingDescriptor>> xmlMappings;
public AdditionalManagedResourcesImpl(
Collection<Class<?>> knownClasses,
Collection<ClassDetails> classDetails,
Collection<String> packageNames,
Collection<Binding<JaxbBindableMappingDescriptor>> xmlMappings) {
this.knownClasses = knownClasses;
this.classDetails = classDetails;
this.packageNames = packageNames;
this.xmlMappings = xmlMappings;
}
@ -49,6 +54,9 @@ public class AdditionalManagedResourcesImpl implements ManagedResources {
@Override
public Collection<String> getAnnotatedClassNames() {
if ( CollectionHelper.isNotEmpty( classDetails ) ) {
return classDetails.stream().map( ClassDetails::getName ).toList();
}
return Collections.emptyList();
}
@ -76,6 +84,7 @@ public class AdditionalManagedResourcesImpl implements ManagedResources {
private final MappingBinder mappingBinder;
private List<Class<?>> classes;
private List<ClassDetails> classDetails;
private List<String> packageNames;
private Collection<Binding<JaxbBindableMappingDescriptor>> xmlMappings;
@ -116,6 +125,16 @@ public class AdditionalManagedResourcesImpl implements ManagedResources {
return this;
}
public Builder addClassDetails(List<ClassDetails> additionalClassDetails) {
if ( additionalClassDetails != null ) {
if ( this.classDetails == null ) {
this.classDetails = new ArrayList<>();
}
this.classDetails.addAll( additionalClassDetails );
}
return this;
}
public Builder addPackages(String... packageNames) {
if ( this.packageNames == null ) {
this.packageNames = new ArrayList<>();
@ -125,7 +144,7 @@ public class AdditionalManagedResourcesImpl implements ManagedResources {
}
public ManagedResources build() {
return new AdditionalManagedResourcesImpl( classes, packageNames, xmlMappings );
return new AdditionalManagedResourcesImpl( classes, classDetails, packageNames, xmlMappings );
}
public Builder addXmlMappings(String resourceName) {

View File

@ -115,11 +115,13 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc
*/
public static void processAdditionalMappings(
List<Class<?>> additionalClasses,
List<ClassDetails> additionalClassDetails,
List<JaxbEntityMappingsImpl> additionalJaxbMappings,
MetadataBuildingContextRootImpl rootMetadataBuildingContext,
MetadataBuildingOptions options) {
final AdditionalManagedResourcesImpl.Builder mrBuilder = new AdditionalManagedResourcesImpl.Builder();
mrBuilder.addLoadedClasses( additionalClasses );
mrBuilder.addClassDetails( additionalClassDetails );
for ( JaxbEntityMappingsImpl additionalJaxbMapping : additionalJaxbMappings ) {
mrBuilder.addXmlBinding( new Binding<>( additionalJaxbMapping, new Origin( OTHER, "additional" ) ) );
}

View File

@ -14,6 +14,7 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl;
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
import org.hibernate.boot.model.relational.Sequence;
import org.hibernate.mapping.Table;
import org.hibernate.models.spi.ClassDetails;
/**
* Collector for contributions from {@linkplain AdditionalMappingContributor contributors}
@ -29,6 +30,11 @@ public interface AdditionalMappingContributions {
*/
void contributeEntity(Class<?> entityType);
/**
* Contribute a ClassDetails representing a "managed class" (entity, embeddable, converter, etc)
*/
void contributeManagedClass(ClassDetails classDetails);
/**
* Contribute mappings from the InputStream containing an XML mapping document.
*/

View File

@ -11,11 +11,18 @@ import java.io.InputStream;
import java.util.List;
import org.hibernate.boot.ResourceStreamLocator;
import org.hibernate.boot.models.JpaAnnotations;
import org.hibernate.boot.spi.AdditionalMappingContributions;
import org.hibernate.boot.spi.AdditionalMappingContributor;
import org.hibernate.boot.spi.InFlightMetadataCollector;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.models.internal.jdk.JdkClassDetails;
import org.hibernate.models.spi.ClassDetails;
import org.hibernate.models.spi.ClassDetailsRegistry;
import org.hibernate.models.spi.FieldDetails;
import org.hibernate.models.spi.MutableAnnotationUsage;
import org.hibernate.models.spi.MutableMemberDetails;
import org.hibernate.testing.orm.junit.BootstrapServiceRegistry;
import org.hibernate.testing.orm.junit.BootstrapServiceRegistry.JavaService;
@ -61,6 +68,32 @@ public class AdditionalMappingContributorTests {
} );
}
@Test
void verifyClassDetailsContributions(DomainModelScope domainModelScope, SessionFactoryScope sessionFactoryScope) {
{
final PersistentClass binding = domainModelScope.getDomainModel().getEntityBinding( Entity4.class.getName() );
assertThat( binding ).isNotNull();
assertThat( binding.getIdentifierProperty() ).isNotNull();
assertThat( binding.getProperties() ).hasSize( 1 );
}
{
final PersistentClass binding = domainModelScope.getDomainModel().getEntityBinding( Entity5.class.getName() );
assertThat( binding ).isNotNull();
assertThat( binding.getIdentifierProperty() ).isNotNull();
assertThat( binding.getProperties() ).hasSize( 1 );
}
sessionFactoryScope.inTransaction( (session) -> {
final List<?> results4 = session.createSelectionQuery( "from Entity4" ).list();
assertThat( results4 ).hasSize( 0 );
final List<?> results5 = session.createSelectionQuery( "from ___Entity5___" ).list();
assertThat( results5 ).hasSize( 0 );
} );
}
@Test
void verifyOrmXmlContribution(DomainModelScope domainModelScope, SessionFactoryScope sessionFactoryScope) {
final PersistentClass binding = domainModelScope.getDomainModel().getEntityBinding( Entity3.class.getName() );
@ -165,6 +198,19 @@ public class AdditionalMappingContributorTests {
}
}
@Entity(name="Entity4")
@Table(name="Entity4")
public static class Entity4 {
@Id
private Integer id;
private String name;
}
public static class Entity5 {
private Integer id;
private String name;
}
public static class AdditionalMappingContributorImpl implements AdditionalMappingContributor {
@Override
public void contribute(
@ -174,6 +220,45 @@ public class AdditionalMappingContributorTests {
MetadataBuildingContext buildingContext) {
contributions.contributeEntity( Entity2.class );
final ClassDetailsRegistry classDetailsRegistry = buildingContext.getMetadataCollector()
.getSourceModelBuildingContext()
.getClassDetailsRegistry();
final ClassDetails entity4Details = classDetailsRegistry.resolveClassDetails(
Entity4.class.getName(),
(name, modelBuildingContext) -> {
assertThat( name ).isEqualTo( Entity4.class.getName() );
assertThat( modelBuildingContext ).isSameAs( buildingContext.getMetadataCollector().getSourceModelBuildingContext() );
return new JdkClassDetails( Entity4.class, modelBuildingContext );
}
);
contributions.contributeManagedClass( entity4Details );
final ClassDetails entity5Details = classDetailsRegistry.resolveClassDetails(
Entity5.class.getName(),
(name, modelBuildingContext) -> {
assertThat( name ).isEqualTo( Entity5.class.getName() );
assertThat( modelBuildingContext ).isSameAs( buildingContext.getMetadataCollector().getSourceModelBuildingContext() );
final JdkClassDetails jdkClassDetails = new JdkClassDetails(
Entity5.class,
modelBuildingContext
);
final MutableAnnotationUsage<Entity> entityAnnotation = JpaAnnotations.ENTITY.createUsage(
jdkClassDetails,
modelBuildingContext
);
entityAnnotation.setAttributeValue( "name", "___Entity5___" );
jdkClassDetails.addAnnotationUsage( entityAnnotation );
final MutableMemberDetails idField = (MutableMemberDetails) jdkClassDetails.findFieldByName( "id" );
idField.addAnnotationUsage( JpaAnnotations.ID.createUsage( idField, modelBuildingContext ) );
return jdkClassDetails;
}
);
contributions.contributeManagedClass( entity5Details );
try ( final InputStream stream = resourceStreamLocator.locateResourceStream( "mappings/intg/contributed-mapping.xml" ) ) {
contributions.contributeBinding( stream );
}