Search code examples
spring-boothibernate

JdbcTypeRecommendationException: Could not determine recommended JdbcType for


I have searched all over the internet, these tricks do not fix my problem. Here is my entity (simplified version):

@Entity
@Table(name = "msg")
public class InternalMessage implements Serializable {
    private static final long serialVersionUID = 3768430013233258L;


    @PrePersist
    public void genTicketId() {
// something
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", unique = true)
    private Long id;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "internal_msg_parent_fk", nullable = true)
    private InternalMessage parent = null;

    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
        private List<InternalMessage> childMessages = new ArrayList<>();
}

I don't see any problems, and this worked fine before I migrated to Spring boot 3 (hibernate 6).

So what could be the issue?

Edit:

Mysql: 8.0.33
Spring boot: 3.3.3
Vscode 1.92.2
gradle: 8.10

Same result run the app in debug mode in vscode, or command line: ./gradlew bootRun

OK, I have some idea, seems the following code if failing:

public Predicate toPredicate(Root<InternalMessage> root, CriteriaQuery<?> query,
                CriteriaBuilder criteriaBuilder) {
            List<Predicate> predicates = new ArrayList<>();

            if (search == null || search.trim().isEmpty()) {
  // this part is causing me issue
                Expression<InternalMessage> parent = root.get("parent").as(InternalMessage.class);
                Predicate p = criteriaBuilder.isNull(parent);
                predicates.add(p);
                query.distinct(true);
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            } else {
// this part works
            }

        }

and this is the line causing the exception:

                Expression<InternalMessage> parent = root.get("parent").as(InternalMessage.class);

Anything wrong with the above line? It worked in older spring boot/hibernate.


Solution

  • I managed to replicate your error locally. I created an implementation of the Specification interface so to have almost the same toPredicate method and the context usage. I confirm also that the error originates from the line:

    Expression<InternalMessage> parent = root.get("parent").as(InternalMessage.class);
    

    Anyway, I have been able to solve the problem replacing the lines:

    Expression<InternalMessage> parent = root.get("parent").as(InternalMessage.class);
    Predicate p = criteriaBuilder.isNull(parent);
    

    With this single statement, removing the intermediate Expression step:

    Predicate p = criteriaBuilder.isNull(root.get("parent"));
    

    I am not sure if this leads to the correct data extraction, but I can see that the sql statement that is generated in junit tests is:

    select distinct im1_0.id,im1_0.internal_msg_parent_fk from msg im1_0 where im1_0.internal_msg_parent_fk is null
    

    That seems what is required in the original toPredicate method. Let me se if this solves the problem in your application.

    For the sake of completness, the original method seems to work if Long is used instead of InternalMessage, in this way:

    Expression<Long> parent = root.get("parent").as(Long.class);
    

    but I think that the above solution is clearer, also because using this approach the generated select statement is this:

    select distinct im1_0.id,im1_0.internal_msg_parent_fk from msg im1_0 where cast(im1_0.internal_msg_parent_fk as bigint) is null
    

    where there is this cast(... as bigint) that is quite unnecessary, in this case.