HHH-17079 - Fixed NPE when mapping a generic class as a composite user type

This commit is contained in:
Bruno Sofiato 2023-08-18 01:41:12 -03:00 committed by Christian Beikov
parent b19bd07080
commit 9c375e1a70
6 changed files with 191 additions and 1 deletions

View File

@ -122,7 +122,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;

View File

@ -0,0 +1,19 @@
package org.hibernate.orm.test.cut.generic;
public class EnumPlaceholder<T extends Enum<T>, R extends Enum<R>> {
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;
}
}

View File

@ -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<EnumPlaceholder> {
@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<? extends Enum> firstEnumClass = values.getValue( 0, Class.class );
String firstEnumValue = values.getValue( 1, String.class );
Class<? extends Enum> 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<EnumPlaceholder> 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<? extends Enum> firstEnumClass;
String firstEnumValue;
Class<? extends Enum> secondEnumClass;
String secondEnumValue;
}
}

View File

@ -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;
}
}

View File

@ -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<Weekdays, Weekdays> placeholder = new EnumPlaceholder<>( Weekdays.MONDAY, Weekdays.SUNDAY );
GenericCompositeUserTypeEntity entity = new GenericCompositeUserTypeEntity( placeholder );
s.persist( entity );
tx.commit();
s.close();
}
}

View File

@ -0,0 +1,10 @@
package org.hibernate.orm.test.cut.generic;
public enum Weekdays {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
SATURDAY,
SUNDAY
}