HHH-17106 Fix ClassCastException when using length 1 named enum mapping
This commit is contained in:
parent
66a723e251
commit
3f8e696dc3
|
@ -149,9 +149,9 @@ public class EnumeratedValueResolution<E extends Enum<E>,R> implements BasicValu
|
|||
}
|
||||
else if ( style == EnumType.STRING ) {
|
||||
jdbcType = jdbcTypeRegistry.getDescriptor( jdbcTypeIndicators.getColumnLength() == 1 ? CHAR : VARCHAR );
|
||||
final JavaType<String> jdbcJavaType = jdbcType.getJdbcRecommendedJavaTypeMapping(
|
||||
jdbcTypeIndicators.getColumnPrecision(),
|
||||
jdbcTypeIndicators.getColumnScale(),
|
||||
final JavaType<Object> jdbcJavaType = jdbcType.getJdbcRecommendedJavaTypeMapping(
|
||||
(int) jdbcTypeIndicators.getColumnLength(),
|
||||
null,
|
||||
typeConfiguration
|
||||
);
|
||||
converter = new NamedEnumValueConverter<>( enumJavaType, jdbcType, jdbcJavaType );
|
||||
|
|
|
@ -334,7 +334,7 @@ public class InferredBasicValueResolver {
|
|||
|
||||
if ( enumStyle == EnumType.STRING ) {
|
||||
//noinspection unchecked
|
||||
return (EnumeratedValueResolution<E, R>) stringEnumValueResolution(
|
||||
return (EnumeratedValueResolution<E, R>) namedEnumValueResolution(
|
||||
enumJavaType,
|
||||
explicitJavaType,
|
||||
explicitJdbcType,
|
||||
|
@ -418,7 +418,7 @@ public class InferredBasicValueResolver {
|
|||
}
|
||||
}
|
||||
|
||||
private static <E extends Enum<E>> EnumeratedValueResolution<E,String> stringEnumValueResolution(
|
||||
private static <E extends Enum<E>> EnumeratedValueResolution<E, Object> namedEnumValueResolution(
|
||||
EnumJavaType<E> enumJavaType,
|
||||
BasicJavaType<?> explicitJavaType,
|
||||
JdbcType explicitJdbcType,
|
||||
|
@ -427,7 +427,7 @@ public class InferredBasicValueResolver {
|
|||
final JdbcType jdbcType = explicitJdbcType == null
|
||||
? enumJavaType.getRecommendedJdbcType( stdIndicators )
|
||||
: explicitJdbcType;
|
||||
final JavaType<String> relationalJtd = stringJavaType( explicitJavaType, stdIndicators, context );
|
||||
final JavaType<Object> relationalJtd = namedJavaType( explicitJavaType, stdIndicators, context );
|
||||
|
||||
return new EnumeratedValueResolution<>(
|
||||
jdbcType,
|
||||
|
@ -442,7 +442,7 @@ public class InferredBasicValueResolver {
|
|||
: relationalJtd.getRecommendedJdbcType( stdIndicators );
|
||||
}
|
||||
|
||||
private static JavaType<String> stringJavaType(
|
||||
private static JavaType<Object> namedJavaType(
|
||||
BasicJavaType<?> explicitJavaType,
|
||||
JdbcTypeIndicators stdIndicators,
|
||||
MetadataBuildingContext context) {
|
||||
|
@ -454,7 +454,7 @@ public class InferredBasicValueResolver {
|
|||
" should handle `java.lang.String` as its relational type descriptor"
|
||||
);
|
||||
}
|
||||
return (JavaType<String>) explicitJavaType;
|
||||
return (JavaType<Object>) explicitJavaType;
|
||||
}
|
||||
else {
|
||||
return context.getMetadataCollector().getTypeConfiguration().getJavaTypeRegistry()
|
||||
|
|
|
@ -273,19 +273,22 @@ public class EnumType<T extends Enum<T>>
|
|||
);
|
||||
}
|
||||
|
||||
private JavaType<String> getStringType() {
|
||||
return typeConfiguration.getJavaTypeRegistry().getDescriptor(String.class);
|
||||
private JavaType<Object> namedJavaType(JdbcTypeIndicators stdIndicators) {
|
||||
return typeConfiguration.getJavaTypeRegistry().getDescriptor(
|
||||
stdIndicators.getColumnLength() == 1 ? Character.class : String.class
|
||||
);
|
||||
}
|
||||
|
||||
private EnumValueConverter<T,?> getConverter(
|
||||
EnumJavaType<T> enumJavaType,
|
||||
EnumType<T>.LocalJdbcTypeIndicators localIndicators,
|
||||
boolean useNamed) {
|
||||
if (useNamed) {
|
||||
if ( useNamed ) {
|
||||
final JavaType<Object> relationalJavaType = namedJavaType( localIndicators );
|
||||
return new NamedEnumValueConverter<>(
|
||||
enumJavaType,
|
||||
getStringType().getRecommendedJdbcType( localIndicators ),
|
||||
getStringType()
|
||||
relationalJavaType.getRecommendedJdbcType( localIndicators ),
|
||||
relationalJavaType
|
||||
);
|
||||
}
|
||||
else {
|
||||
|
@ -310,11 +313,12 @@ public class EnumType<T extends Enum<T>>
|
|||
relationalJavaType
|
||||
);
|
||||
}
|
||||
else if ( isCharacterType(type) ) {
|
||||
else if ( isCharacterType( type ) ) {
|
||||
final JavaType<Object> relationalJavaType = namedJavaType( localIndicators );
|
||||
return new NamedEnumValueConverter<>(
|
||||
enumJavaType,
|
||||
getStringType().getRecommendedJdbcType( localIndicators ),
|
||||
getStringType()
|
||||
relationalJavaType.getRecommendedJdbcType( localIndicators ),
|
||||
relationalJavaType
|
||||
);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -24,18 +24,19 @@ import static org.hibernate.type.descriptor.converter.internal.EnumHelper.getEnu
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class NamedEnumValueConverter<E extends Enum<E>> implements EnumValueConverter<E,String>, Serializable {
|
||||
public class NamedEnumValueConverter<E extends Enum<E>> implements EnumValueConverter<E, Object>, Serializable {
|
||||
private final EnumJavaType<E> domainTypeDescriptor;
|
||||
private final JdbcType jdbcType;
|
||||
private final JavaType<String> relationalTypeDescriptor;
|
||||
private final JavaType<Object> relationalTypeDescriptor;
|
||||
|
||||
public NamedEnumValueConverter(
|
||||
EnumJavaType<E> domainTypeDescriptor,
|
||||
JdbcType jdbcType,
|
||||
JavaType<String> relationalTypeDescriptor) {
|
||||
JavaType<?> relationalTypeDescriptor) {
|
||||
this.domainTypeDescriptor = domainTypeDescriptor;
|
||||
this.jdbcType = jdbcType;
|
||||
this.relationalTypeDescriptor = relationalTypeDescriptor;
|
||||
//noinspection unchecked
|
||||
this.relationalTypeDescriptor = (JavaType<Object>) relationalTypeDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -44,18 +45,21 @@ public class NamedEnumValueConverter<E extends Enum<E>> implements EnumValueConv
|
|||
}
|
||||
|
||||
@Override
|
||||
public JavaType<String> getRelationalJavaType() {
|
||||
public JavaType<Object> getRelationalJavaType() {
|
||||
return relationalTypeDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E toDomainValue(String relationalForm) {
|
||||
return domainTypeDescriptor.fromName( relationalForm );
|
||||
public E toDomainValue(Object relationalForm) {
|
||||
return relationalForm == null
|
||||
? null
|
||||
: domainTypeDescriptor.fromName( relationalTypeDescriptor.toString( relationalForm ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toRelationalValue(E domainForm) {
|
||||
return domainTypeDescriptor.toName( domainForm );
|
||||
public Object toRelationalValue(E domainForm) {
|
||||
final String name = domainTypeDescriptor.toName( domainForm );
|
||||
return name == null ? null : relationalTypeDescriptor.fromString( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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.orm.test.mapping.basic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.JiraKey;
|
||||
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.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@SessionFactory
|
||||
@DomainModel(annotatedClasses = EnumSingleCharTest.Person.class)
|
||||
@JiraKey("HHH-17106")
|
||||
public class EnumSingleCharTest {
|
||||
@BeforeAll
|
||||
public void setUp(SessionFactoryScope scope) {
|
||||
scope.inTransaction( session -> {
|
||||
session.persist( new Person( 1L, SinglecharEnum.B ) );
|
||||
session.persist( new Person( 2L, SinglecharEnum.R ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public void tearDown(SessionFactoryScope scope) {
|
||||
scope.inTransaction( session -> session.createMutationQuery( "delete from Person" ).executeUpdate() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdate(SessionFactoryScope scope) {
|
||||
scope.inTransaction( session -> {
|
||||
List<Person> resultList = session.createQuery( "from Person order by id", Person.class ).getResultList();
|
||||
assertEquals( 2, resultList.size() );
|
||||
assertEquals( SinglecharEnum.B, resultList.get( 0 ).getSingleChar() );
|
||||
assertEquals( SinglecharEnum.R, resultList.get( 1 ).getSingleChar() );
|
||||
} );
|
||||
}
|
||||
|
||||
public enum SinglecharEnum {
|
||||
B("first"),
|
||||
R("second"),
|
||||
O("third"),
|
||||
K("fourth"),
|
||||
E("fifth"),
|
||||
N("sixth");
|
||||
|
||||
private final String item;
|
||||
|
||||
SinglecharEnum(String item) {
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
public String getItem() {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@Column(name="SINGLE_CHAR", length = 1)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private SinglecharEnum singleChar;
|
||||
|
||||
public Person() {
|
||||
}
|
||||
|
||||
public Person(Long id, SinglecharEnum singleChar) {
|
||||
this.id = id;
|
||||
this.singleChar = singleChar;
|
||||
}
|
||||
|
||||
public SinglecharEnum getSingleChar() {
|
||||
return singleChar;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue