diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/CompositeIdDerivedIdWithIdClassTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/CompositeIdDerivedIdWithIdClassTest.java new file mode 100644 index 000000000000..5bf1e7e7dd08 --- /dev/null +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/CompositeIdDerivedIdWithIdClassTest.java @@ -0,0 +1,222 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.jpa.test.factory.puUtil; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EntityManager; +import javax.persistence.Id; +import javax.persistence.IdClass; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; + +import org.junit.After; +import org.junit.Test; + +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.hibernate.testing.TestForIssue; + +import static org.junit.Assert.assertEquals; + +public class CompositeIdDerivedIdWithIdClassTest extends BaseEntityManagerFunctionalTestCase { + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + ShoppingCart.class, + LineItem.class + }; + } + + @After + public void cleanup() { + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + em.createQuery( "delete from LineItem" ).executeUpdate(); + em.createQuery( "delete from Cart" ).executeUpdate(); + em.getTransaction().commit(); + em.close(); + } + + @Test + @TestForIssue(jiraKey = "HHH-11328") + public void testMergeTransientIdManyToOne() throws Exception { + ShoppingCart transientCart = new ShoppingCart( "cart1" ); + transientCart.addLineItem( new LineItem( 0, "description2", transientCart ) ); + + // assertion for HHH-11274 - checking for exception + //final Object identifier = new PersistenceUnitUtilImpl( sessionFactory() ).getIdentifier( transientCart.getLineItems().get( 0 ) ); + final Object identifier = entityManagerFactory().getPersistenceUnitUtil().getIdentifier( + transientCart.getLineItems() + .get( 0 ) + ); + + // merge ID with transient many-to-one + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + em.merge( transientCart ); + em.getTransaction().commit(); + em.close(); + + em = getOrCreateEntityManager(); + em.getTransaction().begin(); + ShoppingCart updatedCart = em.find( ShoppingCart.class, "cart1" ); + // assertion for HHH-11274 - checking for exception + // new PersistenceUnitUtilImpl( sessionFactory() ).getIdentifier( transientCart.getLineItems().get( 0 ) ); + entityManagerFactory().getPersistenceUnitUtil().getIdentifier( transientCart.getLineItems().get( 0 ) ); + assertEquals( 1, updatedCart.getLineItems().size() ); + assertEquals( "description2", updatedCart.getLineItems().get( 0 ).getDescription() ); + em.getTransaction().commit(); + em.close(); + } + + @Test + @TestForIssue(jiraKey = "HHH-10623") + public void testMergeDetachedIdManyToOne() throws Exception { + ShoppingCart cart = new ShoppingCart("cart1"); + + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + em.persist( cart ); + em.getTransaction().commit(); + em.close(); + + // cart is detached now + LineItem lineItem = new LineItem( 0, "description2", cart ); + cart.addLineItem( lineItem ); + + // merge lineItem with an ID with detached many-to-one + em = getOrCreateEntityManager(); + em.getTransaction().begin(); + em.merge(lineItem); + em.getTransaction().commit(); + em.close(); + + em = getOrCreateEntityManager(); + em.getTransaction().begin(); + ShoppingCart updatedCart = em.find( ShoppingCart.class, "cart1" ); + assertEquals( 1, updatedCart.getLineItems().size() ); + assertEquals("description2", updatedCart.getLineItems().get( 0 ).getDescription()); + em.getTransaction().commit(); + em.close(); + } + + @Entity(name = "Cart") + public static class ShoppingCart { + @Id + @Column(name = "id", nullable = false) + private String id; + + @OneToMany(mappedBy = "cart", cascade = CascadeType.ALL, orphanRemoval = true) + private List lineItems = new ArrayList<>(); + + protected ShoppingCart() { + } + + public ShoppingCart(String id) { + this.id = id; + } + + public List getLineItems() { + return lineItems; + } + + public void addLineItem(LineItem lineItem) { + lineItems.add(lineItem); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ShoppingCart that = (ShoppingCart) o; + return Objects.equals( id, that.id ); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + } + + @Entity(name = "LineItem") + @IdClass(LineItem.Pk.class) + public static class LineItem { + + @Id + @Column(name = "item_seq_number", nullable = false) + private Integer sequenceNumber; + + @Column(name = "description") + private String description; + + @Id + @ManyToOne + @JoinColumn(name = "cart_id") + private ShoppingCart cart; + + protected LineItem() { + } + + public LineItem(Integer sequenceNumber, String description, ShoppingCart cart) { + this.sequenceNumber = sequenceNumber; + this.description = description; + this.cart = cart; + } + + public Integer getSequenceNumber() { + return sequenceNumber; + } + + public ShoppingCart getCart() { + return cart; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof LineItem)) return false; + LineItem lineItem = (LineItem) o; + return Objects.equals(getSequenceNumber(), lineItem.getSequenceNumber()) && + Objects.equals(getCart(), lineItem.getCart()); + } + + @Override + public int hashCode() { + return Objects.hash( getSequenceNumber(), getCart() ); + } + + public String getDescription() { + return description; + } + + public static class Pk implements Serializable { + public Integer sequenceNumber; + public String cart; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Pk)) return false; + Pk pk = (Pk) o; + return Objects.equals(sequenceNumber, pk.sequenceNumber) && + Objects.equals(cart, pk.cart); + } + + @Override + public int hashCode() { + return Objects.hash(sequenceNumber, cart); + } + } + } +} diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/CompositeIdDerivedIdWithIdClassTest.java.rej b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/CompositeIdDerivedIdWithIdClassTest.java.rej new file mode 100644 index 000000000000..1331b68a5516 --- /dev/null +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/CompositeIdDerivedIdWithIdClassTest.java.rej @@ -0,0 +1,30 @@ +--- hibernate-entitymanager/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/CompositeIdDerivedIdWithIdClassTest.java ++++ hibernate-entitymanager/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/CompositeIdDerivedIdWithIdClassTest.java +@@ -23,6 +23,8 @@ import org.junit.After; + import org.junit.Test; + + import org.hibernate.Session; ++import org.hibernate.jpa.internal.PersistenceUnitUtilImpl; ++ + import org.hibernate.testing.TestForIssue; + import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; + +@@ -53,6 +55,9 @@ public class CompositeIdDerivedIdWithIdClassTest extends BaseCoreFunctionalTestC + ShoppingCart transientCart = new ShoppingCart( "cart1" ); + transientCart.addLineItem( new LineItem( 0, "description2", transientCart ) ); + ++ // assertion for HHH-11274 - checking for exception ++ final Object identifier = new PersistenceUnitUtilImpl( sessionFactory() ).getIdentifier( transientCart.getLineItems().get( 0 ) ); ++ + // merge ID with transient many-to-one + Session s = openSession(); + s.getTransaction().begin(); +@@ -63,6 +68,8 @@ public class CompositeIdDerivedIdWithIdClassTest extends BaseCoreFunctionalTestC + s = openSession(); + s.getTransaction().begin(); + ShoppingCart updatedCart = s.get( ShoppingCart.class, "cart1" ); ++ // assertion for HHH-11274 - checking for exception ++ new PersistenceUnitUtilImpl( sessionFactory() ).getIdentifier( transientCart.getLineItems().get( 0 ) ); + assertEquals( 1, updatedCart.getLineItems().size() ); + assertEquals( "description2", updatedCart.getLineItems().get( 0 ).getDescription() ); + s.getTransaction().commit(); diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/GetIdentifierTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/GetIdentifierTest.java new file mode 100644 index 000000000000..b2a06b8003f9 --- /dev/null +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/GetIdentifierTest.java @@ -0,0 +1,70 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.jpa.test.factory.puUtil; + +import java.io.Serializable; +import javax.persistence.EntityManager; + +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * @author Steve Ebersole + */ +public class GetIdentifierTest extends BaseEntityManagerFunctionalTestCase { + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + LegacyEntity.class, + ModernEntity.class, + NestedLegacyEntity.class + }; + } + + @Before + public void createData() { + + } + + @After + public void dropData() { + + } + + @Test + public void getIdentifierTest() throws Exception { + EntityManager entityManager = getOrCreateEntityManager(); + entityManager.getTransaction().begin(); + + // This gives a NullPointerException right now. Look at HHH-10623 when this issue is fixed + Serializable nestedLegacyEntityId = (Serializable) entityManager.getEntityManagerFactory() + .getPersistenceUnitUtil().getIdentifier(createExisitingNestedLegacyEntity()); + + entityManager.getTransaction().commit(); + entityManager.close(); + } + + private NestedLegacyEntity createExisitingNestedLegacyEntity() { + + ModernEntity modernEntity = new ModernEntity(); + modernEntity.setFoo(2); + + LegacyEntity legacyEntity = new LegacyEntity(); + legacyEntity.setPrimitivePk1(1); + legacyEntity.setPrimitivePk2(2); + legacyEntity.setFoo("Foo"); + + NestedLegacyEntity nestedLegacyEntity = new NestedLegacyEntity(); + nestedLegacyEntity.setModernEntity(modernEntity); + nestedLegacyEntity.setLegacyEntity(legacyEntity); + + return nestedLegacyEntity; + } +} diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/LegacyEntity.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/LegacyEntity.java new file mode 100644 index 000000000000..06f302e9a994 --- /dev/null +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/LegacyEntity.java @@ -0,0 +1,77 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.jpa.test.factory.puUtil; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.IdClass; + +@Entity(name = "LegacyEntity") +@IdClass(LegacyEntityPk.class) +public class LegacyEntity { + + @Id + private int primitivePk1; + + @Id + private int primitivePk2; + + private String foo; + + public LegacyEntity() {} + + public int getPrimitivePk1() { + return primitivePk1; + } + + public void setPrimitivePk1(int primitivePk1) { + this.primitivePk1 = primitivePk1; + } + + public int getPrimitivePk2() { + return primitivePk2; + } + + public void setPrimitivePk2(int primitivePk2) { + this.primitivePk2 = primitivePk2; + } + + public String getFoo() { + return foo; + } + + public void setFoo(String foo) { + this.foo = foo; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + LegacyEntity that = (LegacyEntity) o; + + if (primitivePk1 != that.primitivePk1) return false; + return primitivePk2 == that.primitivePk2; + + } + + @Override + public int hashCode() { + int result = primitivePk1; + result = 31 * result + primitivePk2; + return result; + } + + @Override + public String toString() { + return "LegacyEntity{" + + "primitivePk1=" + primitivePk1 + + ", primitivePk2=" + primitivePk2 + + '}'; + } +} diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/LegacyEntityPk.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/LegacyEntityPk.java new file mode 100644 index 000000000000..f3307fc5896c --- /dev/null +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/LegacyEntityPk.java @@ -0,0 +1,54 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.jpa.test.factory.puUtil; + +import java.io.Serializable; + +public class LegacyEntityPk implements Serializable { + + private int primitivePk1; + + private int primitivePk2; + + public LegacyEntityPk() { + } + + public int getPrimitivePk1() { + return primitivePk1; + } + + public void setPrimitivePk1(int primitivePk1) { + this.primitivePk1 = primitivePk1; + } + + public int getPrimitivePk2() { + return primitivePk2; + } + + public void setPrimitivePk2(int primitivePk2) { + this.primitivePk2 = primitivePk2; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + LegacyEntityPk that = (LegacyEntityPk) o; + + if (primitivePk1 != that.primitivePk1) return false; + return primitivePk2 == that.primitivePk2; + + } + + @Override + public int hashCode() { + int result = primitivePk1; + result = 31 * result + primitivePk2; + return result; + } +} diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/ModernEntity.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/ModernEntity.java new file mode 100644 index 000000000000..2da6f5b42935 --- /dev/null +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/ModernEntity.java @@ -0,0 +1,63 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.jpa.test.factory.puUtil; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity(name = "ModernEntity") +public class ModernEntity { + + @Id + @GeneratedValue + private int id; + + private int foo; + + public ModernEntity() { + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getFoo() { + return foo; + } + + public void setFoo(int foo) { + this.foo = foo; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ModernEntity that = (ModernEntity) o; + + return id == that.id; + + } + + @Override + public int hashCode() { + return id; + } + + @Override + public String toString() { + return "ModernEntity{" + + "id=" + id + + '}'; + } +} diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/NestedLegacyEntity.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/NestedLegacyEntity.java new file mode 100644 index 000000000000..977c83266ad6 --- /dev/null +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/NestedLegacyEntity.java @@ -0,0 +1,76 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.jpa.test.factory.puUtil; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.IdClass; +import javax.persistence.JoinColumn; +import javax.persistence.JoinColumns; +import javax.persistence.ManyToOne; + +@Entity(name = "NestedLegacyEntity") +@IdClass(NestedLegacyEntityPk.class) +public class NestedLegacyEntity { + + @Id + @ManyToOne + @JoinColumns({@JoinColumn(name = "legacyFk1", referencedColumnName = "primitivePk1"), + @JoinColumn(name = "legacyFk2", referencedColumnName = "primitivePk2")}) + private LegacyEntity legacyEntity; + + @Id + @ManyToOne + @JoinColumn(name = "modernFk", referencedColumnName = "id") + private ModernEntity modernEntity; + + public NestedLegacyEntity() { + } + + public LegacyEntity getLegacyEntity() { + return legacyEntity; + } + + public void setLegacyEntity(LegacyEntity legacyEntity) { + this.legacyEntity = legacyEntity; + } + + public ModernEntity getModernEntity() { + return modernEntity; + } + + public void setModernEntity(ModernEntity modernEntity) { + this.modernEntity = modernEntity; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + NestedLegacyEntity that = (NestedLegacyEntity) o; + + if (legacyEntity != null ? !legacyEntity.equals(that.legacyEntity) : that.legacyEntity != null) return false; + return modernEntity != null ? modernEntity.equals(that.modernEntity) : that.modernEntity == null; + + } + + @Override + public int hashCode() { + int result = legacyEntity != null ? legacyEntity.hashCode() : 0; + result = 31 * result + (modernEntity != null ? modernEntity.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "NestedLegacyEntity{" + + "legacyEntity=" + legacyEntity + + ", modernEntity=" + modernEntity + + '}'; + } +} diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/NestedLegacyEntityPk.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/NestedLegacyEntityPk.java new file mode 100644 index 000000000000..b6afbbe1de7c --- /dev/null +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/factory/puUtil/NestedLegacyEntityPk.java @@ -0,0 +1,54 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.jpa.test.factory.puUtil; + +import java.io.Serializable; + +public class NestedLegacyEntityPk implements Serializable { + + private LegacyEntityPk legacyEntity; + + private int modernEntity; + + public NestedLegacyEntityPk() { + } + + public LegacyEntityPk getLegacyEntity() { + return legacyEntity; + } + + public void setLegacyEntity(LegacyEntityPk legacyEntity) { + this.legacyEntity = legacyEntity; + } + + public int getModernEntity() { + return modernEntity; + } + + public void setModernEntity(int modernEntity) { + this.modernEntity = modernEntity; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + NestedLegacyEntityPk that = (NestedLegacyEntityPk) o; + + if (modernEntity != that.modernEntity) return false; + return legacyEntity != null ? legacyEntity.equals(that.legacyEntity) : that.legacyEntity == null; + + } + + @Override + public int hashCode() { + int result = legacyEntity != null ? legacyEntity.hashCode() : 0; + result = 31 * result + modernEntity; + return result; + } +}