I have encountered a bug that user report they can't get the value, where returned the error message: "message": "Unknown name value for enum class XXX: 1
I checked the project and find no where so I guess this error is thrown by framework.
So:
jakartaee/persistence -> an interface sets
Hibernate-core -> search enumerated
Got EnumeratedValueResolution.java
Continue explore got InferredBasicValueResolver.java
Find a method called ordinalJdbcType
java
private static JdbcType ordinalJdbcType(
JdbcType explicitJdbcType,
EnumJavaType<?> enumJavaType,
MetadataBuildingContext context) {
return explicitJdbcType != null
? explicitJdbcType
: context.getMetadataCollector().getTypeConfiguration().getJdbcTypeRegistry().getDescriptor( enumJavaType.hasManyValues() ? SMALLINT : TINYINT );
}
Here from code we could see it has JdbcType
and JavaType
so there should be some convertor/resolver to do the mapping.
Go to a specific type SMALLINT
,(find in previous code) and explore, check the file comments and doc, find
java
* A type code is often used as a key to obtain a
* {@link org.hibernate.type.descriptor.jdbc.JdbcType}, by implementors of
* {@link org.hibernate.type.descriptor.java.JavaType#getRecommendedJdbcType}
Go check getRecommendedJdbcType
, the implementation for enum value is EnumJavaType.class
Then we find the usage to the EnumType.java
, check some variables and functions.
I also checked the database, the value was saved as varchar
, while in model the filed is an enum type.
So I guess the reason is that:
Enumerated.Ordinal
, saving the ordinal value to the database.While user is querying the value, hibernate finds database metadata, finding its db type is varchar
, its java type is enum value, so the framework will take this db value as the name of the enum type and query, where 1
is not a valid name, though. So here is problem.
I search the varchar
in the EnumType.java
and find getConverterForType
,
Java
private EnumValueConverter<T,?> getConverterForType(
EnumJavaType<T> enumJavaType,
LocalJdbcTypeIndicators localIndicators,
int type) {
if ( isNumericType(type) ) {
final JavaType<? extends Number> relationalJavaType = resolveRelationalJavaType( localIndicators, enumJavaType );
return new OrdinalEnumValueConverter<>(
enumJavaType,
relationalJavaType.getRecommendedJdbcType( localIndicators ),
relationalJavaType
);
}
else if ( isCharacterType(type) ) {
return new NamedEnumValueConverter<>(
enumJavaType,
getStringType().getRecommendedJdbcType( localIndicators ),
getStringType()
);
}
else {
throw new HibernateException(
String.format( "Passed JDBC type code [%s] not recognized as numeric nor character", type )
);
}
}
Lin 14, continue dig we got: NamedEnumValueConverter
, and the doc for the class:
/** * BasicValueConverter handling the conversion of an enum based on * JPA {@link jakarta.persistence.EnumType#STRING} strategy (storing the name) * * @author Steve Ebersole */
It will treat the string value as name.
Based on this, we did the code fix and data fix. Enjoy.