From fa772e5cc89cb85cc8943c2e9fc6806fc451211b Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Fri, 6 Dec 2024 13:08:17 +0100 Subject: [PATCH] HHH-13765 Add test showing the issue has been solved --- .../test/jpa/criteria/TreatKeywordTest.java | 495 ++++++++++-------- 1 file changed, 273 insertions(+), 222 deletions(-) diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatKeywordTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatKeywordTest.java index c848d969da..0f23455171 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatKeywordTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatKeywordTest.java @@ -4,21 +4,17 @@ */ package org.hibernate.orm.test.jpa.criteria; -import java.util.Arrays; -import java.util.List; import jakarta.persistence.Entity; -import jakarta.persistence.EntityManager; -import jakarta.persistence.EntityTransaction; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Join; import jakarta.persistence.criteria.Root; import jakarta.persistence.criteria.Subquery; import jakarta.persistence.metamodel.EntityType; - -import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; import org.hibernate.orm.test.jpa.metamodel.Thing; import org.hibernate.orm.test.jpa.metamodel.ThingWithQuantity; import org.hibernate.orm.test.jpa.metamodel.ThingWithQuantity_; @@ -27,279 +23,334 @@ import org.hibernate.orm.test.jpa.ql.TreatKeywordTest.JoinedEntitySubSubclass; import org.hibernate.orm.test.jpa.ql.TreatKeywordTest.JoinedEntitySubSubclass2; import org.hibernate.orm.test.jpa.ql.TreatKeywordTest.JoinedEntitySubclass; import org.hibernate.orm.test.jpa.ql.TreatKeywordTest.JoinedEntitySubclass2; - +import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; import org.hibernate.testing.orm.junit.JiraKey; -import org.junit.Assert; -import org.junit.Test; +import org.hibernate.testing.orm.junit.Jpa; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import java.util.List; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; /** * @author Steve Ebersole */ -public class TreatKeywordTest extends BaseEntityManagerFunctionalTestCase { - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { +@Jpa( + annotatedClasses = { JoinedEntity.class, JoinedEntitySubclass.class, JoinedEntitySubSubclass.class, JoinedEntitySubclass2.class, JoinedEntitySubSubclass2.class, Animal.class, Elephant.class, Human.class, Thing.class, ThingWithQuantity.class, - TreatAnimal.class, Dog.class, Dachshund.class, Greyhound.class - }; - } + TreatKeywordTest.TreatAnimal.class, TreatKeywordTest.Dog.class, TreatKeywordTest.Dachshund.class, TreatKeywordTest.Greyhound.class, + TreatKeywordTest.Person.class, TreatKeywordTest.Father.class, TreatKeywordTest.Mother.class, TreatKeywordTest.Grandmother.class + } +) +public class TreatKeywordTest { - @Test - public void basicTest() { - EntityManager em = getOrCreateEntityManager(); - CriteriaBuilder builder = em.getCriteriaBuilder(); - CriteriaQuery criteria = builder.createQuery( Thing.class ); - Root root = criteria.from( Thing.class ); - criteria.select( root ); - criteria.where( - builder.equal( - builder.treat( root, ThingWithQuantity.class ).get( ThingWithQuantity_.quantity ), - 2 - ) + @BeforeAll + public void setUp(EntityManagerFactoryScope scope) { + scope.inTransaction( + entityManager -> { + Animal animal = new Animal(); + animal.setId( 100L ); + animal.setName( "2" ); + entityManager.persist( animal ); + Human human = new Human(); + human.setId( 200L ); + human.setName( "2" ); + entityManager.persist( human ); + Elephant elephant = new Elephant(); + elephant.setId( 300L ); + elephant.setName( "2" ); + entityManager.persist( elephant ); + } ); - em.createQuery( criteria ).getResultList(); - em.close(); } @Test - public void basicTest2() { - EntityManager em = getOrCreateEntityManager(); - CriteriaBuilder builder = em.getCriteriaBuilder(); - CriteriaQuery criteria = builder.createQuery( Animal.class ); - Root root = criteria.from( Animal.class ); - criteria.select( root ); - criteria.where( - builder.equal( - builder.treat( root, Human.class ).get( "name" ), - "2" - ) + public void basicTest(EntityManagerFactoryScope scope) { + scope.inEntityManager( + entityManager -> { + CriteriaBuilder builder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteria = builder.createQuery( Thing.class ); + Root root = criteria.from( Thing.class ); + criteria.select( root ); + criteria.where( + builder.equal( + builder.treat( root, ThingWithQuantity.class ).get( ThingWithQuantity_.quantity ), + 2 + ) + ); + entityManager.createQuery( criteria ).getResultList(); + } ); - em.createQuery( criteria ).getResultList(); - em.close(); } @Test - public void treatPathClassTest() { - EntityManager em = getOrCreateEntityManager(); - em.getTransaction().begin(); - Animal animal = new Animal(); - animal.setId(100L); - animal.setName("2"); - em.persist(animal); - Human human = new Human(); - human.setId(200L); - human.setName("2"); - em.persist(human); - Elephant elephant = new Elephant(); - elephant.setId( 300L ); - elephant.setName( "2" ); - em.persist( elephant ); - em.getTransaction().commit(); - - CriteriaBuilder builder = em.getCriteriaBuilder(); - CriteriaQuery criteria = builder.createQuery( String.class ); - Root root = criteria.from( Animal.class ); - EntityType Animal_ = em.getMetamodel().entity(Animal.class); - criteria.select(root.get(Animal_.getSingularAttribute("name", String.class))); - - criteria.where(builder.like(builder.treat(root, Human.class).get( Human_.name ), "2%")); - List animalList = em.createQuery( criteria ).getResultList(); - Assert.assertEquals("treat(Animal as Human) was ignored",1, animalList.size()); - - CriteriaQuery idCriteria = builder.createQuery( Long.class ); - Root idRoot = idCriteria.from( Animal.class ); - idCriteria.select( idRoot.get( Animal_.getSingularAttribute( "id", Long.class ) ) ); - - idCriteria.where( - builder.like( - builder.treat( idRoot, Human.class ) - .get( Human_.name ), "2%" - ) + public void basicTest2(EntityManagerFactoryScope scope) { + scope.inEntityManager( + entityManager -> { + CriteriaBuilder builder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteria = builder.createQuery( Animal.class ); + Root root = criteria.from( Animal.class ); + criteria.select( root ); + criteria.where( + builder.equal( + builder.treat( root, Human.class ).get( "name" ), + "2" + ) + ); + entityManager.createQuery( criteria ).getResultList(); + } ); - List animalIdList = em.createQuery( idCriteria ).getResultList(); - Assert.assertEquals( "treat(Animal as Human) was ignored", 1, animalIdList.size() ); - Assert.assertEquals( 200L, animalIdList.get( 0 ).longValue() ); - - em.close(); } @Test - public void treatPathClassTestHqlControl() { - EntityManager em = getOrCreateEntityManager(); - em.getTransaction().begin(); - Animal animal = new Animal(); - animal.setId(100L); - animal.setName("2"); - em.persist( animal ); - Human human = new Human(); - human.setId(200L); - human.setName("2"); - em.persist(human); - Elephant elephant = new Elephant(); - elephant.setId( 300L ); - elephant.setName( "2" ); - em.persist( elephant ); - em.getTransaction().commit(); + public void treatPathClassTest(EntityManagerFactoryScope scope) { + scope.inEntityManager( + entityManager -> { + CriteriaBuilder builder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteria = builder.createQuery( String.class ); + Root root = criteria.from( Animal.class ); + EntityType Animal_ = entityManager.getMetamodel().entity( Animal.class ); + criteria.select( root.get( Animal_.getSingularAttribute( "name", String.class ) ) ); - List animalList = em.createQuery( "select a.name from Animal a where treat (a as Human).name like '2%'" ).getResultList(); - Assert.assertEquals( "treat(Animal as Human) was ignored", 1, animalList.size() ); + criteria.where( builder.like( builder.treat( root, Human.class ).get( Human_.name ), "2%" ) ); + List animalList = entityManager.createQuery( criteria ).getResultList(); + assertThat( animalList.size() ).as( "treat(Animal as Human) was ignored" ).isEqualTo( 1 ) + ; - List animalIdList = em.createQuery( "select a.id from Animal a where treat (a as Human).name like '2%'" ).getResultList(); - Assert.assertEquals("treat(Animal as Human) was ignored",1, animalList.size()); - Assert.assertEquals( 200L, animalIdList.get( 0 ).longValue() ); + CriteriaQuery idCriteria = builder.createQuery( Long.class ); + Root idRoot = idCriteria.from( Animal.class ); + idCriteria.select( idRoot.get( Animal_.getSingularAttribute( "id", Long.class ) ) ); - em.close(); + idCriteria.where( + builder.like( + builder.treat( idRoot, Human.class ) + .get( Human_.name ), "2%" + ) + ); + List animalIdList = entityManager.createQuery( idCriteria ).getResultList(); + assertThat( animalList.size() ).as( "treat(Animal as Human) was ignored" ).isEqualTo( 1 ); + assertThat( animalIdList.get( 0 ).longValue() ).isEqualTo( 200L ); + } + ); } @Test - @JiraKey( value = "HHH-9549" ) - public void treatRoot() { - EntityManager em = getOrCreateEntityManager(); + public void treatPathClassTestHqlControl(EntityManagerFactoryScope scope) { + scope.inEntityManager( + entityManager -> { + List animalList = entityManager.createQuery( + "select a.name from Animal a where treat (a as Human).name like '2%'", String.class ) + .getResultList(); + assertThat( animalList.size() ).as( "treat(Animal as Human) was ignored" ).isEqualTo( 1 ); - em.getTransaction().begin(); - Animal animal = new Animal(); - animal.setId(100L); - animal.setName("2"); - em.persist(animal); - Human human = new Human(); - human.setId(200L); - human.setName("2"); - em.persist(human); - Elephant elephant = new Elephant(); - elephant.setId( 300L ); - elephant.setName( "2" ); - em.persist( elephant ); - em.getTransaction().commit(); - CriteriaBuilder builder = em.getCriteriaBuilder(); - CriteriaQuery criteria = builder.createQuery( Human.class ); - Root root = criteria.from( Animal.class ); - criteria.select( builder.treat( root, Human.class ) ); - List humans = em.createQuery( criteria ).getResultList(); - Assert.assertEquals( 1, humans.size() ); + List animalIdList = entityManager.createQuery( + "select a.id from Animal a where treat (a as Human).name like '2%'", Long.class ) + .getResultList(); + assertThat( animalList.size() ).as( "treat(Animal as Human) was ignored" ).isEqualTo( 1 ); - em.close(); + assertThat( animalIdList.get( 0 ).longValue() ).isEqualTo( 200L ); + } + ); } @Test - @JiraKey( value = "HHH-9549" ) - public void treatRootReturnSuperclass() { - EntityManager em = getOrCreateEntityManager(); - - em.getTransaction().begin(); - Animal animal = new Animal(); - animal.setId(100L); - animal.setName("2"); - em.persist(animal); - Human human = new Human(); - human.setId(200L); - human.setName("2"); - em.persist(human); - Elephant elephant = new Elephant(); - elephant.setId( 300L ); - elephant.setName( "2" ); - em.persist( elephant ); - em.getTransaction().commit(); - - CriteriaBuilder builder = em.getCriteriaBuilder(); - CriteriaQuery criteria = builder.createQuery( Animal.class ); - Root root = criteria.from( Animal.class ); - criteria.select( builder.treat( root, Human.class ) ); - List animalsThatAreHuman = em.createQuery( criteria ).getResultList(); - Assert.assertEquals( 1, animalsThatAreHuman.size() ); - Assert.assertTrue( Human.class.isInstance( animalsThatAreHuman.get( 0 ) ) ); - - em.close(); + @JiraKey(value = "HHH-9549") + public void treatRoot(EntityManagerFactoryScope scope) { + scope.inEntityManager( + entityManager -> { + CriteriaBuilder builder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteria = builder.createQuery( Human.class ); + Root root = criteria.from( Animal.class ); + criteria.select( builder.treat( root, Human.class ) ); + List humans = entityManager.createQuery( criteria ).getResultList(); + assertThat( humans.size() ).isEqualTo( 1 ); + } + ); } @Test - public void testSelectSubclassPropertyFromDowncast() { - EntityManager em = getOrCreateEntityManager(); - CriteriaBuilder builder = em.getCriteriaBuilder(); - CriteriaQuery criteria = builder.createQuery( Integer.class ); - Root root = criteria.from( Thing.class ); - Root subroot = builder.treat( root, ThingWithQuantity.class ); - criteria.select( subroot.get( "quantity" ) ); - em.createQuery( criteria ).getResultList(); - em.close(); + @JiraKey(value = "HHH-9549") + public void treatRootReturnSuperclass(EntityManagerFactoryScope scope) { + scope.inEntityManager( + entityManager -> { + CriteriaBuilder builder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteria = builder.createQuery( Animal.class ); + Root root = criteria.from( Animal.class ); + criteria.select( builder.treat( root, Human.class ) ); + List animalsThatAreHuman = entityManager.createQuery( criteria ).getResultList(); + assertThat( animalsThatAreHuman.size() ).isEqualTo( 1 ); + assertThat( animalsThatAreHuman.get( 0 ) ).isInstanceOf( Human.class ); + } + ); + } + + @Test + public void testSelectSubclassPropertyFromDowncast(EntityManagerFactoryScope scope) { + scope.inEntityManager( + entityManager -> { + CriteriaBuilder builder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteria = builder.createQuery( Integer.class ); + Root root = criteria.from( Thing.class ); + Root subroot = builder.treat( root, ThingWithQuantity.class ); + criteria.select( subroot.get( "quantity" ) ); + entityManager.createQuery( criteria ).getResultList(); + } + ); } @Test @JiraKey(value = "HHH-9411") - public void testTreatWithRestrictionOnAbstractClass() { - EntityManager em = getOrCreateEntityManager(); - EntityTransaction entityTransaction = em.getTransaction(); - entityTransaction.begin(); + public void testTreatWithRestrictionOnAbstractClass(EntityManagerFactoryScope scope) { + scope.inTransaction( + entityManager -> { + Greyhound greyhound = new Greyhound(); + Dachshund dachshund = new Dachshund(); + entityManager.persist( greyhound ); + entityManager.persist( dachshund ); - Greyhound greyhound = new Greyhound(); - Dachshund dachshund = new Dachshund(); - em.persist( greyhound ); - em.persist( dachshund ); + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery criteriaQuery = cb.createQuery( TreatAnimal.class ); - CriteriaBuilder cb = em.getCriteriaBuilder(); - CriteriaQuery criteriaQuery = cb.createQuery( TreatAnimal.class ); + Root animal = criteriaQuery.from( TreatAnimal.class ); - Root animal = criteriaQuery.from( TreatAnimal.class ); + Root dog = cb.treat( animal, Dog.class ); - Root dog = cb.treat( animal, Dog.class ); + // only fast dogs + criteriaQuery.where( cb.isTrue( dog.get( "fast" ) ) ); - // only fast dogs - criteriaQuery.where( cb.isTrue( dog.get( "fast" ) ) ); + List results = entityManager.createQuery( criteriaQuery ).getResultList(); - List results = em.createQuery( criteriaQuery ).getResultList(); - - // we should only have a single Greyhound here, not slow long dogs! - assertEquals( Arrays.asList( greyhound ), results ); - - entityTransaction.commit(); - em.close(); + // we should only have a single Greyhound here, not slow long dogs! + assertThat( results ).isEqualTo( List.of( greyhound ) ); + } + ); } @Test @JiraKey(value = "HHH-16657") - public void testTypeFilterInSubquery() { - EntityManager em = getOrCreateEntityManager(); - EntityTransaction entityTransaction = em.getTransaction(); - entityTransaction.begin(); + public void testTypeFilterInSubquery(EntityManagerFactoryScope scope) { + scope.inTransaction( + entityManager -> { + JoinedEntitySubclass2 child1 = new JoinedEntitySubclass2( 3, "child1" ); + JoinedEntitySubSubclass2 child2 = new JoinedEntitySubSubclass2( 4, "child2" ); + JoinedEntitySubclass root1 = new JoinedEntitySubclass( 1, "root1", child1 ); + JoinedEntitySubSubclass root2 = new JoinedEntitySubSubclass( 2, "root2", child2 ); + entityManager.persist( child1 ); + entityManager.persist( child2 ); + entityManager.persist( root1 ); + entityManager.persist( root2 ); - JoinedEntitySubclass2 child1 = new JoinedEntitySubclass2( 3, "child1"); - JoinedEntitySubSubclass2 child2 = new JoinedEntitySubSubclass2( 4, "child2"); - JoinedEntitySubclass root1 = new JoinedEntitySubclass( 1, "root1", child1); - JoinedEntitySubSubclass root2 = new JoinedEntitySubSubclass( 2, "root2", child2); - em.persist( child1 ); - em.persist( child2 ); - em.persist( root1 ); - em.persist( root2 ); + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery query = cb.createQuery( String.class ); + Root root = query.from( JoinedEntitySubclass.class ); + query.orderBy( cb.asc( root.get( "id" ) ) ); + Subquery subquery = query.subquery( String.class ); + Root subqueryRoot = subquery.correlate( root ); + Join other = subqueryRoot.join( "other" ); + subquery.select( other.get( "name" ) ); + subquery.where( cb.equal( root.type(), cb.literal( JoinedEntitySubclass.class ) ) ); + query.select( subquery ); - CriteriaBuilder cb = em.getCriteriaBuilder(); - CriteriaQuery query = cb.createQuery( String.class ); - Root root = query.from( JoinedEntitySubclass.class ); - query.orderBy( cb.asc( root.get( "id" ) ) ); - Subquery subquery = query.subquery( String.class ); - Root subqueryRoot = subquery.correlate( root ); - Join other = subqueryRoot.join( "other" ); - subquery.select( other.get( "name" ) ); - subquery.where( cb.equal( root.type(), cb.literal( JoinedEntitySubclass.class ) ) ); - query.select( subquery ); + List results = entityManager.createQuery( + "select (select o.name from j.other o where type(j) = JoinedEntitySubSubclass) from JoinedEntitySubclass j order by j.id", + String.class + ).getResultList(); - List results = em.createQuery( - "select (select o.name from j.other o where type(j) = JoinedEntitySubSubclass) from JoinedEntitySubclass j order by j.id", - String.class - ).getResultList(); + assertThat( results.size() ).isEqualTo( 2 ); + assertThat( results.get( 0 ) ).isNull(); + assertThat( results.get( 1 ) ).isEqualTo( "child2" ); + } + ); + } - assertEquals( 2, results.size() ); - assertNull( results.get( 0 ) ); - assertEquals( "child2", results.get( 1 ) ); + @Test + @JiraKey("HHH-13765") + public void treatRootSingleTableInheritance(EntityManagerFactoryScope scope) { + scope.inTransaction( + entityManager -> { + entityManager.persist( new Person(1L, "Luigi") ); - entityTransaction.commit(); - em.close(); + entityManager.persist( new Mother(2L, "Anna") ); + + entityManager.persist( new Grandmother(3L, "Elisabetta") ); + } + ); + + scope.inEntityManager( + entityManager -> { + CriteriaBuilder builder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteria = builder.createQuery( Person.class ); + + Root person = criteria.from( Person.class ); + criteria.select( person ); + criteria.where( builder.isNotNull( builder.treat( person, Mother.class ).get( "name" ) ) ); + + List people = entityManager.createQuery( criteria ).getResultList(); + assertThat( people.size() ).isEqualTo( 2 ); + } + ); + } + + @Entity + @Inheritance(strategy = InheritanceType.SINGLE_TABLE) + public static class Person { + private Long id; + private String name; + + public Person() { + } + + public Person(Long id, String name) { + this.id = id; + this.name = name; + } + + @Id + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + @Entity + public static class Father extends Person { + } + + @Entity + public static class Mother extends Person { + + public Mother() { + } + + public Mother(Long id, String name) { + super(id, name); + } + } + + @Entity + public static class Grandmother extends Mother { + public Grandmother() { + } + + public Grandmother(Long id, String name) { + super(id, name); + } } @Entity(name = "TreatAnimal")