diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/EmbeddableInheritanceHierarchyOrderTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/EmbeddableInheritanceHierarchyOrderTest.java new file mode 100644 index 000000000000..fa67ef8d5e73 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/EmbeddableInheritanceHierarchyOrderTest.java @@ -0,0 +1,241 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.inheritance; + +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Test; + +import jakarta.persistence.DiscriminatorColumn; +import jakarta.persistence.Embeddable; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +@DomainModel( + annotatedClasses = { + EmbeddableInheritanceHierarchyOrderTest.Animal.class, + EmbeddableInheritanceHierarchyOrderTest.Cat.class, + EmbeddableInheritanceHierarchyOrderTest.Dog.class, + EmbeddableInheritanceHierarchyOrderTest.Fish.class, + EmbeddableInheritanceHierarchyOrderTest.Mammal.class, + // If Mammal is moved right under Animal (before Dog and Cat), test will pass + EmbeddableInheritanceHierarchyOrderTest.Owner.class + } +) +@SessionFactory +public class EmbeddableInheritanceHierarchyOrderTest { + + @AfterAll + static void clean(SessionFactoryScope scope) { + scope.inTransaction( session -> session.createMutationQuery( "delete from Owner" ).executeUpdate() ); + } + + @Test + public void test(SessionFactoryScope scope) { + scope.inTransaction( session -> { + session.persist( new Owner( 1L, new Animal( 2, "Agapius" ) ) ); + session.persist( new Owner( 2L, new Cat( 3, "Bercharius", "Blaesilla" ) ) ); + session.persist( new Owner( 3L, new Dog( 4, "Censurius", "Caesarea" ) ) ); + session.persist( new Owner( 4L, new Fish( 5, "Dionysius", 3 ) ) ); + session.persist( new Owner( 5L, new Mammal( 6, "Epagraphas", "Eanswida" ) ) ); + } ); + scope.inSession( session -> { + final Owner animalOwner = session.find( Owner.class, 1L ); + assertEquals( 2, animalOwner.getPet().getAge() ); + assertEquals( "Agapius", animalOwner.getPet().getName() ); + + final Owner fishOwner = session.find( Owner.class, 4L ); + if ( fishOwner.getPet() instanceof Fish ) { + final Fish fish = (Fish) fishOwner.getPet(); + assertEquals( 5, fish.getAge() ); + assertEquals( "Dionysius", fish.getName() ); + assertEquals( 3, fish.getFins() ); + } + else { + fail( "Not fish owner" ); + } + + final Owner mammalOwner = session.find( Owner.class, 5L ); + if ( mammalOwner.getPet() instanceof Mammal ) { + final Mammal mammal = (Mammal) mammalOwner.getPet(); + assertEquals( 6, mammal.getAge() ); + assertEquals( "Epagraphas", mammal.getName() ); + assertEquals( "Eanswida", mammal.getMother() ); + } + else { + fail( "Not mammal owner" ); + } + + final Owner catOwner = session.find( Owner.class, 2L ); + if ( catOwner.getPet() instanceof Cat ) { + final Cat cat = (Cat) catOwner.getPet(); + assertEquals( 3, cat.getAge() ); + assertEquals( "Bercharius", cat.getName() ); + assertEquals( "Blaesilla", cat.getMother() ); + } + else { + fail( "Not cat owner" ); + } + + final Owner dogOwner = session.find( Owner.class, 3L ); + if ( dogOwner.getPet() instanceof Dog ) { + final Dog dog = (Dog) dogOwner.getPet(); + assertEquals( 4, dog.getAge() ); + assertEquals( "Censurius", dog.getName() ); + assertEquals( "Caesarea", dog.getMother() ); + } + else { + fail( "Not dog owner" ); + } + } ); + } + + @Embeddable + @DiscriminatorColumn(name = "animal_type", length = 64) + static + class Animal { + private int age; + + private String name; + + public Animal() { + } + + public Animal(int age, String name) { + this.age = age; + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + @Embeddable + static + class Cat extends Mammal { + //private int mouse; + // [...] + + + public Cat() { + super(); + } + + public Cat(int age, String name, String mother) { + super( age, name, mother ); + } + } + + @Embeddable + static + class Dog extends Mammal { + //private int bone; + // [...] + + public Dog() { + } + + public Dog(int age, String name, String mother) { + super( age, name, mother ); + } + } + + @Embeddable + static + class Fish extends Animal { + private int fins; + + public Fish() { + } + + public Fish(int age, String name, int fins) { + super( age, name ); + this.fins = fins; + } + + public int getFins() { + return fins; + } + + public void setFins(int fins) { + this.fins = fins; + } + } + + @Embeddable + static + class Mammal extends Animal { + private String mother; + + public Mammal() { + } + + public Mammal(int age, String name, String mother) { + super( age, name ); + this.mother = mother; + } + + public String getMother() { + return mother; + } + + public void setMother(String mother) { + this.mother = mother; + } + } + + @Entity(name = "Owner") + static + class Owner { + @Id + private Long id; + + @Embedded + private Animal pet; + + public Owner() { + } + + public Owner(Long id, Animal pet) { + this.id = id; + this.pet = pet; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Animal getPet() { + return pet; + } + + public void setPet(Animal pet) { + this.pet = pet; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/HierarchyOrderTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/HierarchyOrderTest.java new file mode 100644 index 000000000000..0d01089e2af6 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/HierarchyOrderTest.java @@ -0,0 +1,193 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.inheritance; + +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import jakarta.persistence.Embeddable; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; +import jakarta.persistence.TypedQuery; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@DomainModel( + annotatedClasses = { + HierarchyOrderTest.DerOA.class, + HierarchyOrderTest.DerDA.class, + HierarchyOrderTest.DerDB.class, + HierarchyOrderTest.DerOB.class, + HierarchyOrderTest.BaseD.class, + HierarchyOrderTest.BaseO.class + } +) +@SessionFactory +class HierarchyOrderTest { + + private EntityManagerFactory emf; + private DerOA deroa; + private DerOB derob; + + @BeforeEach + void setUp() { + DerDB derba1 = new DerDB( 5 ); + DerDA derda1 = new DerDA( "1", "abase" ); + deroa = new DerOA( derda1 ); + derob = new DerOB( derba1 ); +// emf = buildEntityManagerFactory(); + } + + @Test + void testBaseProperty(SessionFactoryScope scope) { + scope.inSession( em -> { + em.getTransaction().begin(); + em.persist( deroa ); + em.persist( derob ); + em.getTransaction().commit(); + Integer ida = deroa.getId(); + Integer idb = derob.getId(); + em.clear(); + TypedQuery qa = em.createQuery( "select o from DerOA o where o.id =:id", DerOA.class ); + qa.setParameter( "id", ida ); + DerOA deroain = qa.getSingleResult(); + assertEquals( "abase", deroain.derda.baseprop ); + } ); + } + + @Test + void testDerivedProperty(SessionFactoryScope scope) { + scope.inSession( em -> { + em.getTransaction().begin(); + em.persist( deroa ); + em.persist( derob ); + em.getTransaction().commit(); + Integer idb = derob.getId(); + em.clear(); + + TypedQuery qb = em.createQuery( "select o from DerOB o where o.id =:id", DerOB.class ); + qb.setParameter( "id", idb ); + DerOB derobin = qb.getSingleResult(); + assertNotNull( derobin ); + assertEquals( 5, derobin.derdb().b ); + } ); + } + + /* + * Created on 03/12/2024 by Paul Harrison (paul.harrison@manchester.ac.uk). + */ + @Entity(name = "DerOA") + public static class DerOA extends BaseO { + public DerOA(DerDA derda) { + this.derda = derda; + } + + @Embedded + // @AttributeOverrides({ + // @AttributeOverride(name="a",column = @Column(name = "da")) + // }) + public BaseD derda; + + public DerOA() { + + } + } + + /* + * Created on 03/12/2024 by Paul Harrison (paul.harrison@manchester.ac.uk). + */ + @Embeddable + public static class DerDB extends BaseD { + public DerDB(int b) { + this.b = b; + } + + public int b; + + public DerDB() { + + } + } + + /* + * Created on 03/12/2024 by Paul Harrison (paul.harrison@manchester.ac.uk). + */ + @Embeddable + public static class DerDA extends BaseD { + public DerDA(String a, String bprop) { + super( bprop ); + this.a = a; + } + + public String a; + + public DerDA() { + + } + } + + /* + * Created on 03/12/2024 by Paul Harrison (paul.harrison@manchester.ac.uk). + */ + @Embeddable + public abstract static class BaseD { //TODO would really like this to be abstract + public String baseprop; + + public BaseD(String baseprop) { + this.baseprop = baseprop; + } + + public BaseD() { + + } + + public String getBaseprop() { + return baseprop; + } + + } + + @Entity(name = "BaseO") + @Inheritance(strategy = InheritanceType.JOINED) + public abstract static class BaseO { + @Id + @GeneratedValue + private Integer id; + + public Integer getId() { + return id; + } + } + + /* + * Created on 03/12/2024 by Paul Harrison (paul.harrison@manchester.ac.uk). + */ + @Entity(name = "DerOB") + public static class DerOB extends BaseO { + public DerOB(DerDB derdb) { + this.derdb = derdb; + } + + @Embedded + BaseD derdb; + + public DerOB() { + + } + + public DerDB derdb() { + return (DerDB) derdb; + } + } +}