Skip to content
Advertisement

How do I cast JPA criteria Expression to long java type

This code

    criteriaBuilder.literal(LocalDateTime.now().minusDays( (long) root.get("person").get("birthDay").as(Long.class)))  

has not compile error but at run time gets this error:
Cannot cast from Expression to int

I tried using String:

    criteriaBuilder.literal(LocalDateTime.now().minusDays( Long.parseValue( root.get("person").get("birthDay").toString())))  

This also gets error:
ERROR: For input string: “org.hibernate.query.criteria.internal.path.SingularAttributePath@2ed2d35d”; nested exception is java.lang.NumberFormatException: For input string: “org.hibernate.query.criteria.internal.path.SingularAttributePath@2ed2d35d”

Advertisement

Answer

In your first error, you are mixing LocalDateTime.now().minusDays with the Expression root.get("person").get("birthDay").as(Long.class), and it is not possible.

The error is not detected at compile time because you are actually casting the Expression root.get("person").get("birthDay").as(Long.class) to long:

(long) root.get("person").get("birthDay").as(Long.class)

So everything is fine for the compiler, but at runtime an error will be raised because an Expression is not a long value.

In your second error you are trying using:

root.get("person").get("birthDay").toString()

As a result of the evaluation of this code you will get a String representation of the JPA criteria path you are defining, org.hibernate.query.criteria.internal.path.SingularAttributePath@2ed2d35d in your use case.

Then, if you compute Long.parseValue of org.hibernate.query.criteria.internal.path.SingularAttributePath@2ed2d35d if will raise an error because org.hibernate.query.criteria.internal.path.SingularAttributePath@2ed2d35d doesn’t represent a valid number.

Under the hood, the problem is that you are trying to apply the operation LocalDateTime.now().minusDays to an Expression, but it is not possible, you need to perform the computation in some other suitable way.

It is unclear by your question what you are actually trying to achieve, but the JPA criteria API provides a rich set of builtin expressions you can use as Predicates to deal with dates, such as, assuming root.get("person").get("birthDay") represent a Date like object:

cb.greaterThanOrEqualTo(root.get("person").get("birthDay"), cb.literal(LocalDate.now()));
//...
cb.greaterThan(root.get("person").get("birthDay"), cb.literal(LocalDate.now()));
//...
cb.lessThanOrEqualTo(root.get("person").get("birthDay"), cb.literal(LocalDate.now()));
//...
cb.lessThan(root.get("person").get("birthDay"), cb.literal(LocalDate.now()));

You can create your own function using cb.function as well and use that function in your predicates. Consider for that purpose defining a helper method somewhere in your code, for example:

public static Expression<Long> daysBetween(
  CriteriaBuilder cb, Expression<LocalDate> startDate, Expression<LocalDate> endDate) {
  return cb.function("DAYS_BETWEEN", long.class, startDate, endDate);
}

Where DAYS_BETWEEN is the name, you can choose the one you consider most appropriate, of a database level predefined or user defined function. In Oracle for example it exists per se, but it should be straight forward to implement in other database systems:

create or replace function days_between...

Then, use this helper method in your code. For example, give me the persons that turns years in the following numberOfDaysToTurnYears days:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
 
CriteriaQuery<Person> query = cb.createQuery(Person.class);

Root<Person> root = query.from(Person.class);

ParameterExpression<Integer> numberOfDaysToTurnYears = cb.parameter(Integer.class);

query.where(
  cb.lessThan(
    // Here you can use LocalDate.now(), because it is actually a pure literal value
    daysBetween(cb, root.get("person").get("birthDay"), cb.literal(LocalDate.now())),
    numberOfDaysToTurnYears
  )
);

List<Person> people = entityManager.createQuery(query)
    .setParameter(numberOfDaysToTurnYears, 10)
    .getResultList();
User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement