Skip to content

HHH-19610 make GraphParser support subTypeSubGraph #10521

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,28 @@ package org.hibernate.grammars.graph;
*/
}


graph
: typeIndicator? attributeList
;
: typeIndicator? graphElementList
;

graphElementList
: graphElement (COMMA graphElement)*
;

graphElement
: attributeNode
| subTypeSubGraph
;

typeIndicator
: TYPE_NAME COLON
;

subTypeSubGraph
: LPAREN typeIndicator attributeList RPAREN
;


attributeList
: attributeNode (COMMA attributeNode)*
;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public <T> EntityDomainType<T> resolveEntityName(String entityName) {
//noinspection unchecked
final EntityDomainType<T> entityDomainType = (EntityDomainType<T>) entityDomainNameResolver.apply( jpaEntityName );
final String name = this.name == null ? jpaEntityName : this.name;
return GraphParsing.parse( name, entityDomainType, graphContext.attributeList(), entityNameResolver );
return GraphParsing.parse( name, entityDomainType, graphContext.graphElementList(), entityNameResolver );
}
else {
if ( graphContext.typeIndicator() != null ) {
Expand All @@ -77,7 +77,7 @@ public <T> EntityDomainType<T> resolveEntityName(String entityName) {
//noinspection unchecked
final EntityDomainType<T> entityDomainType = (EntityDomainType<T>) entityDomainClassResolver.apply( (Class<T>) entityType );
final String name = this.name == null ? entityDomainType.getName() : this.name;
return GraphParsing.parse( name, entityDomainType, graphContext.attributeList(), entityNameResolver );
return GraphParsing.parse( name, entityDomainType, graphContext.graphElementList(), entityNameResolver );
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@
package org.hibernate.graph.internal.parse;

import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.ManagedDomainType;

/**
* @author Steve Ebersole
*/
@FunctionalInterface
public interface EntityNameResolver {
<T> EntityDomainType<T> resolveEntityName(String entityName);

static <T> ManagedDomainType<T> managedType(String subtypeName, EntityNameResolver entityNameResolver) {
final EntityDomainType<T> entityDomainType = entityNameResolver.resolveEntityName( subtypeName );
if ( entityDomainType == null ) {
throw new IllegalArgumentException( "Unknown managed type: " + subtypeName );
}
return entityDomainType;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class GraphParser extends GraphLanguageParserBaseVisitor<GraphNode<?>> {
private final EntityNameResolver entityNameResolver;

private final Stack<GraphImplementor<?>> graphStack = new StandardStack<>();
private final Stack<AttributeNodeImplementor<?,?,?>> attributeNodeStack = new StandardStack<>();
private final Stack<AttributeNodeImplementor<?, ?, ?>> attributeNodeStack = new StandardStack<>();
private final Stack<SubGraphGenerator> graphSourceStack = new StandardStack<>();

public GraphParser(EntityNameResolver entityNameResolver) {
Expand All @@ -37,7 +37,6 @@ public GraphParser(EntityNameResolver entityNameResolver) {
/**
* @apiNote It is important that this form only be used after the session-factory is fully
* initialized, especially the {@linkplain SessionFactoryImplementor#getJpaMetamodel()} JPA metamodel}.
*
* @see GraphParser#GraphParser(EntityNameResolver)
*/
public GraphParser(SessionFactoryImplementor sessionFactory) {
Expand All @@ -49,7 +48,50 @@ public Stack<GraphImplementor<?>> getGraphStack() {
}

@Override
public AttributeNodeImplementor<?,?,?> visitAttributeNode(GraphLanguageParser.AttributeNodeContext attributeNodeContext) {
public SubGraphImplementor<?> visitSubTypeSubGraph(GraphLanguageParser.SubTypeSubGraphContext subTypeSubGraphContext) {
final String subTypeName = subTypeSubGraphContext.typeIndicator() == null ?
null :
subTypeSubGraphContext.typeIndicator().TYPE_NAME().getText();

if ( PARSING_LOGGER.isDebugEnabled() ) {
PARSING_LOGGER.debugf(
"%s Starting subtype graph : %s",
StringHelper.repeat( ">>", attributeNodeStack.depth() + 2 ),
subTypeName
);
}

var currentGraph = graphStack.getCurrent();

var subTypeSubGraph = currentGraph.addTreatedSubgraph(
EntityNameResolver.managedType(
subTypeName,
entityNameResolver
)
);

graphStack.push( subTypeSubGraph );

try {
subTypeSubGraphContext.attributeList().accept( this );
}
finally {
graphStack.pop();
}

if ( PARSING_LOGGER.isDebugEnabled() ) {
PARSING_LOGGER.debugf(
"%s Finished subtype graph : %s",
StringHelper.repeat( "<<", attributeNodeStack.depth() + 2 ),
subTypeSubGraph.getGraphedType().getTypeName()
);
}

return subTypeSubGraph;
}

@Override
public AttributeNodeImplementor<?, ?, ?> visitAttributeNode(GraphLanguageParser.AttributeNodeContext attributeNodeContext) {
final String attributeName = attributeNodeContext.attributePath().ATTR_NAME().getText();

final SubGraphGenerator subGraphCreator;
Expand All @@ -66,7 +108,10 @@ public AttributeNodeImplementor<?,?,?> visitAttributeNode(GraphLanguageParser.At
subGraphCreator = PathQualifierType.VALUE.getSubGraphCreator();
}
else {
final String qualifierName = attributeNodeContext.attributePath().attributeQualifier().ATTR_NAME().getText();
final String qualifierName = attributeNodeContext.attributePath()
.attributeQualifier()
.ATTR_NAME()
.getText();

if ( PARSING_LOGGER.isDebugEnabled() ) {
PARSING_LOGGER.debugf(
Expand All @@ -81,7 +126,7 @@ public AttributeNodeImplementor<?,?,?> visitAttributeNode(GraphLanguageParser.At
subGraphCreator = pathQualifierType.getSubGraphCreator();
}

final AttributeNodeImplementor<?,?,?> attributeNode = resolveAttributeNode( attributeName );
final AttributeNodeImplementor<?, ?, ?> attributeNode = resolveAttributeNode( attributeName );

if ( attributeNodeContext.subGraph() != null ) {
attributeNodeStack.push( attributeNode );
Expand All @@ -108,11 +153,11 @@ public AttributeNodeImplementor<?,?,?> visitAttributeNode(GraphLanguageParser.At
return attributeNode;
}

private AttributeNodeImplementor<?,?,?> resolveAttributeNode(String attributeName) {
private AttributeNodeImplementor<?, ?, ?> resolveAttributeNode(String attributeName) {
final GraphImplementor<?> currentGraph = graphStack.getCurrent();
assert currentGraph != null;

final AttributeNodeImplementor<?,?,?> attributeNode = currentGraph.findOrCreateAttributeNode( attributeName );
final AttributeNodeImplementor<?, ?, ?> attributeNode = currentGraph.findOrCreateAttributeNode( attributeName );
assert attributeNode != null;

return attributeNode;
Expand All @@ -132,7 +177,9 @@ private PathQualifierType resolvePathQualifier(String qualifier) {

@Override
public SubGraphImplementor<?> visitSubGraph(GraphLanguageParser.SubGraphContext subGraphContext) {
final String subTypeName = subGraphContext.typeIndicator() == null ? null : subGraphContext.typeIndicator().TYPE_NAME().getText();
final String subTypeName = subGraphContext.typeIndicator() == null ?
null :
subGraphContext.typeIndicator().TYPE_NAME().getText();

if ( PARSING_LOGGER.isDebugEnabled() ) {
PARSING_LOGGER.debugf(
Expand All @@ -142,7 +189,7 @@ public SubGraphImplementor<?> visitSubGraph(GraphLanguageParser.SubGraphContext
);
}

final AttributeNodeImplementor<?,?,?> attributeNode = attributeNodeStack.getCurrent();
final AttributeNodeImplementor<?, ?, ?> attributeNode = attributeNodeStack.getCurrent();
final SubGraphGenerator subGraphCreator = graphSourceStack.getCurrent();

final SubGraphImplementor<?> subGraph = subGraphCreator.createSubGraph(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.checkerframework.checker.nullness.qual.Nullable;

import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.grammars.graph.GraphLanguageLexer;
import org.hibernate.grammars.graph.GraphLanguageParser;
Expand Down Expand Up @@ -41,7 +42,7 @@ public static <T> RootGraphImplementor<T> parse(
}

final EntityDomainType<T> entityType = sessionFactory.getJpaMetamodel().entity( entityClass );
return parse( entityType, graphContext.attributeList(), sessionFactory );
return parse( entityType, graphContext.graphElementList(), sessionFactory );
}

public static <T> RootGraphImplementor<T> parse(
Expand All @@ -62,7 +63,7 @@ public static <T> RootGraphImplementor<T> parse(
throw new InvalidGraphException( "Expecting graph text to not include an entity name : " + graphText );
}

return parse( entityDomainType, graphContext.attributeList(), sessionFactory );
return parse( entityDomainType, graphContext.graphElementList(), sessionFactory );
}

public static <T> RootGraphImplementor<T> parse(
Expand All @@ -84,8 +85,9 @@ public static <T> RootGraphImplementor<T> parse(
}

//noinspection unchecked
final EntityDomainType<T> entityType = (EntityDomainType<T>) sessionFactory.getJpaMetamodel().entity( entityName );
return parse( entityType, graphContext.attributeList(), sessionFactory );
final EntityDomainType<T> entityType = (EntityDomainType<T>) sessionFactory.getJpaMetamodel()
.entity( entityName );
return parse( entityType, graphContext.graphElementList(), sessionFactory );
}

public static <T> RootGraphImplementor<T> parse(
Expand All @@ -106,35 +108,36 @@ public static <T> RootGraphImplementor<T> parse(
final String entityName = graphContext.typeIndicator().TYPE_NAME().getText();

//noinspection unchecked
final EntityDomainType<T> entityType = (EntityDomainType<T>) sessionFactory.getJpaMetamodel().entity( entityName );
return parse( entityType, graphContext.attributeList(), sessionFactory );
final EntityDomainType<T> entityType = (EntityDomainType<T>) sessionFactory.getJpaMetamodel()
.entity( entityName );
return parse( entityType, graphContext.graphElementList(), sessionFactory );
}

public static <T> RootGraphImplementor<T> parse(
EntityDomainType<T> rootType,
GraphLanguageParser.AttributeListContext attributeListContext,
GraphLanguageParser.GraphElementListContext graphElementListContext,
SessionFactoryImplementor sessionFactory) {
return parse( rootType, attributeListContext, new EntityNameResolverSessionFactory( sessionFactory ) );
return parse( rootType, graphElementListContext, new EntityNameResolverSessionFactory( sessionFactory ) );
}

public static <T> RootGraphImplementor<T> parse(
EntityDomainType<T> rootType,
GraphLanguageParser.AttributeListContext attributeListContext,
GraphLanguageParser.GraphElementListContext graphElementListContext,
EntityNameResolver entityNameResolver) {
return parse( null, rootType, attributeListContext, entityNameResolver );
return parse( null, rootType, graphElementListContext, entityNameResolver );
}

public static <T> RootGraphImplementor<T> parse(
@Nullable String name,
EntityDomainType<T> rootType,
GraphLanguageParser.AttributeListContext attributeListContext,
GraphLanguageParser.GraphElementListContext graphElementListContext,
EntityNameResolver entityNameResolver) {
final RootGraphImpl<T> targetGraph = new RootGraphImpl<>( name, rootType );

final GraphParser visitor = new GraphParser( entityNameResolver );
visitor.getGraphStack().push( targetGraph );
try {
visitor.visitAttributeList( attributeListContext );
visitor.visitGraphElementList( graphElementListContext );
}
finally {
visitor.getGraphStack().pop();
Expand Down Expand Up @@ -167,7 +170,7 @@ public static void parseInto(

visitor.getGraphStack().push( targetGraph );
try {
visitor.visitAttributeList( graphContext.attributeList() );
visitor.visitGraphElementList( graphContext.graphElementList() );
}
finally {
visitor.getGraphStack().pop();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
package org.hibernate.graph.internal.parse;


import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.ManagedDomainType;
import static org.hibernate.graph.internal.parse.EntityNameResolver.managedType;

/**
* @author Steve Ebersole
Expand All @@ -23,14 +22,6 @@ public enum PathQualifierType {
: attributeNode.addValueSubgraph().addTreatedSubgraph( managedType( subtypeName, entityNameResolver ) )
);

private static <T> ManagedDomainType<T> managedType(String subtypeName, EntityNameResolver entityNameResolver) {
final EntityDomainType<T> entityDomainType = entityNameResolver.resolveEntityName( subtypeName );
if ( entityDomainType == null ) {
throw new IllegalArgumentException( "Unknown managed type: " + subtypeName );
}
return entityDomainType;
}

private final SubGraphGenerator subGraphCreator;

PathQualifierType(SubGraphGenerator subgraphCreator) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,45 @@ public void testLinkParsing() {
AssertionHelper.assertBasicAttributes( sub.get( GraphParsingTestEntity.class ), "name", "description" );
}

@Test
public void testSubtypeAndTwoBasicAttributesParsing() {
var graph = parseGraph( "name, (GraphParsingTestSubEntity:sub), description" );
assertNotNull( graph );

AssertionHelper.assertBasicAttributes( graph, "name", "description" );

var treatedSubgraphs = graph.getTreatedSubgraphs();
assertEquals( 1, treatedSubgraphs.size() );

var subEntityGraph = treatedSubgraphs.get( GraphParsingTestSubEntity.class );
var subEntityGraphAttributes = subEntityGraph.getAttributeNodes();
assertNotNull( subEntityGraphAttributes );
assertEquals( 1, subEntityGraphAttributes.size() );

var subEntityGraphAttributeNode = subEntityGraphAttributes.get( 0 );
assertNotNull( subEntityGraphAttributeNode );
assertEquals( "sub", subEntityGraphAttributeNode.getAttributeName() );
}

@Test
public void testSubtypeParsing() {
var graph = parseGraph( "(GraphParsingTestSubEntity:sub)" );
assertNotNull( graph );

var treatedSubgraphs = graph.getTreatedSubgraphs();
assertEquals( 1, treatedSubgraphs.size() );

var subEntityGraph = treatedSubgraphs.get( GraphParsingTestSubEntity.class );
var subEntityGraphAttributes = subEntityGraph.getAttributeNodes();

assertNotNull( subEntityGraphAttributes );
assertEquals( 1, subEntityGraphAttributes.size() );

var attributeNode = subEntityGraphAttributes.get( 0 );
assertNotNull( attributeNode );
assertEquals( "sub", attributeNode.getAttributeName() );
}

@Test
public void testMapKeyParsing() {
EntityGraph<GraphParsingTestEntity> graph = parseGraph( "map.key(name, description)" );
Expand Down Expand Up @@ -173,14 +212,15 @@ public void testMixParsingWithSimplifiedMaps() {

@Test
public void testLinkSubtypeParsing() {
RootGraphImplementor<GraphParsingTestEntity> graph = parseGraph( "linkToOne(name, description), linkToOne(GraphParsingTestSubEntity: sub)" );
RootGraphImplementor<GraphParsingTestEntity> graph = parseGraph(
"linkToOne(name, description), linkToOne(GraphParsingTestSubEntity: sub)" );
assertNotNull( graph );

List<? extends AttributeNodeImplementor<?,?,?>> attrs = graph.getAttributeNodeList();
List<? extends AttributeNodeImplementor<?, ?, ?>> attrs = graph.getAttributeNodeList();
assertNotNull( attrs );
assertEquals( 1, attrs.size() );

AttributeNodeImplementor<?,?,?> linkToOneNode = attrs.get( 0 );
AttributeNodeImplementor<?, ?, ?> linkToOneNode = attrs.get( 0 );
assertNotNull( linkToOneNode );
assertEquals( "linkToOne", linkToOneNode.getAttributeName() );

Expand All @@ -204,7 +244,7 @@ public void testHHH10378IsNotFixedYet() {

assertEquals( subGraph.getGraphedType().getJavaType(), GraphParsingTestSubEntity.class );

final AttributeNodeImplementor<?,?,?> subTypeAttrNode = subGraph.findOrCreateAttributeNode( "sub" );
final AttributeNodeImplementor<?, ?, ?> subTypeAttrNode = subGraph.findOrCreateAttributeNode( "sub" );
assert subTypeAttrNode != null;
}

Expand All @@ -221,7 +261,10 @@ public void testHHH12696MapSubgraphsKeyFirst() {
checkMapKeyAndValueSubgraphs( graph, mapAttributeName, keySubgraph, valueSubgraph );
}

private void checkMapKeyAndValueSubgraphs(EntityGraph<GraphParsingTestEntity> graph, final String mapAttributeName, Subgraph<GraphParsingTestEntity> keySubgraph,
private void checkMapKeyAndValueSubgraphs(
EntityGraph<GraphParsingTestEntity> graph,
final String mapAttributeName,
Subgraph<GraphParsingTestEntity> keySubgraph,
Subgraph<GraphParsingTestEntity> valueSubgraph) {
int count = 0;
for ( AttributeNode<?> node : graph.getAttributeNodes() ) {
Expand Down