If you just want to check the exact type of an expression, use Path.type()
as described above.
But if you want the Criteria API equivalent of Java's instanceof
operator, the only way to do it is by explicitly listing all of the sub-types Class
objects. But this makes your code brittle against future refactoring, etc.
Here's a utility class providing a JPAUtil.instanceOf()
method that solves that problem:
/**
* JPA utility methods.
*/
public final class JPAUtil {
private JPAUtil() {
}
/**
* Build an IN predicate from a collection of possible values.
*/
public static <T> Predicate in(CriteriaBuilder builder, Expression<T> expr, Iterable<? extends T> values) {
final CriteriaBuilder.In<T> in = builder.in(expr);
values.forEach(in::value);
return in;
}
/**
* Build an "instanceof" predicate.
*/
@SuppressWarnings("unchecked")
public static Predicate instanceOf(EntityManager entityManager, Path<?> path, Class<?> type) {
final Set<Class<?>> subtypes = entityManager.getMetamodel().getManagedTypes().stream()
.map(ManagedType::getJavaType)
.filter(type::isAssignableFrom)
.collect(Collectors.toSet());
return JPAUtil.in(entityManager.getCriteriaBuilder(), (Expression<Class<?>>)path.type(), subtypes);
}
}