Hibernate 6 cannot read VARCHAR column as INT

Description

https://discourse.hibernate.org/t/hibernate-6-cannot-persist-enum-as-ordinal-in-varchar-column/7775/17

As discussed in this thread, in Hibernate 6 if a column is VARCHAR, but actually contains integers meant to be mapped with @Enumerated(value = EnumType.ORDINAL) then you’ll get an exception caused by it using the char value of the int from the db as the ordinal index. So a 0 in the db becomes a 48.

java.lang.ArrayIndexOutOfBoundsException: Index 48 out of bounds for length 2 at org.hibernate.type.descriptor.java.EnumJavaType.fromInteger(EnumJavaType.java:194) at org.hibernate.type.descriptor.java.EnumJavaType.fromOrdinal(EnumJavaType.java:211) at org.hibernate.type.descriptor.converter.internal.OrdinalEnumValueConverter.toDomainValue(OrdinalEnumValueConverter.java:40) at org.hibernate.type.descriptor.converter.internal.OrdinalEnumValueConverter.toDomainValue(OrdinalEnumValueConverter.java:23)

In Hibernate 5, this worked without issue.

https://github.com/lbenedetto/HHH-17017-Issue-Reproducer

Attachments

1
  • 06 Sep 2024, 07:48 AM

Activity

Show:

Andrea Boriero September 6, 2024 at 8:41 AM
Edited

Thanks for the feedback,

it seems that a possible workaround can be to use @JdbcTypeCode(SqlTypes.INTEGER)

or a better solution can be to change the enum definition adding the @EnumeratedValue annotation in this way

public enum MyEnum { A(0), B(1); @EnumeratedValue final int intValue; MyEnum(int intValue) { this.intValue = intValue; } }

can you give a try and let me know if it works?

Thanks.

Lars Benedetto September 6, 2024 at 7:30 AM
Edited

Ah, nevermind, it passed tests locally but when deployed to run against existing data, it fails.

Caused by: java.lang.IllegalArgumentException: No enum constant dk.tgtg.service.domain.ExpirationStrategy.3 at java.base/java.lang.Enum.valueOf(Enum.java:293) 29 lines skipped for [org.hibernate] at org.springframework.data.jpa.repository.query.JpaQueryExecution$SingleEntityExecution.doExecute(JpaQueryExecution.java:223)

It interprets the String “3” from the database as the name of the enum instead of as the ordinal.

The enum looks like this:

public enum ExpirationStrategy { /* 0 */ SESSION_CONSUMER, /* 1 */ SESSION_STORE_OWNER, /* 2 */ SESSION_ADMIN, /* 3 */ REFRESH_TOKEN,

And the issue is that the ordinal value 3 is stored in the DB as a String, which confuses Hibernate.

Your suggested change causes Hibernate to write the enum name to the database instead:

Here is a screenshot of my database. My code normally writes numbers but with your fix it writes strings.

image-20240906-074802.png

Lars Benedetto September 5, 2024 at 3:39 PM

Interesting. I just tried it out on my code and it does indeed work.

 

This is strange because in the original thread that same annotation was suggested and it didn’t work:

https://discourse.hibernate.org/t/hibernate-6-cannot-persist-enum-as-ordinal-in-varchar-column/7775/12

Andrea Boriero September 5, 2024 at 1:23 PM

Hi ,

I have just tried with Hibernate 6.0.0.Final adding the @JdbcTypeCode(SqlTypes.VARCHAR) and the test passes.

@Enumerated(value = EnumType.ORDINAL) @Column(columnDefinition = "VARCHAR(255) NOT NULL") @JdbcTypeCode(SqlTypes.VARCHAR) MyEnum myEnum;

Can you please double check?

Thanks

Details

Assignee

Reporter

Worked in

Affects versions

Priority

Created July 31, 2023 at 7:00 PM
Updated September 6, 2024 at 10:07 AM