HHH-17079 - Fixed NPE when mapping a generic class as a composite user type
This commit is contained in:
parent
b19bd07080
commit
9c375e1a70
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package org.hibernate.orm.test.cut.generic;
|
||||
|
||||
public enum Weekdays {
|
||||
MONDAY,
|
||||
TUESDAY,
|
||||
WEDNESDAY,
|
||||
THURSDAY,
|
||||
SATURDAY,
|
||||
SUNDAY
|
||||
}
|
Loading…
Reference in New Issue