Compare Date entities in JPA Criteria API

JavaDateJpa 2.0Criteria Api

Java Problem Overview


Using JPA 2 with EclipseLink implementation.

I'm trying to build a dynamic query which should bring me some records persisted after a given date.

CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Event> criteria = builder.createQuery(Event.class);
Root<Event> root = criteria.from(Event.class);
criteria.select(root);
criteria.distinct(true);
List<Predicate> predicates = new ArrayList<Predicate>();
//...
if (dateLimit != null){
    ParameterExpression<Date> param = builder.parameter(Date.class, "dateLimit");
    predicates.add(builder.lessThanOrEqualTo(root.get("dateCreated"), param));
}

lessThanOrEqualTo() and le() are the only two methods in the API which look like may help me in this case. This warning is thrown by the eclipse though:

Bound mismatch: The generic method lessThanOrEqualTo(Expression<? extends Y>, Expression<? extends Y>)
of type CriteriaBuilder is not applicable for the arguments (Path<Object>, ParameterExpression<Date>).
The inferred type Object is not a valid substitute for the bounded parameter
<Y extends Comparable<? super Y>>

I can imagine that I'm not taking the correct approach for this problem but I can't find anywhere some tips or pointers for a possible solution.

Java Solutions


Solution 1 - Java

The problem is that with the string-based API it cannot infer the type for the result value of the get-Operation. This is explained for example in Javadoc for Path.

If you use

predicates.add(builder.lessThanOrEqualTo(root.<Date>get("dateCreated"), param));

instead, it will work fine, because it can figure out the return type from the type argument and will find out that it is comparable. Note, the use of a parameterised method invocation root.<Date>get(...) (see, e.g., https://stackoverflow.com/questions/2781672/when-is-a-parameterized-method-call-useful).

Another (in my opinion better) solution is to use the metamodel based API instead of the string-based one. A simple example about canonical metamodel is given for example here. If you have more time to invest, this is a good article about static metamodel: Dynamic, typesafe queries in JPA 2.0

Solution 2 - Java

You need to use the generated metamodel to access the attributes is a really safe way. If you use Strings to refer to your attributes, types can only be deduced from the explicit generic type used when calling the method, or by a type cast, or by the automatic type inference done by the compiler:

Path<Date> dateCreatedPath = root.get("dateCreated");
predicates.add(builder.lessThanOrEqualTo(dateCreatedPath, dateLimit));

Solution 3 - Java

I was getting a similar error but with the syntax predicates.add(cb.greaterThan(article.get(Article_.created), since)); and found this page. The cause for me, turned out to be that I had upgraded my project from Java 1.7 to 1.8, and in the process had configured Maven to compile for Java 1.8 as well. I simply had to change Maven compiles back to 1.7, while keeping the rest of the project at 1.8, to fix the error.

Solution 4 - Java

I had the same problem, when I have worked with predicates. It worked great with all types except Date type. I tried all method and most simple way for me was:

predicates.add(builder.greaterThanOrEqualTo(root.get(criteria.getKey()), (Date)criteria.getValue()));

I added (Date) before criteria.getValue(), what help to recognize my value Object as Date type.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionIonutView Question on Stackoverflow
Solution 1 - JavaMikko MaunuView Answer on Stackoverflow
Solution 2 - JavaJB NizetView Answer on Stackoverflow
Solution 3 - JavaBjørn StenfeldtView Answer on Stackoverflow
Solution 4 - JavaMurat KurbanovView Answer on Stackoverflow