Hibernate getter and setter for enum value

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:

  1. jakartaee/persistence -> an interface sets

  2. Hibernate-core -> search enumerated

  3. Got EnumeratedValueResolution.java

  4. Continue explore got InferredBasicValueResolver.java

  5. Find a method called ordinalJdbcType

    private static JdbcType ordinalJdbcType(
          JdbcType explicitJdbcType,
          EnumJavaType<?> enumJavaType,
          MetadataBuildingContext context) {
       return explicitJdbcType != null
             ? explicitJdbcType
             : context.getMetadataCollector().getTypeConfiguration().getJdbcTypeRegistry().getDescriptor( enumJavaType.hasManyValues() ? SMALLINT : TINYINT );
    }
    
  6. Here from code we could see it has JdbcType and JavaType so there should be some convertor/resolver to do the mapping.

  7. Go to a specific type SMALLINT,(find in previous code) and explore, check the file comments and doc, find

     * 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}
    
  8. Go check getRecommendedJdbcType, the implementation for enum value is EnumJavaType.class

  9. 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:

  • When saving to database, the hibernate checking the annotation, finding it's null, so default is 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.
  1. I search the varchar in the EnumType.java and find getConverterForType,

    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.