speedment / jpa-streamer

JPAstreamer is a lightweight library for expressing JPA queries as Java Streams
GNU Lesser General Public License v2.1
344 stars 35 forks source link

JPAStreamer filter does not work with Hibernate 6.3 or later #390

Open Przemeo opened 9 months ago

Przemeo commented 9 months ago

Describe the bug As of HHH-16875 Hibernate validates comparison between objects of different types and throws org.hibernate.query.SemanticException if the objects are not comparable - this is done via the assertComparable method in org.hibernate.query.sqm.internal.TypecheckUtil. JPAStreamer sets the class as Object.class in com.speedment.jpastreamer.criteria.standard.internal.predicate.DefaultPredicateMapper in many of the methods (for example equal) instead of inferring the type, which leads to exception: Cannot compare left expression of type 'java.lang.Long' with right expression of type 'java.lang.Object' when field of type Long is compared to Long value in filter - I think that the Long.class inferred from value should be used here instead of Object.class.

Expected behavior filter works with equal and other predicates.

Actual behavior filter does not work with equal and other predicates.

How To Reproduce Create simple JPAStreamer application, quarkus-jpastreamer in version 3.0.3.Final can be used with Quarkus 3.7.1, and perform filter operation on Long field from generated metamodel with equal method.

Build tool Maven with maven-compiler-plugin with version 3.12.1 (for generating metamodel with fieldgenerator-standard) and quarkus-maven-plugin with version 3.7.1.

JPAStreamer version JPAStreamer 3.0.4

JPA Provider Hibernate 6.4.2.Final

Java Version Java 17.0.10

primowenjoy commented 9 months ago

I have also stumped on this issue.

primowenjoy commented 9 months ago
    private <ENTITY> PredicateMapping equal(
        final Criteria<ENTITY, ?> criteria,
        final FieldPredicate<ENTITY> fieldPredicate
    ) {
        Class<?> clazz = Object.class;
        if (fieldPredicate instanceof HasArg0) {
            clazz = ((HasArg0<?>) fieldPredicate).get0().getClass();
        }
        return typeMapping(
            criteria,
            fieldPredicate,
            createParameterizedPredicate(
                (column, parameter) -> criteria.getBuilder().equal(criteria.getRoot().get(column), parameter)
            ),
            clazz
        );
    }

I find a way to workaround this. However, as I am not familiar with its internal logic, i am not sure if it's a decent way. Instead of directly using Object.class, we can get a more concrete class info via HasArg0 interface.

alenaSchuh commented 8 months ago

I also encountered this issue, but with Strings: Cannot compare left expression of type 'java.lang.String' with right expression of type 'java.lang.Object Right expression is just a normal String in our code.

titusn commented 5 months ago

Another workaround is described by a user on Stackoverflow: it's possible to use the in method instead of equal