99import java .io .Serializable ;
1010import java .lang .reflect .Field ;
1111import java .util .ArrayList ;
12+ import java .util .Arrays ;
1213import java .util .Collection ;
1314import java .util .HashMap ;
1415import java .util .HashSet ;
7374import static org .hibernate .metamodel .internal .InjectionHelper .injectTypedQueryReference ;
7475
7576/**
76- *
7777 * @author Steve Ebersole
7878 */
7979public class JpaMetamodelImpl implements JpaMetamodelImplementor , Serializable {
@@ -106,7 +106,7 @@ private ImportInfo(String importedName, Class<T> loadedClass) {
106106 private final Map <Class <?>, String > entityProxyInterfaceMap = new HashMap <>();
107107
108108 private final Map <String , ImportInfo <?>> nameToImportMap = new ConcurrentHashMap <>();
109- private final Map <String ,Object > knownInvalidnameToImportMap = new ConcurrentHashMap <>();
109+ private final Map <String , Object > knownInvalidnameToImportMap = new ConcurrentHashMap <>();
110110
111111
112112 public JpaMetamodelImpl (
@@ -143,13 +143,14 @@ public JpaCompliance getJpaCompliance() {
143143 public <X > ManagedDomainType <X > managedType (String typeName ) {
144144 final ManagedDomainType <X > managedType = findManagedType ( typeName );
145145 if ( managedType == null ) {
146- throw new IllegalArgumentException ("Not a managed type: " + typeName );
146+ throw new IllegalArgumentException ( "Not a managed type: " + typeName );
147147 }
148148 return managedType ;
149149 }
150150
151151 @ Override
152- @ Nullable public EntityDomainType <?> findEntityType (@ Nullable String entityName ) {
152+ @ Nullable
153+ public EntityDomainType <?> findEntityType (@ Nullable String entityName ) {
153154 if ( entityName == null ) {
154155 return null ;
155156 }
@@ -162,18 +163,19 @@ public EntityDomainType<?> entity(String entityName) {
162163 final EntityDomainType <?> entityType = findEntityType ( entityName );
163164 if ( entityType == null ) {
164165 // per JPA
165- throw new IllegalArgumentException ("Not an entity: " + entityName );
166+ throw new IllegalArgumentException ( "Not an entity: " + entityName );
166167 }
167168 return entityType ;
168169 }
169170
170171 @ Override
171- @ Nullable public EmbeddableDomainType <?> findEmbeddableType (@ Nullable String embeddableName ) {
172+ @ Nullable
173+ public EmbeddableDomainType <?> findEmbeddableType (@ Nullable String embeddableName ) {
172174 if ( embeddableName == null ) {
173175 return null ;
174176 }
175177 final ManagedDomainType <?> managedType = managedTypeByName .get ( embeddableName );
176- if ( !( managedType instanceof EmbeddableDomainType <?> embeddableDomainType ) ) {
178+ if ( !(managedType instanceof EmbeddableDomainType <?> embeddableDomainType ) ) {
177179 return null ;
178180 }
179181 return embeddableDomainType ;
@@ -183,7 +185,7 @@ public EntityDomainType<?> entity(String entityName) {
183185 public EmbeddableDomainType <?> embeddable (String embeddableName ) {
184186 final EmbeddableDomainType <?> embeddableType = findEmbeddableType ( embeddableName );
185187 if ( embeddableType == null ) {
186- throw new IllegalArgumentException ("Not an embeddable: " + embeddableName );
188+ throw new IllegalArgumentException ( "Not an embeddable: " + embeddableName );
187189 }
188190 return embeddableType ;
189191 }
@@ -226,7 +228,8 @@ public <X> EntityDomainType<X> resolveHqlEntityReference(String entityName) {
226228 }
227229
228230 @ Override
229- @ Nullable public <X > ManagedDomainType <X > findManagedType (Class <X > cls ) {
231+ @ Nullable
232+ public <X > ManagedDomainType <X > findManagedType (Class <X > cls ) {
230233 //noinspection unchecked
231234 return (ManagedDomainType <X >) managedTypeByClass .get ( cls );
232235 }
@@ -242,9 +245,10 @@ public <X> ManagedDomainType<X> managedType(Class<X> cls) {
242245 }
243246
244247 @ Override
245- @ Nullable public <X > EntityDomainType <X > findEntityType (Class <X > cls ) {
248+ @ Nullable
249+ public <X > EntityDomainType <X > findEntityType (Class <X > cls ) {
246250 final ManagedType <?> type = managedTypeByClass .get ( cls );
247- if ( !( type instanceof EntityDomainType <?> ) ) {
251+ if ( !(type instanceof EntityDomainType <?>) ) {
248252 return null ;
249253 }
250254 //noinspection unchecked
@@ -263,7 +267,7 @@ public <X> EntityDomainType<X> entity(Class<X> cls) {
263267 @ Override
264268 public @ Nullable <X > EmbeddableDomainType <X > findEmbeddableType (Class <X > cls ) {
265269 final ManagedType <?> type = managedTypeByClass .get ( cls );
266- if ( !( type instanceof EmbeddableDomainType <?> ) ) {
270+ if ( !(type instanceof EmbeddableDomainType <?>) ) {
267271 return null ;
268272 }
269273 //noinspection unchecked
@@ -281,7 +285,7 @@ public <X> EmbeddableDomainType<X> embeddable(Class<X> cls) {
281285
282286 private Collection <ManagedDomainType <?>> getAllManagedTypes () {
283287 // should never happen
284- return switch (jpaMetaModelPopulationSetting ) {
288+ return switch ( jpaMetaModelPopulationSetting ) {
285289 case IGNORE_UNSUPPORTED -> managedTypeByClass .values ();
286290 case ENABLED -> managedTypeByName .values ();
287291 case DISABLED -> emptySet ();
@@ -311,7 +315,7 @@ public Set<EmbeddableType<?>> getEmbeddables() {
311315
312316 @ Override
313317 public @ Nullable Set <String > getEnumTypesForValue (String enumValue ) {
314- return allowedEnumLiteralsToEnumTypeNames .get ( enumValue );
318+ return allowedEnumLiteralsToEnumTypeNames .get ( enumValue );
315319 }
316320
317321 @ Override
@@ -388,7 +392,8 @@ public <T> void addNamedEntityGraph(String graphName, RootGraphImplementor<T> en
388392 }
389393 }
390394
391- @ Override @ SuppressWarnings ("unchecked" )
395+ @ Override
396+ @ SuppressWarnings ("unchecked" )
392397 public <T > RootGraphImplementor <T > findEntityGraphByName (String name ) {
393398 return (RootGraphImplementor <T >) entityGraphMap .get ( name );
394399 }
@@ -403,8 +408,8 @@ public <T> List<RootGraphImplementor<? super T>> findEntityGraphsByJavaType(Clas
403408 final List <RootGraphImplementor <? super T >> results = new ArrayList <>();
404409 for ( RootGraphImplementor <?> entityGraph : entityGraphMap .values () ) {
405410 if ( entityGraph .appliesTo ( entityType ) ) {
406- @ SuppressWarnings ("unchecked" )
407- final RootGraphImplementor <? super T > result = (RootGraphImplementor <? super T >) entityGraph ;
411+ @ SuppressWarnings (
412+ "unchecked" ) final RootGraphImplementor <? super T > result = (RootGraphImplementor <? super T >) entityGraph ;
408413 results .add ( result );
409414 }
410415 }
@@ -490,21 +495,54 @@ private void applyNamedEntityGraphs(Collection<NamedEntityGraphDefinition> named
490495 if ( entityType == null ) {
491496 throw new IllegalArgumentException (
492497 "Attempted to register named entity graph [" + definition .getRegisteredName ()
493- + "] for unknown entity [" + definition .getEntityName () + "]"
498+ + "] for unknown entity [" + definition .getEntityName () + "]"
494499
495500 );
496501 }
502+
497503 final NamedEntityGraph namedEntityGraph = definition .getAnnotation ();
498504 final RootGraphImpl <?> entityGraph =
499- createRootGraph ( definition .getRegisteredName (), entityType ,
500- namedEntityGraph .includeAllAttributes () );
501- if ( namedEntityGraph .attributeNodes () != null ) {
502- applyNamedAttributeNodes ( namedEntityGraph .attributeNodes (), namedEntityGraph , entityGraph );
503- }
505+ createEntityGraph (
506+ namedEntityGraph ,
507+ definition .getRegisteredName (),
508+ entityType ,
509+ namedEntityGraph .includeAllAttributes ()
510+ );
511+
504512 entityGraphMap .put ( definition .getRegisteredName (), entityGraph );
505513 }
506514 }
507515
516+ private <T > RootGraphImpl <T > createEntityGraph (
517+ NamedEntityGraph namedEntityGraph ,
518+ String registeredName ,
519+ EntityDomainType <T > entityType ,
520+ boolean includeAllAttributes ) {
521+ final RootGraphImpl <T > entityGraph =
522+ createRootGraph ( registeredName , entityType , includeAllAttributes );
523+
524+ if ( namedEntityGraph .subclassSubgraphs () != null ) {
525+ Arrays
526+ .stream ( namedEntityGraph .subclassSubgraphs () )
527+ .forEach ( subclassSubgraph -> {
528+ GraphImplementor <?> subgraph = (GraphImplementor <?>) entityGraph .addTreatedSubgraph (
529+ (Class ) subclassSubgraph .type () );
530+
531+ applyNamedAttributeNodes (
532+ subclassSubgraph .attributeNodes (),
533+ namedEntityGraph ,
534+ subgraph
535+ );
536+ } );
537+ }
538+
539+ if ( namedEntityGraph .attributeNodes () != null ) {
540+ applyNamedAttributeNodes ( namedEntityGraph .attributeNodes (), namedEntityGraph , entityGraph );
541+ }
542+
543+ return entityGraph ;
544+ }
545+
508546 private static <T > RootGraphImpl <T > createRootGraph (
509547 String name , EntityDomainType <T > entityType , boolean includeAllAttributes ) {
510548 final RootGraphImpl <T > entityGraph = new RootGraphImpl <>( name , entityType );
@@ -521,31 +559,42 @@ private void applyNamedAttributeNodes(
521559 NamedEntityGraph namedEntityGraph ,
522560 GraphImplementor <?> graphNode ) {
523561 for ( NamedAttributeNode namedAttributeNode : namedAttributeNodes ) {
524- final AttributeNodeImplementor <?> attributeNode =
525- graphNode .findOrCreateAttributeNode ( namedAttributeNode .value () );
562+ final String value = namedAttributeNode .value ();
563+ AttributeNodeImplementor <?> attributeNode = (AttributeNodeImplementor <?>) graphNode .addAttributeNode (
564+ value );
565+
526566 if ( isNotEmpty ( namedAttributeNode .subgraph () ) ) {
527567 applyNamedSubgraphs (
528568 namedEntityGraph ,
529569 namedAttributeNode .subgraph (),
530- attributeNode .makeSubGraph ()
570+ attributeNode ,
571+ false
531572 );
532573 }
533574 if ( isNotEmpty ( namedAttributeNode .keySubgraph () ) ) {
534575 applyNamedSubgraphs (
535576 namedEntityGraph ,
536577 namedAttributeNode .keySubgraph (),
537- attributeNode .makeKeySubGraph ()
578+ attributeNode ,
579+ true
538580 );
539581 }
540582 }
541583 }
542584
543- private void applyNamedSubgraphs (
585+ @ SuppressWarnings ({"unchecked" , "rawtypes" })
586+ private <T > void applyNamedSubgraphs (
544587 NamedEntityGraph namedEntityGraph ,
545588 String subgraphName ,
546- SubGraphImplementor <?> subgraph ) {
589+ AttributeNodeImplementor < T > attributeNode , Boolean isKeySubGraph ) {
547590 for ( NamedSubgraph namedSubgraph : namedEntityGraph .subgraphs () ) {
548591 if ( subgraphName .equals ( namedSubgraph .name () ) ) {
592+ var isDefaultSubgraphType = namedSubgraph .type ().equals ( void .class );
593+ Class subGraphType = isDefaultSubgraphType ? null : namedSubgraph .type ();
594+
595+ SubGraphImplementor <?> subgraph = makeAttributeNodeSubgraph ( attributeNode , isKeySubGraph ,
596+ subGraphType );
597+
549598 applyNamedAttributeNodes (
550599 namedSubgraph .attributeNodes (),
551600 namedEntityGraph ,
@@ -555,6 +604,19 @@ private void applyNamedSubgraphs(
555604 }
556605 }
557606
607+ private static <T > SubGraphImplementor <?> makeAttributeNodeSubgraph (AttributeNodeImplementor <T > attributeNode , Boolean isKeySubGraph , Class <T > subGraphType ) {
608+
609+ if ( isKeySubGraph ) {
610+ return subGraphType != null ? attributeNode .makeKeySubGraph ( subGraphType )
611+ : attributeNode .makeKeySubGraph ();
612+ }
613+
614+ return subGraphType != null ?
615+ attributeNode .makeSubGraph ( subGraphType ) :
616+ attributeNode
617+ .makeSubGraph ();
618+ }
619+
558620 private <X > Class <X > resolveRequestedClass (String entityName ) {
559621 try {
560622 return getServiceRegistry ().requireService ( ClassLoaderService .class )
@@ -609,8 +671,8 @@ public <T> EntityDomainType<T> resolveEntityReference(Class<T> javaType) {
609671 // incorrect results
610672 final ManagedDomainType <?> superType = managedType .getSuperType ();
611673 if ( superType != null
612- && superType .getPersistenceType () == Type .PersistenceType .ENTITY
613- && javaType .isAssignableFrom ( superType .getJavaType () ) ) {
674+ && superType .getPersistenceType () == Type .PersistenceType .ENTITY
675+ && javaType .isAssignableFrom ( superType .getJavaType () ) ) {
614676 continue ;
615677 }
616678
@@ -631,7 +693,8 @@ public <T> EntityDomainType<T> resolveEntityReference(Class<T> javaType) {
631693 }
632694 }
633695
634- throw new EntityTypeException ( "Could not resolve entity class '" + javaType .getName () + "'" , javaType .getName () );
696+ throw new EntityTypeException ( "Could not resolve entity class '" + javaType .getName () + "'" ,
697+ javaType .getName () );
635698 }
636699
637700 @ Override
@@ -719,7 +782,7 @@ private void populateStaticMetamodel(MetadataImplementor bootMetamodel, Metadata
719782 -> injectTypedQueryReference ( definition , namedQueryMetamodelClass ( definition , context ) ) );
720783 bootMetamodel .visitNamedNativeQueryDefinitions ( definition
721784 -> injectTypedQueryReference ( definition , namedQueryMetamodelClass ( definition , context ) ) );
722- bootMetamodel .getNamedEntityGraphs ().values ().forEach (definition
785+ bootMetamodel .getNamedEntityGraphs ().values ().forEach ( definition
723786 -> injectEntityGraph ( definition , graphMetamodelClass ( definition , context ), this ) );
724787 }
725788
@@ -763,8 +826,7 @@ private <T> EntityDomainType<T> locateOrBuildEntityType(
763826 PersistentClass persistentClass ,
764827 MetadataContext context ,
765828 final TypeConfiguration typeConfiguration ) {
766- @ SuppressWarnings ("unchecked" )
767- final EntityDomainType <T > entityType =
829+ @ SuppressWarnings ("unchecked" ) final EntityDomainType <T > entityType =
768830 (EntityDomainType <T >)
769831 context .locateEntityType ( persistentClass );
770832 return entityType == null
@@ -816,8 +878,7 @@ private <T> MappedSuperclassDomainType<T> locateOrBuildMappedSuperclassType(
816878 MappedSuperclass mappedSuperclass ,
817879 MetadataContext context ,
818880 TypeConfiguration typeConfiguration ) {
819- @ SuppressWarnings ("unchecked" )
820- final MappedSuperclassDomainType <T > mappedSuperclassType =
881+ @ SuppressWarnings ("unchecked" ) final MappedSuperclassDomainType <T > mappedSuperclassType =
821882 (MappedSuperclassDomainType <T >)
822883 context .locateMappedSuperclassType ( mappedSuperclass );
823884 return mappedSuperclassType == null
0 commit comments