From 7de3be2492830c80ad90a43dd986b488f8a3e6ed Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Sat, 1 Feb 2020 10:49:46 +0000 Subject: [PATCH] Fix NPE in SingularAssociationAttributeMapping#resolveCircularFetch(...) method --- .../SingularAssociationAttributeMapping.java | 10 +- .../internal/EmbeddableFetchImpl.java | 4 +- .../MultiLoadSubSelectCollectionTest.java | 100 +++++++++--------- 3 files changed, 59 insertions(+), 55 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SingularAssociationAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SingularAssociationAttributeMapping.java index e811d36685..945c1dbafd 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SingularAssociationAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SingularAssociationAttributeMapping.java @@ -13,6 +13,7 @@ import java.util.List; import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.NotYetImplementedFor6Exception; +import org.hibernate.boot.model.source.spi.EmbeddedAttributeMapping; import org.hibernate.engine.FetchStrategy; import org.hibernate.engine.FetchTiming; import org.hibernate.mapping.ManyToOne; @@ -47,6 +48,7 @@ import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.Fetchable; +import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableFetchImpl; import org.hibernate.sql.results.graph.entity.EntityFetch; import org.hibernate.sql.results.graph.entity.EntityResultGraphNode; import org.hibernate.sql.results.graph.entity.EntityValuedFetchable; @@ -210,9 +212,13 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu } final FetchParent associationFetchParent = fetchParent.resolveContainingAssociationParent(); - assert associationFetchParent.getReferencedModePart() instanceof Association; + if(associationFetchParent == null){ + return null; + } + final ModelPart referencedModePart = associationFetchParent.getReferencedModePart(); + assert referencedModePart instanceof Association; - final Association associationParent = (Association) associationFetchParent.getReferencedModePart(); + final Association associationParent = (Association) referencedModePart; if ( Arrays.equals( associationParent.getIdentifyingColumnExpressions(), this.getIdentifyingColumnExpressions() ) ) { // we need to determine the NavigablePath referring to the entity that the bi-dir diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableFetchImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableFetchImpl.java index ad3dc8b744..7c6db35042 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableFetchImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableFetchImpl.java @@ -10,7 +10,6 @@ import java.util.function.Consumer; import org.hibernate.LockMode; import org.hibernate.engine.FetchTiming; -import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable; import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; import org.hibernate.query.NavigablePath; @@ -18,7 +17,6 @@ import org.hibernate.sql.ast.SqlAstJoinType; import org.hibernate.sql.ast.tree.from.TableGroupJoin; import org.hibernate.sql.results.graph.AbstractFetchParent; import org.hibernate.sql.results.graph.AssemblerCreationState; -import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode; import org.hibernate.sql.results.graph.DomainResultAssembler; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.Fetch; @@ -26,6 +24,8 @@ import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.FetchParentAccess; import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.Initializer; +import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode; +import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable; /** * @author Steve Ebersole diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/loading/multiLoad/MultiLoadSubSelectCollectionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/multiLoad/MultiLoadSubSelectCollectionTest.java index 7a811d9ea6..55620cb986 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/loading/multiLoad/MultiLoadSubSelectCollectionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/multiLoad/MultiLoadSubSelectCollectionTest.java @@ -20,73 +20,71 @@ import javax.persistence.Table; import org.hibernate.CacheMode; import org.hibernate.Hibernate; -import org.hibernate.Session; import org.hibernate.annotations.BatchSize; import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchMode; import org.hibernate.cfg.AvailableSettings; -import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; -import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static javax.persistence.GenerationType.AUTO; -import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @author Steve Ebersole * @author Gail Badner */ -public class MultiLoadSubSelectCollectionTest extends BaseNonConfigCoreFunctionalTestCase { - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { Parent.class, Child.class }; - } +@DomainModel(annotatedClasses = { + MultiLoadSubSelectCollectionTest.Parent.class, + MultiLoadSubSelectCollectionTest.Child.class +}) +@ServiceRegistry +@SessionFactory +public class MultiLoadSubSelectCollectionTest { protected void addSettings(Map settings) { settings.put( AvailableSettings.GENERATE_STATISTICS, "true" ); } - @Before - public void before() { - Session session = sessionFactory().openSession(); - session.getTransaction().begin(); - session.setCacheMode( CacheMode.IGNORE ); - for ( int i = 1; i <= 60; i++ ) { - final Parent p = new Parent( i, "Entity #" + i ); - for ( int j = 0; j < i ; j++ ) { - Child child = new Child(); - child.setParent( p ); - p.getChildren().add( child ); + @BeforeEach + public void before(SessionFactoryScope scope) { + scope.inTransaction( session -> { + session.setCacheMode( CacheMode.IGNORE ); + for ( int i = 1; i <= 60; i++ ) { + final Parent p = new Parent( i, "Entity #" + i ); + for ( int j = 0; j < i; j++ ) { + Child child = new Child(); + child.setParent( p ); + p.getChildren().add( child ); + } + session.persist( p ); } - session.persist( p ); - } - session.getTransaction().commit(); - session.close(); + } ); } - @After - public void after() { - Session session = sessionFactory().openSession(); - session.getTransaction().begin(); - session.createQuery( "delete Child" ).executeUpdate(); - session.createQuery( "delete Parent" ).executeUpdate(); - session.getTransaction().commit(); - session.close(); + @AfterEach + public void after(SessionFactoryScope scope) { + scope.inTransaction( session -> { + session.createQuery( "delete Child" ).executeUpdate(); + session.createQuery( "delete Parent" ).executeUpdate(); + } ); } @Test - @TestForIssue( jiraKey = "HHH-12740" ) - public void testSubselect() { - doInHibernate( - this::sessionFactory, session -> { - List list = session.byMultipleIds( Parent.class ).multiLoad( ids(56) ); + @TestForIssue(jiraKey = "HHH-12740") + public void testSubselect(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + List list = session.byMultipleIds( Parent.class ).multiLoad( ids( 56 ) ); assertEquals( 56, list.size() ); // None of the collections should be loaded yet @@ -98,13 +96,13 @@ public class MultiLoadSubSelectCollectionTest extends BaseNonConfigCoreFunctiona // should be loaded. Hibernate.initialize( list.get( 0 ).children ); - for ( int i = 0 ; i < 50 ; i++ ) { + for ( int i = 0; i < 50; i++ ) { assertTrue( Hibernate.isInitialized( list.get( i ).children ) ); assertEquals( i + 1, list.get( i ).children.size() ); } // The collections for the 51st through 56th entities should still be uninitialized - for (int i = 50 ; i < 56 ; i ++ ) { + for ( int i = 50; i < 56; i++ ) { assertFalse( Hibernate.isInitialized( list.get( i ).children ) ); } @@ -112,7 +110,7 @@ public class MultiLoadSubSelectCollectionTest extends BaseNonConfigCoreFunctiona // also be initialized. Hibernate.initialize( list.get( 50 ).children ); - for ( int i = 50 ; i < 56 ; i++ ) { + for ( int i = 50; i < 56; i++ ) { assertTrue( Hibernate.isInitialized( list.get( i ).children ) ); assertEquals( i + 1, list.get( i ).children.size() ); } @@ -123,14 +121,14 @@ public class MultiLoadSubSelectCollectionTest extends BaseNonConfigCoreFunctiona private Integer[] ids(int count) { Integer[] ids = new Integer[count]; for ( int i = 1; i <= count; i++ ) { - ids[i-1] = i; + ids[i - 1] = i; } return ids; } - @Entity( name = "Parent" ) - @Table( name = "Parent" ) - @BatchSize( size = 15 ) + @Entity(name = "Parent") + @Table(name = "Parent") + @BatchSize(size = 15) public static class Parent { Integer id; String text; @@ -172,7 +170,7 @@ public class MultiLoadSubSelectCollectionTest extends BaseNonConfigCoreFunctiona } } - @Entity( name = "Child" ) + @Entity(name = "Child") public static class Child { @Id