Spring @QuerydslPredicate Questions

Libários usados

Spring Boot 1.3.2.RELEASE

QueryDSL 3.7.2

QueryDSL Maven Plugin 1.1.3

Hibernate 4.3.11.Final

Questão

Atualmente, 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 umListPathe 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 adicional

Como 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.

questionAnswers(2)

yourAnswerToTheQuestion