From a01795e23af50033f14180eb0181cbfe72ab9d7c Mon Sep 17 00:00:00 2001 From: Bruno Sofiato Date: Fri, 18 Aug 2023 01:41:12 -0300 Subject: [PATCH] HHH-17079 - Fixed NPE when mapping a generic class as a composite user type --- .../java/org/hibernate/mapping/Component.java | 2 +- .../orm/test/cut/generic/EnumPlaceholder.java | 19 ++++ .../cut/generic/EnumPlaceholderUserType.java | 97 +++++++++++++++++++ .../GenericCompositeUserTypeEntity.java | 30 ++++++ .../generic/GenericCompositeUserTypeTest.java | 34 +++++++ .../orm/test/cut/generic/Weekdays.java | 10 ++ 6 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/cut/generic/EnumPlaceholder.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/cut/generic/EnumPlaceholderUserType.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/cut/generic/GenericCompositeUserTypeEntity.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/cut/generic/GenericCompositeUserTypeTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/cut/generic/Weekdays.java diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Component.java b/hibernate-core/src/main/java/org/hibernate/mapping/Component.java index 9beecf7171..e30aa25edd 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Component.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Component.java @@ -119,7 +119,7 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable private Component(Component original) { super( original ); this.properties.addAll( original.properties ); - this.originalPropertyOrder = original.originalPropertyOrder.clone(); + this.originalPropertyOrder = original.originalPropertyOrder == null ? null : original.originalPropertyOrder.clone(); this.componentClassName = original.componentClassName; this.embedded = original.embedded; this.parentProperty = original.parentProperty; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/cut/generic/EnumPlaceholder.java b/hibernate-core/src/test/java/org/hibernate/orm/test/cut/generic/EnumPlaceholder.java new file mode 100644 index 0000000000..13c704fd38 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/cut/generic/EnumPlaceholder.java @@ -0,0 +1,19 @@ +package org.hibernate.orm.test.cut.generic; + +public class EnumPlaceholder, R extends Enum> { + private final T firstEnum; + private final R secondEnum; + + public EnumPlaceholder(T firstEnum, R secondEnum) { + this.firstEnum = firstEnum; + this.secondEnum = secondEnum; + } + + public T getFirstEnum() { + return firstEnum; + } + + public R getSecondEnum() { + return secondEnum; + } +} \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/cut/generic/EnumPlaceholderUserType.java b/hibernate-core/src/test/java/org/hibernate/orm/test/cut/generic/EnumPlaceholderUserType.java new file mode 100644 index 0000000000..36b0c03bc3 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/cut/generic/EnumPlaceholderUserType.java @@ -0,0 +1,97 @@ +package org.hibernate.orm.test.cut.generic; + +import java.io.Serializable; +import java.util.Objects; + +import org.hibernate.HibernateException; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.metamodel.spi.ValueAccess; +import org.hibernate.usertype.CompositeUserType; + +public class EnumPlaceholderUserType implements CompositeUserType { + + @Override + public Object getPropertyValue(EnumPlaceholder component, int property) throws HibernateException { + switch ( property ) { + case 0: + return component.getFirstEnum().getClass(); + case 1: + return component.getFirstEnum().name(); + case 2: + return component.getSecondEnum().getClass(); + case 3: + return component.getSecondEnum().name(); + default: + throw new RuntimeException(); + } + } + + @Override + public EnumPlaceholder instantiate(ValueAccess values, SessionFactoryImplementor sessionFactory) { + Class firstEnumClass = values.getValue( 0, Class.class ); + String firstEnumValue = values.getValue( 1, String.class ); + Class secondEnumClass = values.getValue( 2, Class.class ); + String secondEnumValue = values.getValue( 3, String.class ); + + Enum firstEnum = Enum.valueOf( firstEnumClass, firstEnumValue ); + Enum secondEnum = Enum.valueOf( secondEnumClass, secondEnumValue ); + + return new EnumPlaceholder( firstEnum, secondEnum ); + } + + @Override + public Class embeddable() { + return EmbeddableMapper.class; + } + + @Override + public Class returnedClass() { + return EnumPlaceholder.class; + } + + @Override + public boolean equals(EnumPlaceholder x, EnumPlaceholder y) { + return Objects.equals( x, y ); + } + + @Override + public int hashCode(EnumPlaceholder x) { + return Objects.hashCode( x ); + } + + @Override + public EnumPlaceholder deepCopy(EnumPlaceholder value) { + return new EnumPlaceholder<>( value.getFirstEnum(), value.getSecondEnum() ); + } + + @Override + public boolean isMutable() { + return false; + } + + @Override + public Serializable disassemble(EnumPlaceholder value) { + return (Serializable) value; + } + + @Override + public EnumPlaceholder assemble(Serializable cached, Object owner) { + return (EnumPlaceholder) cached; + } + + @Override + public EnumPlaceholder replace(EnumPlaceholder detached, EnumPlaceholder managed, Object owner) { + return detached; + } + + public static class EmbeddableMapper { + Class firstEnumClass; + + String firstEnumValue; + + Class secondEnumClass; + + String secondEnumValue; + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/cut/generic/GenericCompositeUserTypeEntity.java b/hibernate-core/src/test/java/org/hibernate/orm/test/cut/generic/GenericCompositeUserTypeEntity.java new file mode 100644 index 0000000000..fc0367597f --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/cut/generic/GenericCompositeUserTypeEntity.java @@ -0,0 +1,30 @@ +package org.hibernate.orm.test.cut.generic; + +import org.hibernate.annotations.CompositeType; + +import jakarta.persistence.AttributeOverride; +import jakarta.persistence.AttributeOverrides; +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Lob; + +@Entity +public class GenericCompositeUserTypeEntity { + @Lob + @Embedded + @CompositeType(value = EnumPlaceholderUserType.class) + @AttributeOverrides({ + @AttributeOverride(name = "type", column = @Column(name = "TYPE", updatable = false)), + @AttributeOverride(name = "jsonValue", column = @Column(name = "DATA", updatable = false, columnDefinition = "clob")) + }) + protected EnumPlaceholder placeholder; + @Id + private final Long id; + + public GenericCompositeUserTypeEntity(EnumPlaceholder placeholder) { + this.id = System.currentTimeMillis(); + this.placeholder = placeholder; + } +} \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/cut/generic/GenericCompositeUserTypeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/cut/generic/GenericCompositeUserTypeTest.java new file mode 100644 index 0000000000..bd96bbc83e --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/cut/generic/GenericCompositeUserTypeTest.java @@ -0,0 +1,34 @@ +package org.hibernate.orm.test.cut.generic; + +import org.hibernate.Session; +import org.hibernate.Transaction; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + + +@TestForIssue(jiraKey = "HHH-17019") +public class GenericCompositeUserTypeTest extends BaseCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + GenericCompositeUserTypeEntity.class + }; + } + + @Test + public void hhh17019Test() throws Exception { + Session s = openSession(); + Transaction tx = s.beginTransaction(); + + EnumPlaceholder placeholder = new EnumPlaceholder<>( Weekdays.MONDAY, Weekdays.SUNDAY ); + GenericCompositeUserTypeEntity entity = new GenericCompositeUserTypeEntity( placeholder ); + + s.persist( entity ); + + tx.commit(); + s.close(); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/cut/generic/Weekdays.java b/hibernate-core/src/test/java/org/hibernate/orm/test/cut/generic/Weekdays.java new file mode 100644 index 0000000000..bcf87af0f7 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/cut/generic/Weekdays.java @@ -0,0 +1,10 @@ +package org.hibernate.orm.test.cut.generic; + +public enum Weekdays { + MONDAY, + TUESDAY, + WEDNESDAY, + THURSDAY, + SATURDAY, + SUNDAY +}