From 57edc75ef81b191b51f28589adecad05af259800 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Wed, 28 Aug 2024 23:04:06 +0200 Subject: [PATCH] 97 Add dynamic-class resolution support to MutableClassDetailsRegistry --- .../dynamic/SimpleDynamicModelTests.java | 58 +++++++++++++++++++ .../AbstractClassDetailsRegistry.java | 37 +++++++++++- .../internal/MutableClassDetailsRegistry.java | 18 ++++++ 3 files changed, 112 insertions(+), 1 deletion(-) diff --git a/hibernate-models-jandex/src/test/java/org/hibernate/models/dynamic/SimpleDynamicModelTests.java b/hibernate-models-jandex/src/test/java/org/hibernate/models/dynamic/SimpleDynamicModelTests.java index 8e7d777..7e388cc 100644 --- a/hibernate-models-jandex/src/test/java/org/hibernate/models/dynamic/SimpleDynamicModelTests.java +++ b/hibernate-models-jandex/src/test/java/org/hibernate/models/dynamic/SimpleDynamicModelTests.java @@ -90,6 +90,64 @@ void testSimpleBasics() { checkPersistability( entityDetails.getFields().get( 1 ) ); } + + @Test + void testResolveClassDetails() { + final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( (Index) null ); + final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); + + final ClassDetails integerClassDetails = classDetailsRegistry.getClassDetails( Integer.class.getName() ); + final ClassTypeDetailsImpl integerTypeDetails = new ClassTypeDetailsImpl( integerClassDetails, TypeDetails.Kind.CLASS ); + + final ClassDetails stringClassDetails = classDetailsRegistry.getClassDetails( String.class.getName() ); + final ClassTypeDetailsImpl stringTypeDetails = new ClassTypeDetailsImpl( stringClassDetails, TypeDetails.Kind.CLASS ); + + classDetailsRegistry.as( MutableClassDetailsRegistry.class ) + .resolveClassDetails( "TheEntity", (name) -> new DynamicClassDetails( name, buildingContext ) ); + + final DynamicClassDetails entityDetails = (DynamicClassDetails) classDetailsRegistry.resolveClassDetails( "TheEntity" ); + final Entity created = entityDetails.applyAnnotationUsage( + JpaAnnotations.ENTITY, + buildingContext + ); + final Entity preExisting = entityDetails.applyAnnotationUsage( + JpaAnnotations.ENTITY, + buildingContext + ); + assertThat( created ).isSameAs( preExisting ); + + final DynamicFieldDetails idMember = entityDetails.applyAttribute( + "id", + integerTypeDetails, + false, + false, + buildingContext + ); + final Id first = idMember.applyAnnotationUsage( + JpaAnnotations.ID, + buildingContext + ); + final Id second = idMember.applyAnnotationUsage( + JpaAnnotations.ID, + buildingContext + ); + assertThat( first ).isSameAs( second ); + + entityDetails.applyAttribute( + "name", + stringTypeDetails, + false, + false, + buildingContext + ); + + assertThat( entityDetails.getFields() ).hasSize( 2 ); + assertThat( entityDetails.getFields().get( 0 ).getName() ).isEqualTo( "id" ); + assertThat( entityDetails.getFields().get( 0 ).hasDirectAnnotationUsage( Id.class ) ).isTrue(); + checkPersistability( entityDetails.getFields().get( 0 ) ); + checkPersistability( entityDetails.getFields().get( 1 ) ); + } + private void checkPersistability(FieldDetails fieldDetails) { assertThat( fieldDetails.isPersistable() ).isTrue(); diff --git a/hibernate-models/src/main/java/org/hibernate/models/internal/AbstractClassDetailsRegistry.java b/hibernate-models/src/main/java/org/hibernate/models/internal/AbstractClassDetailsRegistry.java index a68630a..6c2f136 100644 --- a/hibernate-models/src/main/java/org/hibernate/models/internal/AbstractClassDetailsRegistry.java +++ b/hibernate-models/src/main/java/org/hibernate/models/internal/AbstractClassDetailsRegistry.java @@ -15,7 +15,6 @@ import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.ClassDetailsBuilder; import org.hibernate.models.spi.SourceModelBuildingContext; -import org.hibernate.models.spi.VoidTypeDetails; /** * @author Steve Ebersole @@ -126,4 +125,40 @@ public void addClassDetails(String name, ClassDetails classDetails) { subTypes.add( classDetails ); } } + + @Override + public ClassDetails resolveClassDetails(String name, ClassDetailsCreator creator) { + if ( name == null ) { + throw new IllegalArgumentException( "`name` cannot be null" ); + } + + if ( "void".equals( name ) ) { + return null; + } + + final ClassDetails existing = classDetailsMap.get( name ); + if ( existing != null ) { + return existing; + } + + return createClassDetails( name, creator ); + } + + protected ClassDetails createClassDetails(String name, ClassDetailsCreator creator) { + try { + final ClassDetails created = creator.createClassDetails( name ); + addClassDetails( name, created ); + return created; + } + catch (UnknownClassException e) { + // see if it might be a package name... + try { + return creator.createClassDetails( name + ".package-info" ); + } + catch (UnknownClassException noPackage) { + throw e; + } + } + } + } diff --git a/hibernate-models/src/main/java/org/hibernate/models/internal/MutableClassDetailsRegistry.java b/hibernate-models/src/main/java/org/hibernate/models/internal/MutableClassDetailsRegistry.java index f5ab11b..75be938 100644 --- a/hibernate-models/src/main/java/org/hibernate/models/internal/MutableClassDetailsRegistry.java +++ b/hibernate-models/src/main/java/org/hibernate/models/internal/MutableClassDetailsRegistry.java @@ -7,6 +7,7 @@ package org.hibernate.models.internal; +import org.hibernate.models.UnknownClassException; import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.ClassDetailsRegistry; @@ -24,4 +25,21 @@ public interface MutableClassDetailsRegistry extends ClassDetailsRegistry { * Adds a managed-class descriptor using the given {@code name} as the registration key */ void addClassDetails(String name, ClassDetails classDetails); + + /** + * Resolve (find or create) ClassDetails by name. If there is currently no + * such registration, one is created using the specified {@code creator}. + */ + ClassDetails resolveClassDetails(String name, ClassDetailsCreator creator); + + /** + * Create a CLass Details + */ + @FunctionalInterface + interface ClassDetailsCreator { + /** + * @throws UnknownClassException + */ + ClassDetails createClassDetails(String name) throws UnknownClassException; + } }