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.99k stars 1.41k forks source link

Spring data JPA error for field with @jakarta.persistence.Convert #3543

Closed tcordel closed 3 months ago

tcordel commented 3 months ago

Hi,

First of all, i apologize in advance if this is not the right place to publish or if this report is shitty :sob:.

We face an issue using Spring data jpa queries with parameters refering to field having an @jakarta.persistence.Convert strategy. For the convinience, I have initialized a small project presenting the default, you may find it here. This issue is surely caused by HHH-17595

@jakarta.persistence.Entity
public class Entity {

    @Id
    @GeneratedValue
    private Long id;

    @Convert(converter = DateConverter.class)
    private Date creationDate;
}

public interface WorkingEntityRepository
        extends JpaRepository<Entity, Long> {

        // Still working
    @Query("SELECT E from Entity E where E.creationDate = :creationDate")
    Entity working(@Param("creationDate") Date creationDate);
}

public interface BuggyEntityRepository
        extends JpaRepository<Entity, Long> {

        // This is no more working since spring boot 3.2.0
    Entity findFirstByCreationDate(Date creationDate);
}

the stack :

Caused by: org.hibernate.query.SemanticException: Cannot compare left expression of type 'java.util.Date' with right expression of type 'java.sql.Timestamp'
    at org.hibernate.query.sqm.internal.TypecheckUtil.assertComparable(TypecheckUtil.java:358)
    at org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate.<init>(SqmComparisonPredicate.java:48)
    at org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate.<init>(SqmComparisonPredicate.java:34)
    at org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder.equal(SqmCriteriaNodeBuilder.java:2143)
    at org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder.equal(SqmCriteriaNodeBuilder.java:190)

Thanks in advance,

christophstrobl commented 3 months ago

Thank you @tcordel for raising the issue and providing the sample project. Unfortunately there's not much we can do from a spring-data side. Like you already said, this is a hibernate issue that can be reproduced with plain JPA. While everything works fine using equal(Expression<?> x, Object y), things start to fail in this case once a ParameterExpression is used as outlined below.

Root<Entity> root = criteriaQuery.from(Entity.class);
ParameterExpression<Date> createDateParameter = criteriaBuilder.parameter(Date.class);
TypedQuery<Entity> query = entityManager.createQuery(criteriaQuery.where(criteriaBuilder.equal(root.get("creationDate"), createDateParameter)));
query.setParameter(createDateParameter, creationDate);

I recommend to get in touch with the hibernate team, maybe providing the minimalist possible reproducer that only contains the required hibernate/JPA parts.