Skip to content

Instantly share code, notes, and snippets.

@Xanaxiel
Forked from odrotbohm/StoreRepository.java
Created October 22, 2021 09:08
Show Gist options
  • Save Xanaxiel/5c0022b01ed8cf668385caec967a2ec9 to your computer and use it in GitHub Desktop.
Save Xanaxiel/5c0022b01ed8cf668385caec967a2ec9 to your computer and use it in GitHub Desktop.
Dynamic, Querydsl-based filter bindings using Spring Data REST

We’re just experimenting with some Spring Data / Spring MVC integration that will allow you to bind property path expressions in the request to a Querydsl Predicate as a Spring MVC controller method argument. This is cool for manually implemented controllers so I wondered what it takes to integrate that with Spring Data REST.

In the example above you see StoreRepository extending QuerydslPredicateExecutor<Store>. In the coming version of Spring Data REST, this will cause the collection resource exposed for the repository to accept property based filtering:

GET /stores?name=Foo

will return all stores with a name of "Foo". A plain equals(…) comparison might be a bit strict, so we expose a QuerydslBinderCustomizer interface that will allow you to customize the way properties are bound within the overall predicate.

As you can see above, the easiest way to define customized bindings is by implementing customize(…) in a default method and use the provided QuerydslBindings and entity path to tweak the binding as you like. You see we define the city to be bound via endsWith(…), String properties in general are bound via a contains(…) to make the resulting predicate less restrictive.

A working example can be found in this feature branch of the Spring Data Examples repository.

public interface StoreRepository extends PagingAndSortingRepository<Store, String>,
QueryDslPredicateExecutor<Store>, QuerydslBinderCustomizer<QStore> {
@RestResource(rel = "by-location")
Page<Store> findByAddressLocationNear(Point location, Distance distance, Pageable pageable);
default void customize(QuerydslBindings bindings, QStore store) {
bindings.bind(store.address.city).single((path, value) -> path.startsWith(value));
bindings.bind(String.class).single((StringPath path, String value) -> path.contains(value));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment