Solved similar problems using the Specification interface:
public class ResolutionSpecs { public static Specification<Resolution> isActualUser(String user) { return new Specification<Resolution>() { public Predicate toPredicate(Root<Resolution> r, CriteriaQuery<?> cq, CriteriaBuilder cb) { return cb.equal(r.get(_Resolution.user), user); } }; } public static Specification<Resolution> isSomeDateAfter(Date start) { return new Specification<Resolution>() { public Predicate toPredicate(Root<Resolution> r, CriteriaQuery<?> cq, CriteriaBuilder cb) { return cb.greater(r.get(_Resolution.someDate), start); } }; } public static Specification<Resolution> isSomeDateBefore(Date end) { return new Specification<Resolution>() { public Predicate toPredicate(Root<Resolution> r, CriteriaQuery<?> cq, CriteriaBuilder cb) { return cb.lower(r.get(_Resolution.someDate), end); } }; } } @Repository public interface ResolutionRepository extends JpaRepository<Resolution, Long>, JpaSpecificationExecutor<Resolution> { } @Service public class ResolutionService { private final ResolutionRepository repository; @Autowired public ResolutionService(ResolutionRepository repository) { this.repository = repository; } public List<Resolution> findByUserAndSomeDateBetween(String user, Date start, Date end) { Specification<Resolution> sp = null; if (user != null) { sp = Specifications.where(ResolutionSpecs.isActualUser(user)); } if (start != null) { sp = (sp == null ? Specifications.where(ResolutionSpecs.isSomeDateAfter(start)) : sp.and(ResolutionSpecs.isSomeDateAfter(start))); } if (end != null) { sp = (sp == null ? Specifications.where(ResolutionSpecs.isSomeDateBefore(end)) : sp.and(ResolutionSpecs.isSomeDateBefore(end))); } return repository.findAll(sp); } }
Documentation is here .
It may also be an option to use the library to generate SQL queries, such as JOOQ, but I do not have combat experience with it. Documentation is here . An example is here .