Close

Spring Data JPA - Querydsl Web support, Custom Bindings

[Last Updated: Jun 23, 2018]

In the last tutorial we went through default Querydsl bindings. In this tutorial we will learn how to use customized ones.

There are two ways to customize the Querydsl bindings:

  • By using @QuerydslPredicate annotation with Predicate parameter in controller method and assigning its attribute bindings to a class implementing QuerydslBinderCustomizer.
  • By implementing QuerydslBinderCustomizer in our repository interface, and overriding its method customize() as Java 8 default method.

Example

JPA Entity

@Entity
public class Employee {
  private @Id
  @GeneratedValue
  Long id;
  private String name;
  private String dept;
  private int salary;
  @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
  private Date dateOfBirth;
    .............
}

In above entity we are using Jackson annotation @JsonFormat to serialize java.sql.Date as formatted string in the web response, by default the date is serialized as number of seconds since epoch.

Implementing QuerydslBinderCustomizer

package com.logicbig.example;

import com.querydsl.core.types.dsl.NumberExpression;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.querydsl.binding.QuerydslBinderCustomizer;
import org.springframework.data.querydsl.binding.QuerydslBindings;
import org.springframework.data.repository.PagingAndSortingRepository;
import java.sql.Date;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public interface EmployeeRepository extends PagingAndSortingRepository<Employee, Long>,
      QuerydslPredicateExecutor<Employee>, QuerydslBinderCustomizer<QEmployee> {
  @Override
  default void customize(QuerydslBindings bindings, QEmployee root) {

      bindings.bind(root.salary)
              .first(NumberExpression::goe);

      bindings.bind(root.dateOfBirth)
              .all((path, value) -> {
                  List<? extends Date> dates = new ArrayList<>(value);
                  if (dates.size() == 1) {
                      return Optional.of(path.eq(dates.get(0)));
                  } else {
                      Date from = dates.get(0);
                      Date to = dates.get(1);
                      return Optional.of(path.between(from, to));
                  }
              });
  }
}
In above example, the first custom binding is using QuerydslBindings.first() method to bind the first value in the query string for the target path (employee.salary). If for the same property, there are more than one values in the requested query string then the rest are ignored. Also we are applying 'goe' (greater than or equals) predicate for the salary.
The method QuerydslBindings.all() is used to bind all values in the query string for the target path. In above example we are using only first and second values for 'dateOfBirth' property to apply 'between' criteria.

MVC controller

@RestController
public class EmployeeController {

  @Autowired
  private EmployeeRepository repository;

  @GetMapping("/employees")
  public List<Employee> getEmployees(Predicate predicate) {
      Iterable<Employee> iterable = repository.findAll(predicate);
      List<Employee> employees = StreamSupport.stream(iterable.spliterator(), false)
                                              .collect(Collectors.toList());
      return employees;
  }
}

Running

To try examples, run embedded tomcat (configured in pom.xml of example project below):

mvn tomcat7:run-war

Output

http://localhost:8080/employees (without any query string)

http://localhost:8080/employees?salary=6000 (returns employees with salaries greater then 6000 inclusively)

http://localhost:8080/employees?dateOfBirth=1999-10-19&dateOfBirth=2005-01-01 (returns employees only within the provided range of date of births)

We can still use the default bindings along with the customized one:

http://localhost:8080/employees?salary=6000&dept=IT

Example Project

Dependencies and Technologies Used:

  • spring-data-jpa 2.0.7.RELEASE: Spring Data module for JPA repositories.
    Uses org.springframework:spring-context version 5.0.6.RELEASE
  • spring-webmvc 5.0.6.RELEASE: Spring Web MVC.
  • querydsl-apt 4.2.1: APT based Source code generation for Querydsl.
  • querydsl-jpa 4.2.1: JPA support for Querydsl.
  • jackson-databind 2.9.5: General data-binding functionality for Jackson: works on core streaming API.
  • javax.servlet-api 3.0.1 Java Servlet API
  • hibernate-core 5.3.1.Final: Hibernate's core ORM functionality.
    Implements javax.persistence:javax.persistence-api version 2.2
  • h2 1.4.197: H2 Database Engine.
  • JDK 1.8
  • Maven 3.3.9

Querydsl customized binding example Select All Download
  • spring-data-query-dsl-web-customized-bindings
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • EmployeeRepository.java
          • resources
            • META-INF

    See Also