QueryParameterBindingValidator uses property type instead of AttributeConverter type

Hello,

Defining a property like this with an enum set converter to string:

    @Convert(converter = app.masterchefworld.utils.enumconverters.Efficiency.class)
    @Column(columnDefinition = "text", name = "efficiency")
    private Set<Efficiency> efficiencies;

and a query:

@NamedQuery(name="recipes.findSpecial", query= """
        select recipe
        from Recipe recipe
        where recipe.efficiencies like ?1 escape '!'
        """)

when I try to execute:

Query query = em.createNamedQuery("recipes.findSpecial", Recipe.class);
query.setParameter(1, "%asdf%");
List<Recipe> result = query.getResultList();

I get:

Argument [%asdf%] of type [java.lang.String] did not match parameter type [java.util.Set (n/a)]

I think this is related to this [HHH-17693] - Hibernate JIRA and this [HHH-17790] - Hibernate JIRA.

Is there a workaround?
I’m using Hibernate 6.4.8

Thanks,
Hugo

Workaround is to model it like this:

    @Column(columnDefinition = "text", name = "efficiency")
    private String efficienciesText;
    private transient Set<Efficiency> efficiencies;

    @PostLoad
    void postLoad() {
        efficiencies = new app.masterchefworld.utils.enumconverters.Efficiency().convertToEntityAttribute(efficienciesText);
    }
    
    @PrePersist
    @PreUpdate
    void prePersistUpdate() {
        efficienciesText = new app.masterchefworld.utils.enumconverters.Efficiency().convertToDatabaseColumn(efficiencies);
    }

Thanks @beikov, after tested it, I see that “efficiencies” is empty in @PreUpdate. It seams that transient properties are not available in @PreUpdate because JPA creates a new instance to merge it. JPA transient information lost on create - Stack Overflow

Indeed, @PreUpdate is called on the managed object after copying the state over from the object passed to merge, but only if the passed object is not already managed.

So either you apply changes to the managed object and don’t use merge, or you call this prePersistUpdate method yourself before calling merge.

You can just map the column twice though:

    @Convert(converter = app.masterchefworld.utils.enumconverters.Efficiency.class)
    @Column(columnDefinition = "text", name = "efficiency")
    private Set<Efficiency> efficiencies;
    @Column(columnDefinition = "text", name = "efficiency", insertable = false, updatable = false)
    private String efficienciesText;

And use that other attribute in your query

        select recipe
        from Recipe recipe
        where recipe.efficienciesText like ?1 escape '!'

Thanks @beikov With this I think I can fix the problem!