Skip to content

Commit 4d9e0dd

Browse files
committed
HHH-19610 make GraphParser support subTypeSubGraph
1 parent 9bf7773 commit 4d9e0dd

File tree

18 files changed

+418
-78
lines changed

18 files changed

+418
-78
lines changed

hibernate-core/src/main/antlr/org/hibernate/grammars/graph/GraphLanguageParser.g4

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,32 @@ package org.hibernate.grammars.graph;
2121
*/
2222
}
2323

24-
2524
graph
26-
: typeIndicator? attributeList
27-
;
25+
: typeIndicator? graphElementList
26+
;
27+
28+
graphElementList
29+
: graphElement (COMMA graphElement)*
30+
;
31+
32+
33+
graphElement
34+
: treatedSubGraph
35+
| attributeNode
36+
;
37+
38+
treatedSubGraph
39+
: subTypeIndicator LPAREN attributeList RPAREN
40+
;
2841

2942
typeIndicator
3043
: TYPE_NAME COLON
3144
;
3245

46+
subTypeIndicator
47+
: COLON TYPE_NAME
48+
;
49+
3350
attributeList
3451
: attributeNode (COMMA attributeNode)*
3552
;
@@ -47,6 +64,10 @@ attributeQualifier
4764
;
4865

4966
subGraph
50-
: LPAREN typeIndicator? attributeList RPAREN
51-
;
67+
: subGraphWithTypeIndicator
68+
| treatedSubGraph
69+
;
5270

71+
subGraphWithTypeIndicator
72+
: LPAREN typeIndicator? attributeList RPAREN
73+
;

