spring-projects / spring-data-jpa

Simplifies the development of creating a JPA-based data access layer.
https://spring.io/projects/spring-data-jpa/
Apache License 2.0
2.99k stars 1.41k forks source link

Specification<T>.toPredicate(...) Change type of first parameter to From<?, T> #2761

Open jobayle opened 1 year ago

jobayle commented 1 year ago

Dear spring devs,

I'd like to suggest the following change in interface Specification<T>:

Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);

to

Predicate toPredicate(From<?, T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);

Because From<T, U> is the supertype of both Root<T> and Join<T, U>, it would allow better reuse of specifications when joining tables.


Our use case is the following, we have a OneToMany relation Table CarMaker <>---> Table Car

We have already made Specification factory methods from Request DTOs for entities CarMaker and Car. We would like to reuse these 2 methods when filtering on both CarMaker and Car:

Specification<CarMaker> filterCarMakers(CarMakerRequestDTO request) { ... }

Specification<Car> filterCars(CarRequestDTO request) { ... }

Specification<CarMaker> filterCarMakersAndCars(CarMakerAndCarAggregatedRequestDTO  request) {
    return filterCarMakers(request.getCarMakerRequest())
            .and((r, q, c) -> filterCars(request.getCarRequest()).toPredicate(r.join("cars", JoinType.INNER), q, c));
}

see also: https://stackoverflow.com/a/46955740/6705221

mp911de commented 1 year ago

From an API perspective, Root declares one method more than From does, and it denotes a more specific type. Generally speaking, From could be a better alternative than Root to improve reuse of specifications. However, specifications weren't designed with reuse in mind and we have no way to introduce a non-breaking change considering the amount of existing specification implementations.

This could be a topic worth revisiting for Spring Data JPA 4.0.

mp911de commented 1 year ago

Another approach here could be the introduction of a functional-style composition API to build and reuse specification-like fragments. Anyone willing to experiment with that kind of approach can take a spike and we're happy to keep the discussion going.

bukajsytlos commented 7 months ago

when we are at it, why not Path<X>?

svenmeier commented 5 months ago

With a Path you would not be able to join or correlate, so From<T,T> seems to be a nice fit.