Spring Questions @QuerydslPredicate

Leaders Used

Spring Download 1.3.2.RELEASE

QueryDSL 3.7.2

QueryDSL Maven Plugin 1.1.3

Sleep mode 4.3.11. The final

Problem

I currently have a Spring boot application that has some basic CRUD functions using Spring Data JPA (running Hibernate) and auditing using Spring Data Envers. I also have the following endpoint for getting a list of objects from:

http: // localhost: 8080 / test-app / list

Now I wanted to use the new QueryDSL support that Spring offers through the @QuerydslPredicate annotation. This works great for most fields or sub-entities, but it doesn't seem to work for collections of sub-entities. The documentation, blog posts, etc., do not seem to cover this case - and the only information I can find is that it supports "in" for simple collections (ie String Collections, etc. .).

So my entity is set up something like this:

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; } 

I generate my Q classes using com.mysema.maven:apt-maven-plugin , which generates my QPerson with the following field:

 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); 

If I try to execute a request for this, I get an exception:

Query:

http: // localhost: 8080 / test-app / list? pets.age = 5

An exception:

 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] 

Now this query looks like it is trying to solve the Person.pets.age property. It correctly identifies Person.pets as a ListPath , and then tries to identify CompanyAddress.addressLine1 (which seems correct). The problem is that he is trying to use the entity path to get the class, which is ListPath instead of QPet :

 Field field = ReflectionUtils.findField(entityPath.getClass(), path.getSegment()); Object value = ReflectionUtils.getField(field, entityPath); 

The following query works as expected:

http: // localhost: 8080 / test-app / list? name = Bob

I was expecting the following predicate to be built using ?pets.age=5 :

 QPerson.person.pets.any().age.eq(5) 

Is this possible with Spring QuerydslPredicate support? Or do I need to manually build predicates from query parameters?

Additional question

As an additional question, you can use QuerydslPredicate. Let's say I have firstName and lastName for pets, and I want to run the query only with name=Bob :

http: // localhost: 8080 / test-app / pet / list? name = Bob

I would like the query predicate to be constructed as follows:

 final BooleanBuilder petBuilder = new BooleanBuilder(); petBuilder.and(QPet.firstName.equals("Bob").or(QPet.lastName.equals("Bob"))); 

Is it possible? From a look at the QuerydslBinderCustomizer configuration QuerydslBinderCustomizer this does not look like you need to bind a Q class field. I assume that what I want to do is not supported.

If this is not possible, I will stick with it manually, creating a predicate and passing it to the repository.

+5
source share
2 answers

You can use QuerydslBinderCustomizer to achieve your goal. Here is sample code that might help you:

 public interface PersonRepository extends JpaRepository<Job, Integer>, QueryDslPredicateExecutor<Person>, QuerydslBinderCustomizer<QJob> { @Override public default void customize(final QuerydslBindings bindings, final QPerson person) { bindings.bind(person.pets.any().name).first((path, value) -> { return path.eq(value); }); } } 
+1
source

I came across the same error. However, I noticed that using the QuerydslAnnotationProcessor plugin (instead of the JPA annotation processor) allows me to query subcategories of objects as expected. You just need to mark all entity classes with the @QueryEntity annotation. (The JPA annotation engine automatically generates query classes for annotated @Entity classes.)

In your pom:

  <plugin> <groupId>com.mysema.maven</groupId> <artifactId>apt-maven-plugin</artifactId> <version>1.1.3</version> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>process</goal> </goals> <configuration> <outputDirectory>target/generated-sources/annotations</outputDirectory> <processor>com.querydsl.apt.QuerydslAnnotationProcessor</processor> </configuration> </execution> </executions> <dependencies> <dependency> <groupId>com.querydsl</groupId> <artifactId>querydsl-apt</artifactId> <version>4.1.3</version> </dependency> </dependencies> </plugin> 

I suppose I came across the exception that you encountered because I changed it from the JPA Annotation Processor to QuerydslAnnotationProcessor, for some reason I don’t remember, and neglected to mark the entity class of the list in question with @ Annotations QueryEntity. However, I also believe that I have another Spring -Data-Rest \ JPA API that uses the JPA Annotation Processor, built in August 2017, and I believe that object sub-deposit requests work as expected. I can confirm this later today and provide versions of the respective dependencies, if so. Perhaps this issue has been fixed.

+1
source

Source: https://habr.com/ru/post/1244823/


All Articles