spring-data-commons icon indicating copy to clipboard operation
spring-data-commons copied to clipboard

QuerydslPredicateArgumentResolver supportsParameter condition to determine the problem [DATACMNS-1623]

Open spring-projects-issues opened this issue 6 years ago • 4 comments

ft0907 opened DATACMNS-1623 and commented

As long as the reference type is Predicate, it will directly enter the QuerydslPredicateArgumentResolver, which greatly reduces the ability of the Predicate type to customize the ArgumentResolver.The following is the specific code

@Override
public boolean supportsParameter(MethodParameter parameter) {

   //Here to judge the serious impact, as long as the parameter type is //Predicate, directly execute QuerydslPredicateArgumentResolver
   if (Predicate.class.equals(parameter.getParameterType())) {
      return true;
   }

   if (parameter.hasParameterAnnotation(QuerydslPredicate.class)) {
      throw new IllegalArgumentException(String.format("Parameter at position %s must be of type Predicate but was %s.",
            parameter.getParameterIndex(), parameter.getParameterType()));
   }

   return false;
}

amend as below

@Override
public boolean supportsParameter(MethodParameter parameter) {

   if (parameter.hasParameterAnnotation(QuerydslPredicate.class) && !Predicate.class.equals(parameter.getParameterType())) {
      throw new IllegalArgumentException(String.format("Parameter at position %s must be of type Predicate but was %s.",
            parameter.getParameterIndex(), parameter.getParameterType()));
   }

   return parameter.hasParameterAnnotation(QuerydslPredicate.class);
}

 

I have modified the code here on github

https://github.com/spring-projects/spring-data-commons/pull/419

 


Affects: 2.2.2 (Moore SR2)

Referenced from: pull request https://github.com/spring-projects/spring-data-commons/pull/419

spring-projects-issues avatar Nov 19 '19 08:11 spring-projects-issues

Oliver Drotbohm commented

Can we step back a bit and clarify what the actual problem is that we're trying to solve? The proposed PR simply turns a test case from expecting true to false. The original test case was created for a reason which makes me wonder what would make us invert the expectation it expresses.

Can you please give an example of user code that is not working as expected or would try to do something that should work but doesn't right now?

spring-projects-issues avatar Nov 22 '19 09:11 spring-projects-issues

ft0907 commented

As shown in the code below, when I use the custom @CustomizeQuerydslPredicate, my custom annotation method will not be executed, because the supportsParameter method in the @QuerydslPredicateArgumentResolver class will always execute true, so an error will occur in subsequent executions.

ResponseEntity<?> list(@CustomizeQuerydslPredicate(root = Category.class) Predicate predicate);//

The above code will appear the following error

Unable to find Querydsl root type for detected domain type class java.lang.Object! User @QuerydslPredicate's root attribute to define the domain type manually!] with root cause 
//The reason for this problem is that the judgment here returns true.
if(Predicate.class.equals(parameter.getParameterType())) { 
   return true; 
}

So all CustomizePredicateArgumentResolvers written for Predicate will execute QuerydslPredicateArgumentResolver instead of our custom CustomizePredicateArgumentResolver,

I don't know if I describe it clearly enough. If I don't know, I can provide a test code.Oliver Drotbohm

 

 

spring-projects-issues avatar Nov 24 '19 13:11 spring-projects-issues

Oliver Drotbohm commented

I agree that this is unfortunate and we should find a fix for the problem. However, your proposed change would break all implementations that previously just used Predicate as a parameter type and did not explicitly annotate them.

I'd much rather evaluate options to make sure that you can register your custom HandlerMethodArgumentResolver or even allow you to tweak our implementation so that you don't even need the custom implementation in the first place. What are you doing in your implementation exactly?

spring-projects-issues avatar Nov 25 '19 20:11 spring-projects-issues

ft0907 commented

Thank you very much for your reply, because the existing QuerydslPredicateArgumentResolver cannot achieve the function I need 1.We need QuerydslPredicateArgumentResolver to return a parsed parameter directly, preferably map, because we are a mvc mode project, we need to record the correct parsing parameters to return to the page again. Of course, there are other solutions that can be implemented. The custom HandlerMethodArgumentResolver only binds a Predicate for implementation, the code will look more elegant, and rsql may be introduced in the future. A custom implementation is required, similar to this @RsqlPredicate(root = Content.class) Predicate predicate 2.We don't allow QuerydslPredicateArgumentResolver to return a Predicate object with a null value. This will allow us to directly call the QuerydslRepository interface method similar to "findAll" to determine whether Predicate is null So if you can customize an annotation @CustomizeQuerydslPredicate for the parameter Predicate, it will be more straightforward, because this is not a general-purpose function. If you modify the QuerydslPredicateArgumentResolver implementation directly, it will not break the general type. Of course, if you guys have a better solution, I would be happy to accept it

spring-projects-issues avatar Nov 26 '19 01:11 spring-projects-issues

There are three workarounds:

  1. Implement WebMvcConfigurer and add your bean before QuerydslPredicateArgumentResolver
  2. Disable QuerydslWebConfiguration and configure a subclass with your customizations of QuerydslPredicateArgumentResolver
  3. Create a BeanPostProcessor and exchange the actual bean being used for QuerydslPredicateArgumentResolver.

mp911de avatar Sep 14 '23 12:09 mp911de