Implement search for JPA and Spring I'm trying to implement properly search functionality for database table. I tried this approach:

Controller:

    @GetMapping
    public Page&lt;TransactionDTO&gt; find(TransactionFilterDTO filter, Pageable page) {
        return searchRepository
                .findTransactionsByFilter(mapper.toFilter(filter), page)
                .map(mapper::toDTO);
    }


Filer DTO:

public class TransactionFilterDTO {

    private String name;

    private Integer id;

    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
    private LocalDateTime from;

    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
    private LocalDateTime to;
    ... // getters and setter
}


Search implementation:

@Repository
public class TransactionSearchRepositoryImpl implements TransactionSearchRepository {

    @Autowired
    private TransactionRepository transactionRepository;

    @Autowired
    private TransactionSpecification specification;

    @Override
    public Page&lt;Transaction&gt; findTransactionsByFilter(TransactionFilter filter, @Nullable Pageable page) {


        List&lt;Transaction&gt; transactions = transactionRepository
                .findAll(specification.getFilter(filter));

        int totalCount = transactions.size();

        if(page != null) {
           transactions = transactions
                   .stream()
                   .skip(page.getOffset())
                   .limit(page.getPageSize())
                   .collect(Collectors.toList());
        }

        return new PageImpl&lt;&gt;(transactions, page, totalCount);
    }
}


Repository:

public interface TransactionSearchRepository {

    Page&lt;Transaction&gt; findTransactionsByFilter(TransactionFilter filter, Pageable page);
}


Is there some better way to implement a search functionality? This solution is very ugly in my view.
In JPA you could use JpaSpecificationExecutor&lt;T&gt; in repository, with that you could utilize it's method.

TransactionRepository

public interface TransactionRepository extends JpaRepository&lt;Transaction, Long&gt;,
                                                JpaSpecificationExecutor&lt;Transaction&gt; {


}


If you look at the source of JpaSpecificationExecutor it has,


Page&lt; T &gt; findAll(@Nullable Specification&lt;T&gt; spec, Pageable pageable);



With that you just pass the specification and Pageable to return what you expected.

Specification

@AllArgsConstructor
class TransactionSpecification implements Specification&lt;Transaction&gt; {

       private TransactionFilter transactionFilter;

       @Override
        public Predicate toPredicate(Root&lt;DataImport&gt; root, CriteriaQuery&lt;?&gt; query, CriteriaBuilder criteriaBuilder) {
            // You could add multiple Predicates based on the transactionFilter
            return criteriaBuilder.equal(root.get("table_name"), "value");
        }
}


Controller

    @Autowired
    private TransactionRepository transactionRepository;

    @GetMapping
    public Page&lt;TransactionDTO&gt; find(TransactionFilterDTO filter, Pageable page) {
        TransactionFilter transactionFilter = mapper.toFilter(filter);
        return transactionRepository.findAll(new TransactionSpecification(transactionFilter), page);
    }


I am pretty late answering but you could give it a try