Java 8 for constructing JPA criteria queries

Java 8 for constructing JPA criteria queries

June 30, 2015
frontpage, Java
One Comment

How to use Stream API and Lambda functions for flexible JPA criteria queries construction.

One of the things I found interesting and evolutionary after 2 years away from actual coding is the way of constructing JPA criteria queries using object-oriented approach. How I got involved in this you can read here.


Simple enough:

1.Define criteria methods

The methods return

and trough Lambda functions define the JPA criterias.

  public Specification<User> activeUsers(long from) {
        return (root, query, cb) -> {
            Subquery<Integer> sq = query.subquery(Integer.class);
            return cb.and(
                    cb.greaterThanOrEqualTo(root.get(User_.createdDate), new Date(from)),

    public Specification<User> proUsers() {
        return (root, query, cb) -> {
            final String proUserPermissionsName = ProUserPermissions.class.getSimpleName();
            return cb.and(
                            cb.equal(root.get(User_.userLevel), proUserPermissionsName),

    public Specification<User> userByCreatedRange(Long from, Long to) {
        return (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (from != null && from > 0) {
                                   new Date(from)));
            if (to != null && to > 0) {
                                   new Date(to)));
            Predicate[] p = predicates.toArray(new Predicate[predicates.size()]);
            return p.length == 0 ? null : p.length == 1 ? p[0] : cb.and(p);


2. Define some helper methods and classes

  private <T> CriteriaQuery<T> applyFilter(CriteriaQuery<T> query, Class<?> cls,
        Specification filter, Root<?> root, CriteriaBuilder cb) {
        Predicate[] where = Stream.of(filter)
                .filter(f -> f != null)
                .map(new FilterPredicateFunction<>(root, query, cb))
                .filter(f -> f != null)
        return where.length > 0 ? query.where(where) : query;

   private static class FilterPredicateFunction<T> implements java.util.function.
        Function<Specification, Predicate> {
        private final Root<T> root;
        private final CriteriaQuery<?> query;
        private final CriteriaBuilder cb;

        public FilterPredicateFunction(Root<T> root, CriteriaQuery<?> query,
            CriteriaBuilder cb) {
            this.root = root;
            this.query = query;
            this.cb = cb;
public Predicate apply(@Nullable Specification input) {
            if (input instanceof Specification) {
                return input.toPredicate(root, query, cb);
            } else {
                throw new IllegalArgumentException();

    public Specification and(Specification... filters) {
        return (root, query, cb) ->
                        .filter(f -> f != null)
                        .map(f -> (f.toPredicate(root, query, cb))
                        .filter(f -> f != null)


The following method queries the DB for all the users that have more than one RssReadTask object associated, have certain permission object a associated and are created in a specified time range. Adding different criterias based on input parameters is quite easy.

 @RequestMapping(value = "/count", method = RequestMethod.GET, params = {"activeOnly"})
    public Long count(
        @RequestParam(value = "from", defaultValue = "0") long from,
        @RequestParam(value = "to", defaultValue = "0") long to,
        @RequestParam(value = "activeOnly", defaultValue = "false") boolean activeOnly,
        @RequestParam(value = "proOnly", defaultValue = "false") boolean proOnly) {

        List<> filterList
            = new ArrayList<>();
        if (activeOnly) {
        if (proOnly) {

        filterList.add(userByCreatedRange(from, to)))

        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Long> query = cb.createQuery(Long.class);
        Root<User> root = query.from(User.class);
        return em.createQuery(applyFilter(, User.class,
                   and(filterList), root, cb, false)).getSingleResult();


The best thing about the approach is that all the criteria methods activeUsers, proUsers, userByCreatedRange are reusable and can be applied in more complex queries using the Java 8 Streams API.

What are your ways of accomplishing flexibility in creating JPA queries? Do you use Java 8 Lamba and Streams API with JPA?

Cvetelin Andreev

Cvetelin has been involved in startups (mostly tech) since 2003 year playing as (co-)founder, partner and occasionally Java full stack developer. Currently Full Stack Soldier, Startup activist and active blogger @ Dreamix. Plays, teaches and manages @ Founder of, fan of #futureofwork. Practice sustainable gardening and lifestyle. Runs a forest kindergarten near Sofia. Father of two.

More Posts - Website

Follow Me:
TwitterFacebookLinkedInGoogle Plus

Do you want more great blogs like this?

Subscribe for Dreamix Blog now!