hibernate-core/src/main/java/org/hibernate/annotations/NamedEntityGraph.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@
3939
@Retention(RUNTIME)
4040
@Repeatable(NamedEntityGraphs.class)
4141
public @interface NamedEntityGraph {
42+
43+
/**
44+
* Names the entity that is the root of the {@linkplain #graph graph}.
45+
* When the annotation is applied to a class, the class itself is assumed.
46+
* When applied to a package, this attribute is required.
47+
*/
48+
Class<?> root() default void.class;
49+
4250
/**
4351
* The name used to identify the entity graph in calls to
4452
* {@linkplain org.hibernate.Session#getEntityGraph(String)}.

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

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@
1313
import org.hibernate.grammars.graph.GraphLanguageLexer;
1414
import org.hibernate.grammars.graph.GraphLanguageParser;
1515
import org.hibernate.graph.InvalidGraphException;
16+
import org.hibernate.graph.InvalidNamedEntityGraphParameterException;
1617
import org.hibernate.graph.internal.parse.EntityNameResolver;
1718
import org.hibernate.graph.internal.parse.GraphParsing;
1819
import org.hibernate.graph.spi.RootGraphImplementor;
20+
import org.hibernate.internal.log.DeprecationLogger;
1921
import org.hibernate.metamodel.model.domain.EntityDomainType;
2022

2123
import java.util.function.Function;
@@ -60,24 +62,67 @@ public <T> EntityDomainType<T> resolveEntityName(String entityName) {
6062
}
6163
};
6264

65+
final EntityDomainType<T> entityDomainType = resolveEntityDomainType(
66+
graphContext,
67+
entityDomainClassResolver,
68+
entityDomainNameResolver
69+
);
70+
71+
final String name = this.name == null ? entityDomainType.getName() : this.name;
72+
73+
return GraphParsing.parse( name, entityDomainType, graphContext.graphElementList(), entityNameResolver );
74+
75+
}
76+
77+
private <T> EntityDomainType<T> resolveEntityDomainType(
78+
GraphLanguageParser.GraphContext graphContext,
79+
Function<Class<T>, EntityDomainType<?>> entityDomainClassResolver,
80+
Function<String, EntityDomainType<?>> entityDomainNameResolver) {
81+
var typeIndicator = graphContext.typeIndicator();
82+
final Class<?> annotationRootAttribute = annotation.root();
83+
6384
if ( entityType == null ) {
64-
if ( graphContext.typeIndicator() == null ) {
65-
throw new InvalidGraphException( "Expecting graph text to include an entity name : " + annotation.graph() );
85+
86+
if ( typeIndicator == null && void.class.equals( annotationRootAttribute ) ) {
87+
throw new InvalidNamedEntityGraphParameterException(
88+
"The 'root' parameter of the @NamedEntityGraph should be passed. Graph : " + annotation.name()
89+
);
90+
}
91+
92+
if ( typeIndicator != null ) {
93+
DeprecationLogger.DEPRECATION_LOGGER.deprecatedNamedEntityGraphTextThatContainTypeIndicator();
94+
95+
//noinspection unchecked
96+
return (EntityDomainType<T>) entityDomainNameResolver.apply(
97+
typeIndicator.TYPE_NAME().toString() );
98+
6699
}
67-
final String jpaEntityName = graphContext.typeIndicator().TYPE_NAME().toString();
100+
68101
//noinspection unchecked
69-
final EntityDomainType<T> entityDomainType = (EntityDomainType<T>) entityDomainNameResolver.apply( jpaEntityName );
70-
final String name = this.name == null ? jpaEntityName : this.name;
71-
return GraphParsing.parse( name, entityDomainType, graphContext.attributeList(), entityNameResolver );
102+
return (EntityDomainType<T>) entityDomainClassResolver.apply( (Class<T>) annotationRootAttribute );
72103
}
73-
else {
74-
if ( graphContext.typeIndicator() != null ) {
75-
throw new InvalidGraphException( "Expecting graph text to not include an entity name : " + annotation.graph() );
104+
105+
106+
if ( typeIndicator != null ) {
107+
throw new InvalidGraphException( "Expecting graph text to not include an entity name : " + annotation.graph() );
108+
}
109+
110+
if ( !void.class.equals( annotationRootAttribute ) ) {
111+
112+
if ( !annotationRootAttribute.equals( entityType ) ) {
113+
throw new InvalidNamedEntityGraphParameterException(
114+
"The 'root' parameter of the @NamedEntityGraph annotation must reference the entity '"
115+
+ entityType.getName()
116+
+ "', but '" + annotationRootAttribute.getName() + "' was provided."
117+
+ " Graph :" + annotation.name()
118+
);
76119
}
120+
77121
//noinspection unchecked
78-
final EntityDomainType<T> entityDomainType = (EntityDomainType<T>) entityDomainClassResolver.apply( (Class<T>) entityType );
79-
final String name = this.name == null ? entityDomainType.getName() : this.name;
80-
return GraphParsing.parse( name, entityDomainType, graphContext.attributeList(), entityNameResolver );
122+
return (EntityDomainType<T>) entityDomainClassResolver.apply( (Class<T>) annotationRootAttribute );
81123
}
124+
125+
//noinspection unchecked
126+
return (EntityDomainType<T>) entityDomainClassResolver.apply( (Class<T>) entityType );
82127
}
83128
}

hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/NamedEntityGraphAnnotation.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
public class NamedEntityGraphAnnotation implements NamedEntityGraph {
1818
private String name;
1919
private String graph;
20+
private Class<?> root;
2021

2122
/**
2223
* Used in creating dynamic annotation instances (e.g. from XML)
@@ -31,6 +32,7 @@ public NamedEntityGraphAnnotation(ModelsContext modelContext) {
3132
public NamedEntityGraphAnnotation(NamedEntityGraph annotation, ModelsContext modelContext) {
3233
this.name = annotation.name();
3334
this.graph = annotation.graph();
35+
this.root = annotation.root();
3436
}
3537

3638
/**
@@ -39,13 +41,23 @@ public NamedEntityGraphAnnotation(NamedEntityGraph annotation, ModelsContext mod
3941
public NamedEntityGraphAnnotation(Map<String, Object> attributeValues, ModelsContext modelContext) {
4042
this.name = (String) attributeValues.get( "name" );
4143
this.graph = (String) attributeValues.get( "graph" );
44+
this.root = (Class<?>) attributeValues.get( "root" );
4245
}
4346

4447
@Override
4548
public Class<? extends Annotation> annotationType() {
4649
return NamedEntityGraph.class;
4750
}
4851

52+
@Override
53+
public Class<?> root() {
54+
return this.root;
55+
}
56+
57+
public void root(Class<?> root) {
58+
this.root = root;
59+
}
60+
4961
@Override
5062
public String name() {
5163
return name;

hibernate-core/src/main/java/org/hibernate/graph/GraphParser.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -116,16 +116,18 @@ public static <T> RootGraph<T> parse(
116116
* @see org.hibernate.SessionFactory#parseEntityGraph(Class, CharSequence)
117117
*
118118
* @since 7.0
119+
* @deprecated This usage is deprecated. You must specify the entityType {see {@link #parse(Class, CharSequence, SessionFactory)} or {@link #parse(String, CharSequence, SessionFactory)}
119120
*/
120-
public static <T> RootGraph<T> parse(
121-
final CharSequence graphText,
122-
final SessionFactory sessionFactory) {
123-
if ( graphText == null ) {
124-
return null;
125-
}
126-
return GraphParsing.parse(
127-
graphText.toString(),
128-
sessionFactory.unwrap( SessionFactoryImplementor.class )
121+
@Deprecated(forRemoval = true)
122+
public static <T> RootGraph<T> parse(
123+
final CharSequence graphText,
124+
final SessionFactory sessionFactory) {
125+
if ( graphText == null ) {
126+
return null;
127+
}
128+
return GraphParsing.parse(
129+
graphText.toString(),
130+
sessionFactory.unwrap( SessionFactoryImplementor.class )
129131
);
130132
}
131133

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.graph;
6+
7+
import org.hibernate.HibernateException;
8+
9+
public class InvalidNamedEntityGraphParameterException extends HibernateException {
10+
private static final long serialVersionUID = 1L;
11+
12+
public InvalidNamedEntityGraphParameterException(String message) {
13+
super( message );
14+
}
15+
}

hibernate-core/src/main/java/org/hibernate/graph/internal/parse/EntityNameResolver.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,20 @@
55
package org.hibernate.graph.internal.parse;
66

77
import org.hibernate.metamodel.model.domain.EntityDomainType;
8+
import org.hibernate.metamodel.model.domain.ManagedDomainType;
89

910
/**
1011
* @author Steve Ebersole
1112
*/
1213
@FunctionalInterface
1314
public interface EntityNameResolver {
1415
<T> EntityDomainType<T> resolveEntityName(String entityName);
16+
17+
static <T> ManagedDomainType<T> managedType(String subtypeName, EntityNameResolver entityNameResolver) {
18+
final EntityDomainType<T> entityDomainType = entityNameResolver.resolveEntityName( subtypeName );
19+
if ( entityDomainType == null ) {
20+
throw new IllegalArgumentException( "Unknown managed type: " + subtypeName );
21+
}
22+
return entityDomainType;
23+
}
1524
}

0 commit comments

Comments
 (0)