diff --git a/hibernate-core/src/main/java/org/hibernate/Session.java b/hibernate-core/src/main/java/org/hibernate/Session.java index cd4109bc9a24..d826916f1987 100644 --- a/hibernate-core/src/main/java/org/hibernate/Session.java +++ b/hibernate-core/src/main/java/org/hibernate/Session.java @@ -14,6 +14,7 @@ import jakarta.persistence.metamodel.EntityType; import org.hibernate.graph.RootGraph; import org.hibernate.jdbc.Work; +import org.hibernate.query.NativeQuery; import org.hibernate.query.Query; import org.hibernate.stat.SessionStatistics; @@ -1515,7 +1516,7 @@ public interface Session extends SharedSessionContract, EntityManager { @Override List> getEntityGraphs(Class entityClass); - // The following overrides should not be necessary, + // The following overrides should not be necessary // and are only needed to work around a bug in IntelliJ @Override @@ -1527,6 +1528,9 @@ public interface Session extends SharedSessionContract, EntityManager { @Override @Deprecated @SuppressWarnings("rawtypes") Query createQuery(String queryString); + @Override @Deprecated @SuppressWarnings("rawtypes") + NativeQuery createNativeQuery(String queryString); + @Override Query createNamedQuery(String name, Class resultClass); diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/NamedEntityGraph.java b/hibernate-core/src/main/java/org/hibernate/annotations/NamedEntityGraph.java index aa5aed0ac291..e3b397ff475d 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/NamedEntityGraph.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/NamedEntityGraph.java @@ -45,7 +45,7 @@ * Entity graph names must be unique within the persistence unit. *

* When applied to a root entity class, the name is optional and - * defaults to the entity-name of that entity. + * defaults to the JPA entity name of that entity. */ String name() default ""; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/NamedGraphCreatorParsed.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/NamedGraphCreatorParsed.java index ed0ca3054e50..01b29907259b 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/NamedGraphCreatorParsed.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/NamedGraphCreatorParsed.java @@ -4,14 +4,11 @@ */ package org.hibernate.boot.model.internal; -import org.antlr.v4.runtime.CharStreams; -import org.antlr.v4.runtime.CommonTokenStream; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.UnknownEntityTypeException; import org.hibernate.annotations.NamedEntityGraph; import org.hibernate.boot.model.NamedGraphCreator; -import org.hibernate.grammars.graph.GraphLanguageLexer; import org.hibernate.grammars.graph.GraphLanguageParser; import org.hibernate.graph.InvalidGraphException; import org.hibernate.graph.spi.GraphParserEntityClassResolver; @@ -20,6 +17,7 @@ import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.metamodel.model.domain.EntityDomainType; +import static org.hibernate.graph.internal.parse.GraphParsing.parseText; import static org.hibernate.internal.util.StringHelper.nullIfEmpty; /** @@ -44,36 +42,33 @@ class NamedGraphCreatorParsed implements NamedGraphCreator { public RootGraphImplementor createEntityGraph( GraphParserEntityClassResolver entityDomainClassResolver, GraphParserEntityNameResolver entityDomainNameResolver) { - final var lexer = new GraphLanguageLexer( CharStreams.fromString( annotation.graph() ) ); - final var parser = new GraphLanguageParser( new CommonTokenStream( lexer ) ); - final var graphContext = parser.graph(); - + final var graphContext = parseText( annotation.graph() ); final var typeIndicator = graphContext.typeIndicator(); + final EntityDomainType entityDomainType; + final String jpaEntityName; if ( entityType == null ) { if ( typeIndicator == null ) { - throw new InvalidGraphException( "Expecting graph text to include an entity name : " + annotation.graph() ); + throw new InvalidGraphException( "Expecting graph text to include an entity name: " + annotation.graph() ); } - final String jpaEntityName = typeIndicator.TYPE_NAME().toString(); - final var entityDomainType = entityDomainNameResolver.resolveEntityName( jpaEntityName ); - final String name = this.name == null ? jpaEntityName : this.name; - return parse( entityDomainNameResolver, name, entityDomainType, graphContext ); + jpaEntityName = typeIndicator.TYPE_NAME().toString(); + entityDomainType = entityDomainNameResolver.resolveEntityName( jpaEntityName ); } else { if ( typeIndicator != null ) { - throw new InvalidGraphException( "Expecting graph text to not include an entity name : " + annotation.graph() ); + throw new InvalidGraphException( "Expecting graph text to not include an entity name: " + annotation.graph() ); } - final var entityDomainType = entityDomainClassResolver.resolveEntityClass( entityType ); - final String name = this.name == null ? entityDomainType.getName() : this.name; - return parse( entityDomainNameResolver, name, entityDomainType, graphContext ); + entityDomainType = entityDomainClassResolver.resolveEntityClass( entityType ); + jpaEntityName = entityDomainType.getName(); } + return visit( name == null ? jpaEntityName : name, + entityDomainType, entityDomainNameResolver, graphContext ); } - private static @NonNull RootGraphImplementor parse( - GraphParserEntityNameResolver entityDomainNameResolver, + private static @NonNull RootGraphImplementor visit( String name, - EntityDomainType entityDomainType, + EntityDomainType entityDomainType, GraphParserEntityNameResolver entityDomainNameResolver, GraphLanguageParser.GraphContext graphContext) { - return GraphParsing.parse( name, entityDomainType, graphContext.attributeList(), + return GraphParsing.visit( name, entityDomainType, graphContext.attributeList(), entityName -> resolve( entityName, entityDomainNameResolver ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/EntityGraphs.java b/hibernate-core/src/main/java/org/hibernate/graph/EntityGraphs.java index 9106be1fd9d9..9d44ffbd78c4 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/EntityGraphs.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/EntityGraphs.java @@ -7,7 +7,6 @@ import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.stream.Stream; import jakarta.persistence.AttributeNode; @@ -310,31 +309,10 @@ public static boolean areEqual(EntityGraph a, EntityGraph b) { if ( a == b ) { return true; } - if ( ( a == null ) || ( b == null ) ) { - return false; - } - - final List> aNodes = a.getAttributeNodes(); - final List> bNodes = b.getAttributeNodes(); - - if ( aNodes.size() != bNodes.size() ) { - return false; - } - for ( AttributeNode aNode : aNodes ) { - final String attributeName = aNode.getAttributeName(); - AttributeNode bNode = null; - for ( AttributeNode bCandidate : bNodes ) { - if ( attributeName.equals( bCandidate.getAttributeName() ) ) { - bNode = bCandidate; - break; - } - } - if ( !areEqual( aNode, bNode ) ) { - return false; - } + else { + return a != null && b != null + && haveSameNodes( a, b ); } - - return true; } /** @@ -345,10 +323,10 @@ public static boolean areEqual(AttributeNode a, AttributeNode b) { if ( a == b ) { return true; } - if ( ( a == null ) || ( b == null ) ) { + else if ( a == null || b == null ) { return false; } - if ( a.getAttributeName().equals( b.getAttributeName() ) ) { + else if ( a.getAttributeName().equals( b.getAttributeName() ) ) { return areEqual( a.getSubgraphs(), b.getSubgraphs() ) && areEqual( a.getKeySubgraphs(), b.getKeySubgraphs() ); } @@ -367,28 +345,23 @@ public static boolean areEqual( if ( a == b ) { return true; } - if ( ( a == null ) || ( b == null ) ) { + else if ( a == null || b == null ) { return false; } - - @SuppressWarnings("rawtypes") - final Set aKeys = a.keySet(); - @SuppressWarnings("rawtypes") - final Set bKeys = b.keySet(); - - if ( aKeys.equals( bKeys ) ) { - for ( Class clazz : aKeys ) { - if ( !bKeys.contains( clazz ) ) { - return false; - } - if ( !areEqual( a.get( clazz ), b.get( clazz ) ) ) { - return false; + else { + final var aKeys = a.keySet(); + final var bKeys = b.keySet(); + if ( aKeys.equals( bKeys ) ) { + for ( var key : aKeys ) { + if ( !areEqual( a.get( key ), b.get( key ) ) ) { + return false; + } } + return true; + } + else { + return false; } - return true; - } - else { - return false; } } @@ -396,42 +369,38 @@ public static boolean areEqual( * Compares two entity subgraphs and returns {@code true} if they are equal, * ignoring attribute order. */ - public static boolean areEqual( - @SuppressWarnings("rawtypes") Subgraph a, - @SuppressWarnings("rawtypes") Subgraph b) { + public static boolean areEqual(Subgraph a, Subgraph b) { if ( a == b ) { return true; } - if ( ( a == null ) || ( b == null ) ) { - return false; - } - if ( a.getClassType() != b.getClassType() ) { - return false; + else { + return a != null && b != null + && a.getClassType() == b.getClassType() + && haveSameNodes( a, b ); } + } - @SuppressWarnings("unchecked") - final List> aNodes = a.getAttributeNodes(); - @SuppressWarnings("unchecked") - final List> bNodes = b.getAttributeNodes(); - + private static boolean haveSameNodes(Graph a, Graph b) { + final var aNodes = a.getAttributeNodes(); + final var bNodes = b.getAttributeNodes(); if ( aNodes.size() != bNodes.size() ) { return false; } - - for ( AttributeNode aNode : aNodes ) { - final String attributeName = aNode.getAttributeName(); - AttributeNode bNode = null; - for ( AttributeNode bCandidate : bNodes ) { - if ( attributeName.equals( bCandidate.getAttributeName() ) ) { - bNode = bCandidate; - break; + else { + for ( var aNode : aNodes ) { + final String attributeName = aNode.getAttributeName(); + AttributeNode bNode = null; + for ( var bCandidate : bNodes ) { + if ( attributeName.equals( bCandidate.getAttributeName() ) ) { + bNode = bCandidate; + break; + } + } + if ( !areEqual( aNode, bNode ) ) { + return false; } } - if ( !areEqual( aNode, bNode ) ) { - return false; - } + return true; } - - return true; } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/GraphParser.java b/hibernate-core/src/main/java/org/hibernate/graph/GraphParser.java index ae5ca1086929..f2386b680453 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/GraphParser.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/GraphParser.java @@ -28,7 +28,8 @@ * The {@link #parse} methods all create a root {@link jakarta.persistence.EntityGraph} * based on the passed entity class and parse the graph string into that root graph. *

- * The {@link #parseInto} methods parse the graph string into a passed graph, which may be a subgraph + * The {@link #parseInto} methods parse the graph string into a passed graph, which may + * be a subgraph. *

* Multiple graphs for the same entity type can be * {@linkplain EntityGraphs#merge(EntityManager, Class, jakarta.persistence.Graph...) @@ -36,7 +37,6 @@ * * @author asusnjar */ -@SuppressWarnings("unused") public final class GraphParser { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -135,8 +135,8 @@ public static RootGraph parse( } /** - * Creates a root graph based on the passed `rootType` and parses `graphText` into - * the generated root graph + * Creates a root graph based on the passed {@code rootType} and parses {@code graphText} + * into the generated root graph. * * @apiNote The passed EntityManager is expected to be a Hibernate implementation. * Attempting to pass another provider's EntityManager implementation will fail. diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/GraphParser.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/GraphParser.java index 1377b8678ac1..2f69953025c9 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/GraphParser.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/GraphParser.java @@ -13,11 +13,11 @@ import org.hibernate.graph.spi.GraphParserEntityNameResolver; import org.hibernate.graph.spi.GraphImplementor; import org.hibernate.graph.spi.SubGraphImplementor; -import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.Stack; import org.hibernate.internal.util.collections.StandardStack; import static org.hibernate.graph.internal.GraphParserLogging.PARSING_LOGGER; +import static org.hibernate.internal.util.StringHelper.repeat; /** * Unified access to the Antlr parser for Hibernate's "graph language" @@ -51,36 +51,12 @@ public Stack> getGraphStack() { @Override public AttributeNodeImplementor visitAttributeNode(GraphLanguageParser.AttributeNodeContext attributeNodeContext) { - final String attributeName = attributeNodeContext.attributePath().ATTR_NAME().getText(); + final var attributePathContext = attributeNodeContext.attributePath(); + final var attributeQualifierContext = attributePathContext.attributeQualifier(); - final SubGraphGenerator subGraphCreator; + final String attributeName = attributePathContext.ATTR_NAME().getText(); - if ( attributeNodeContext.attributePath().attributeQualifier() == null ) { - if ( PARSING_LOGGER.isTraceEnabled() ) { - PARSING_LOGGER.tracef( - "%s Start attribute : %s", - StringHelper.repeat( ">>", attributeNodeStack.depth() + 1 ), - attributeName - ); - } - - subGraphCreator = PathQualifierType.VALUE.getSubGraphCreator(); - } - else { - final String qualifierName = attributeNodeContext.attributePath().attributeQualifier().ATTR_NAME().getText(); - - if ( PARSING_LOGGER.isTraceEnabled() ) { - PARSING_LOGGER.tracef( - "%s Start qualified attribute : %s.%s", - StringHelper.repeat( ">>", attributeNodeStack.depth() + 1 ), - attributeName, - qualifierName - ); - } - - final PathQualifierType pathQualifierType = resolvePathQualifier( qualifierName ); - subGraphCreator = pathQualifierType.getSubGraphCreator(); - } + final var subGraphCreator = subGraphCreator( attributeQualifierContext, attributeName ); final var attributeNode = resolveAttributeNode( attributeName ); @@ -101,7 +77,7 @@ public AttributeNodeImplementor visitAttributeNode(GraphLanguageParser.At if ( PARSING_LOGGER.isTraceEnabled() ) { PARSING_LOGGER.tracef( "%s Finished attribute : %s", - StringHelper.repeat( "<<", attributeNodeStack.depth() + 1 ), + repeat( "<<", attributeNodeStack.depth() + 1 ), attributeName ); } @@ -109,6 +85,31 @@ public AttributeNodeImplementor visitAttributeNode(GraphLanguageParser.At return attributeNode; } + private SubGraphGenerator subGraphCreator(GraphLanguageParser.AttributeQualifierContext attributeQualifierContext, String attributeName) { + if ( attributeQualifierContext == null ) { + if ( PARSING_LOGGER.isTraceEnabled() ) { + PARSING_LOGGER.tracef( + "%s Start attribute : %s", + repeat( ">>", attributeNodeStack.depth() + 1 ), + attributeName + ); + } + return PathQualifierType.VALUE.getSubGraphCreator(); + } + else { + final String qualifierName = attributeQualifierContext.ATTR_NAME().getText(); + if ( PARSING_LOGGER.isTraceEnabled() ) { + PARSING_LOGGER.tracef( + "%s Start qualified attribute : %s.%s", + repeat( ">>", attributeNodeStack.depth() + 1 ), + attributeName, + qualifierName + ); + } + return resolvePathQualifier( qualifierName ).getSubGraphCreator(); + } + } + private AttributeNodeImplementor resolveAttributeNode(String attributeName) { final var currentGraph = graphStack.getCurrent(); assert currentGraph != null; @@ -140,7 +141,7 @@ public SubGraphImplementor visitSubGraph(GraphLanguageParser.SubGraphContext if ( PARSING_LOGGER.isTraceEnabled() ) { PARSING_LOGGER.tracef( "%s Starting graph: %s", - StringHelper.repeat( ">>", attributeNodeStack.depth() + 2 ), + repeat( ">>", attributeNodeStack.depth() + 2 ), subTypeName ); } @@ -148,7 +149,7 @@ public SubGraphImplementor visitSubGraph(GraphLanguageParser.SubGraphContext final var attributeNode = attributeNodeStack.getCurrent(); final var subGraphCreator = graphSourceStack.getCurrent(); - final SubGraphImplementor subGraph = subGraphCreator.createSubGraph( + final var subGraph = subGraphCreator.createSubGraph( attributeNode, subTypeName, entityNameResolver @@ -166,7 +167,7 @@ public SubGraphImplementor visitSubGraph(GraphLanguageParser.SubGraphContext if ( PARSING_LOGGER.isTraceEnabled() ) { PARSING_LOGGER.tracef( "%s Finished graph : %s", - StringHelper.repeat( "<<", attributeNodeStack.depth() + 2 ), + repeat( "<<", attributeNodeStack.depth() + 2 ), subGraph.getGraphedType().getTypeName() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/GraphParsing.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/GraphParsing.java index 332ce3885fef..514b6c3c7316 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/GraphParsing.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/GraphParsing.java @@ -41,7 +41,7 @@ public static RootGraphImplementor parse( throw new InvalidGraphException( "Expecting graph text to not include an entity name: " + graphText ); } - return parse( entityDomainType, graphContext.attributeList(), sessionFactory ); + return visit( entityDomainType, graphContext.attributeList(), sessionFactory ); } public static RootGraphImplementor parse( @@ -74,30 +74,30 @@ public static RootGraphImplementor parse( final String entityName = graphContext.typeIndicator().TYPE_NAME().getText(); final var entityType = sessionFactory.getJpaMetamodel().entity( entityName ); - return parse( entityType, graphContext.attributeList(), sessionFactory ); + return visit( entityType, graphContext.attributeList(), sessionFactory ); } - public static RootGraphImplementor parse( + public static RootGraphImplementor visit( EntityDomainType rootType, GraphLanguageParser.AttributeListContext attributeListContext, SessionFactoryImplementor sessionFactory) { - return parse( rootType, attributeListContext, sessionFactory.getJpaMetamodel()::findEntityType ); + return visit( rootType, attributeListContext, sessionFactory.getJpaMetamodel()::findEntityType ); } - public static RootGraphImplementor parse( + public static RootGraphImplementor visit( EntityDomainType rootType, GraphLanguageParser.AttributeListContext attributeListContext, GraphParserEntityNameResolver entityNameResolver) { - return parse( null, rootType, attributeListContext, entityNameResolver ); + return visit( null, rootType, attributeListContext, entityNameResolver ); } - private static @NonNull GraphContext parseText(String graphText) { + public static @NonNull GraphContext parseText(String graphText) { final var lexer = new GraphLanguageLexer( CharStreams.fromString( graphText ) ); final var parser = new GraphLanguageParser( new CommonTokenStream( lexer ) ); return parser.graph(); } - public static RootGraphImplementor parse( + public static RootGraphImplementor visit( @Nullable String name, EntityDomainType rootType, GraphLanguageParser.AttributeListContext attributeListContext,