Spring @QuerydslPredicate Questions
Spring Boot 1.3.2.RELEASE
QueryDSL 3.7.2
QueryDSL Maven Plugin 1.1.3
Hibernate 4.3.11.Final
QuestãoAtualmente, tenho um aplicativo Spring Boot que possui algumas funcionalidades básicas de CRUD usando o Spring Data JPA (suportado pelo Hibernate) e auditando usando o Spring Data Envers. Eu também tenho o seguinte ponto de extremidade para recuperar uma lista de entidades de:
http: // localhost: 8080 / test-app / list
Agora, eu queria usar onovo suporte QueryDSL que o Spring oferece através de@QuerydslPredicate
anotação. Isso funciona bem para a maioria dos campos ou subentidades, mas não parece funcionar para coleções de subentidades. A documentação, as postagens do blog etc. não parecem cobrir esse caso - e a única informação que pude encontrar é que ela suporta "in" para coleções simples (ou seja, coleções de String etc.).
Então, minha entidade está configurada da seguinte forma:
Person.java
@Data
@Entity
@Audited
public class Person {
@Id
private long id;
private String name;
private List<Pet> pets = new ArrayList<>();
}
Pet.java
@Data
@Entity
@Audited
public class Pet {
@Id
private long id;
private int age;
}
Eu gero minhas classes Q usando ocom.mysema.maven:apt-maven-plugin
, o que gera meuQPerson
com o seguinte campo:
public final ListPath<com.test.Pet, com.test.QPet> pets = this.<com.test.Pet, com.test.QPet>createList("pets", com.test.Pet.class, com.test.QPet.class, PathInits.DIRECT2);
Se eu tentar consultar isso, recebo uma exceção:
Inquerir:
http: // localhost: 8080 / test-app / list? pets.age = 5
Exceção:
10:21:37,523 ERROR [org.springframework.boot.context.web.ErrorPageFilter] (http-/127.0.0.1:8080-1) Forwarding to error page from request [/list] due to exception [null]: java.lang.NullPointerException
at org.springframework.util.ReflectionUtils.getField(ReflectionUtils.java:143) [spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.data.querydsl.binding.QuerydslPredicateBuilder.reifyPath(QuerydslPredicateBuilder.java:185) [spring-data-commons-1.11.2.RELEASE.jar:]
at org.springframework.data.querydsl.binding.QuerydslPredicateBuilder.reifyPath(QuerydslPredicateBuilder.java:188) [spring-data-commons-1.11.2.RELEASE.jar:]
at org.springframework.data.querydsl.binding.QuerydslPredicateBuilder.getPath(QuerydslPredicateBuilder.java:167) [spring-data-commons-1.11.2.RELEASE.jar:]
at org.springframework.data.querydsl.binding.QuerydslPredicateBuilder.invokeBinding(QuerydslPredicateBuilder.java:136) [spring-data-commons-1.11.2.RELEASE.jar:]
at org.springframework.data.querydsl.binding.QuerydslPredicateBuilder.getPredicate(QuerydslPredicateBuilder.java:111) [spring-data-commons-1.11.2.RELEASE.jar:]
at org.springframework.data.web.querydsl.QuerydslPredicateArgumentResolver.resolveArgument(QuerydslPredicateArgumentResolver.java:106) [spring-data-commons-1.11.2.RELEASE.jar:]
at org.springframework.data.web.querydsl.QuerydslPredicateArgumentResolver.resolveArgument(QuerydslPredicateArgumentResolver.java:48) [spring-data-commons-1.11.2.RELEASE.jar:]
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:78) [spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
Agora, esta consulta parece estar tentando resolver o propertyPathPerson.pets.age
. Identifica corretamentePerson.pets
como umListPath
e tenta identificarCompanyAddress.addressLine1
(o que parece correto). O problema é que ele tenta usar o caminho da entidade para obter a classe, que é aListPath
ao invés deQPet
:
Field field = ReflectionUtils.findField(entityPath.getClass(), path.getSegment());
Object value = ReflectionUtils.getField(field, entityPath);
A consulta a seguir funciona conforme o esperado:
http: // localhost: 8080 / test-app / list? name = Bob
Minha expectativa era que, usando?pets.age=5
, o seguinte predicado seria criado:
QPerson.person.pets.any().age.eq(5)
No momento, isso é possível com o suporte QuerydslPredicate do Spring? Ou devo criar manualmente os predicados a partir dos parâmetros da consulta?
Pergunta adicionalComo uma pergunta adicional, é possível o seguinte com QuerydslPredicate. Digamos que eu tenha um nome e um sobrenome no animal de estimação e desejo executar uma consulta com apenasname=Bob
:
http: // localhost: 8080 / test-app / pet / list? name = Bob
Eu gostaria que o predicado de consulta fosse construído assim:
final BooleanBuilder petBuilder = new BooleanBuilder();
petBuilder.and(QPet.firstName.equals("Bob").or(QPet.lastName.equals("Bob")));
Isso é possível? Observando o método de personalização doQuerydslBinderCustomizer
não parece que seria, já que você precisa vincular um campo da classe Q. Estou supondo que o que eu quero fazer não seja suportado.
Se isso não for possível, continuarei criando manualmente o predicado e transmitindo-o ao repositório.