Reputation: 23226
I have a Spring Data Rest repository which utilises the QueryDSL support outlined here:
https://spring.io/blog/2015/09/04/what-s-new-in-spring-data-release-gosling#spring-data-rest
The default is to query all specified parameters using equals. A mechanism to override the param binding to something other than equals is given in the same article however it requires Java 8.
https://spring.io/blog/2015/09/04/what-s-new-in-spring-data-release-gosling#querydsl-web-support
Is there any clean way in Java 7 to achieve the same functionality?
I can get the binding customization working as below:
@Override
public void customize(QuerydslBindings bindings, QMember member) {
bindings.bind(member.forename).first(new SingleValueBinding<StringPath, String>() {
@Override
public Predicate bind(StringPath path, String value) {
return path.like(value);
}
});
bindings.bind(member.surname).first(new SingleValueBinding<StringPath, String>() {
@Override
public Predicate bind(StringPath path, String value) {
return path.startsWith(value);
}
});
}
However the examples all use a Java 8 default method on the repository interface to have them applied.
public interface MemberRepository extends JpaRepository<Member, Long>,
QueryDslPredicateExecutor<Member>,QuerydslBinderCustomizer<QMember> {
default void customize(QuerydslBindings bindings, QMember member) {
....
}
}
In Java 7 this is obviously not possible. I have tried with a custom repository however that fails with an error:
org.springframework.data.mapping.PropertyReferenceException: No property customize found for type Member!
public interface MemberRepositoryCustom {
public void customize(QuerydslBindings bindings, QMember member);
}
public class MemberRepositoryCustomImpl implements MemberRepositoryCustom {
@Override
public void customize(QuerydslBindings bindings, QMember member) {
bindings.bind(member.forename).first(new SingleValueBinding<StringPath, String>() {
@Override
public Predicate bind(StringPath path, String value) {
return path.like(value);
}
});
bindings.bind(member.surname).first(new SingleValueBinding<StringPath, String>() {
@Override
public Predicate bind(StringPath path, String value) {
return path.startsWith(value);
}
});
}
}
Upvotes: 3
Views: 7585
Reputation: 7169
There are two ways that you can accomplish this using Java 7. The first way is to create a generic base repository that will apply the custom bindings to all of the implemented model repositories. For example:
public class GenericModelRepository<T, ID extends Serializable, S extends EntityPath<T>> extends QueryDslJpaRepository<T, ID> implements QuerydslBinderCustomizer<S> {
public GenericModelRepository(
JpaEntityInformation<T, ID> entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager);
}
public GenericModelRepository(
JpaEntityInformation<T, ID> entityInformation,
EntityManager entityManager,
EntityPathResolver resolver) {
super(entityInformation, entityManager, resolver);
}
@Override
public void customize(QuerydslBindings bindings, S t) {
bindings.bind(String.class).first(new SingleValueBinding<StringPath, String>() {
@Override
public Predicate bind(StringPath path, String s) {
return path.equalsIgnoreCase(s);
}
});
}
}
To tell Spring Data to use this base repository when implementing all of your custom repository interfaces, simply add it as the repositoryBaseClass
in the @EnableJpaRepositories
annotation:
@Configuration
@EnableJpaRepositories(basePackages = { "me.woemler.project.repositories" }, repositoryBaseClass = GenericModelRepository.class)
@EnableTransactionManagement
public class RepositoryConfig { ... }
@RepositoryRestResource
public interface PersonRepository extends JpaRepository<Person, Long>,
QueryDslPredicateExecutor<Person>,
QuerydslBinderCustomizer<EntityPath<Person>> {
}
Now all web service StringPath
query operations will be case-insensitive equality tests:
GET http://localhost:8080/persons?name=joe%20smith
"_embedded": {
"persons": [
{
"name": "Joe Smith",
"gender": "M",
"age": 35,
"_links": {
"self": {
"href": "http://localhost:8080/persons/1"
},
"person": {
"href": "http://localhost:8080/persons/1"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost:8080/persons"
},
"profile": {
"href": "http://localhost:8080/profile/persons"
}
},
"page": {
"size": 20,
"totalElements": 1,
"totalPages": 1,
"number": 0
}
}
The second option, should you want more fine control over how each repository handling its bindings would be to create an Impl
version of the repositories you wish to customize:
public class PersonRepositoryImpl implements QuerydslBinderCustomizer<EntityPath<Person>> {
@Override
public void customize(QuerydslBindings bindings, EntityPath<Person> t) {
bindings.bind(String.class).first(new SingleValueBinding<StringPath, String>() {
@Override
public Predicate bind(StringPath path, String s) {
return path.equalsIgnoreCase(s);
}
});
}
}
You can then use the @EnableJpaRepositories
annotation normally, but you must create an Impl
instance for each of your repository interfaces that you wish to customize.
Upvotes: 4
Reputation: 1171
you can use the
BooleanBuilder
import com.mysema.query.BooleanBuilder;
to construct the queryDsl predicate
QUser quser=QUser.User;
BooleanBuilder whereClause=new BooleanBuilder();
whereClause.and(quser.property1.eq("some"));
whereClause.and(quser.property2.in(listOfValues));
springRepository.find(whereClause);
FootNote: java 8 would help reduce a lot of keystrokes for the above case
Upvotes: -1