spring-projects / spring-data-jpa

Simplifies the development of creating a JPA-based data access layer.
https://spring.io/projects/spring-data-jpa/
Apache License 2.0
2.98k stars 1.41k forks source link

Specification using enum values does not follow `@Enumerated(EnumType.STRING)` and tries to convert it to smallint #3486

Closed jluiz20 closed 4 months ago

jluiz20 commented 4 months ago

I have been migrating some services from Spring Boot 2.7.18 to Spring Boot 3.2.5 and after it, I am facing a specific issue with an enum column only using the Specification and I think it could be a bug (or I am doing something wrong).

I have an entity with the following field

    @Enumerated(EnumType.STRING)
    @Builder.Default
    @Column(nullable = false)
    var acceptanceStatus: PaymentAcceptanceStatus = PaymentAcceptanceStatus.RECEIVED,

As the annotation shows, I am storing it as a String in the DB (PostgreSQL) and that works perfectly.

image

It also works well when fetching the entity by id using normal repository methods.

But when I create a Specification filtering by the enum, like below.

image

I get an error ERROR: invalid input syntax for type smallint: "SENT"

In debugging further, it seems that it is trying to convert the value passed SENT to a smallint. This is the query generated (some other fields were truncated)

org.hibernate.exception.DataException: JDBC exception executing SQL [select prw1_0.id,prw1_0.acceptance_status,prw1_0.client_id from my_table prw1_0 where cast(prw1_0.acceptance_status as smallint)=? and cast(prw1_0.acceptance_status as smallint)=? order by prw1_0.received_at desc offset ? rows fetch first ? rows only] [ERROR: invalid input syntax for type smallint: "SENT"] [n/a]

going deeper it seems that in the SimpleJpaRepository when building the parameterBindingMap, it is defining the jdbcType as TyneIntJdbcType instead of some kind of varchar or string that I would expect based on the @Enumerated(EnumType.STRING) definition.

image

Now, I am not sure if I need to add some other annotation of metadata to the field, or if the problem is the Hibernate or in the data jpa. I came here as saving and fetching are working so I think the mapping of the field is correct in Hibernate and I only have this problem when trying to use the Specification.

I also forced the latest version 3.3.0 of the library and I still see the problem. Also, tried to force a column definition @Column(nullable = false, columnDefinition = "varchar(255)") but it didn't help.

Anything I can do? Any help is really appreciated! Thank you!

quaff commented 4 months ago

Could you provide your specifications code? It's better to provide a minimal reproducer project.

jluiz20 commented 4 months ago

Thank you for your attention and I really sorry as I found out that the problem is on my side.

Turns out that we have a custom code that builds Specifications based on generic parameters and due to the Hibernate change it started breaking.

The previous code was creating an Expression using

 pathExpression = path.as(path.getJavaType());

The implementation was SingularAttributePath and it was mapped correctly,

On hibernate 6, the same logic was creating a SelfRenderingSqmFunction with the incorrect types.

image

Turns out that I only need the .as(path.getJavaType()) anymore and the new logic is

 pathExpression = path;

which maps the correct type

image

I honestly don't know how this magic works, but it is not working again.

Sorry for creating an issue that was a problem on my side.