DATACMNS-1785 - Polishing.
Introduce constructors accepting non-null ConversionService, handle conversion service defaulting in configuration classes by using ObjectProvider. Extract common code to create a predicate in getPredicate(…) method. Add unit test. Convert spaces to tabs. Related ticket: #2200. Original pull request: #2274.
This commit is contained in:
@@ -16,10 +16,8 @@
|
||||
package org.springframework.data.web.config;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
@@ -27,6 +25,7 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.data.querydsl.EntityPathResolver;
|
||||
import org.springframework.data.querydsl.SimpleEntityPathResolver;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBindingsFactory;
|
||||
@@ -48,7 +47,7 @@ import com.querydsl.core.types.Predicate;
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class QuerydslWebConfiguration implements WebMvcConfigurer {
|
||||
|
||||
@Autowired @Qualifier("mvcConversionService") ObjectFactory<ConversionService> conversionService;
|
||||
@Autowired @Qualifier("mvcConversionService") ObjectProvider<ConversionService> conversionService;
|
||||
@Autowired ObjectProvider<EntityPathResolver> resolver;
|
||||
@Autowired BeanFactory beanFactory;
|
||||
|
||||
@@ -63,7 +62,7 @@ public class QuerydslWebConfiguration implements WebMvcConfigurer {
|
||||
public QuerydslPredicateArgumentResolver querydslPredicateArgumentResolver() {
|
||||
return new QuerydslPredicateArgumentResolver(
|
||||
beanFactory.getBean("querydslBindingsFactory", QuerydslBindingsFactory.class),
|
||||
Optional.of(conversionService.getObject()));
|
||||
conversionService.getIfUnique(DefaultConversionService::getSharedInstance));
|
||||
}
|
||||
|
||||
@Lazy
|
||||
|
||||
@@ -15,10 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.web.config;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
@@ -26,6 +23,7 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.data.querydsl.EntityPathResolver;
|
||||
import org.springframework.data.querydsl.SimpleEntityPathResolver;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBindingsFactory;
|
||||
@@ -34,24 +32,24 @@ import org.springframework.web.reactive.config.WebFluxConfigurer;
|
||||
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
|
||||
|
||||
/**
|
||||
* Querydsl-specific web configuration for Spring Data. Registers a {@link HandlerMethodArgumentResolver} that builds up
|
||||
* {@link Predicate}s from web requests.
|
||||
* Querydsl-specific web configuration for Spring Data. Registers a
|
||||
* {@link org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver} that builds up
|
||||
* {@link com.querydsl.core.types.Predicate}s from web requests.
|
||||
*
|
||||
* @author Matías Hermosilla
|
||||
* @author Mark Paluch
|
||||
* @since 1.11
|
||||
* @soundtrack Anika Nilles - Alter Ego
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class ReactiveQuerydslWebConfiguration implements WebFluxConfigurer {
|
||||
|
||||
@Autowired
|
||||
@Qualifier("webFluxConversionService") ObjectFactory<ConversionService> conversionService;
|
||||
@Autowired @Qualifier("webFluxConversionService") ObjectProvider<ConversionService> conversionService;
|
||||
@Autowired ObjectProvider<EntityPathResolver> resolver;
|
||||
@Autowired BeanFactory beanFactory;
|
||||
|
||||
/**
|
||||
* Default {@link ReactiveQuerydslPredicateArgumentResolver} to create Querydsl {@link Predicate} instances for
|
||||
* Spring WebFlux controller methods.
|
||||
* Default {@link ReactiveQuerydslPredicateArgumentResolver} to create Querydsl {@link Predicate} instances for Spring
|
||||
* WebFlux controller methods.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@@ -60,7 +58,7 @@ public class ReactiveQuerydslWebConfiguration implements WebFluxConfigurer {
|
||||
public ReactiveQuerydslPredicateArgumentResolver querydslPredicateArgumentResolver() {
|
||||
return new ReactiveQuerydslPredicateArgumentResolver(
|
||||
beanFactory.getBean("querydslBindingsFactory", QuerydslBindingsFactory.class),
|
||||
Optional.of(conversionService.getObject()));
|
||||
conversionService.getIfUnique(DefaultConversionService::getSharedInstance));
|
||||
}
|
||||
|
||||
@Lazy
|
||||
@@ -69,10 +67,14 @@ public class ReactiveQuerydslWebConfiguration implements WebFluxConfigurer {
|
||||
return new QuerydslBindingsFactory(resolver.getIfUnique(() -> SimpleEntityPathResolver.INSTANCE));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.web.reactive.config.WebFluxConfigurer#configureArgumentResolvers(org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer)
|
||||
*/
|
||||
@Override
|
||||
public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
|
||||
configurer.addCustomResolver(beanFactory.getBean("querydslPredicateArgumentResolver",
|
||||
ReactiveQuerydslPredicateArgumentResolver.class));
|
||||
configurer.addCustomResolver(
|
||||
beanFactory.getBean("querydslPredicateArgumentResolver", ReactiveQuerydslPredicateArgumentResolver.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,18 +16,15 @@
|
||||
package org.springframework.data.web.querydsl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBinderCustomizer;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBindings;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBindingsFactory;
|
||||
import org.springframework.data.querydsl.binding.QuerydslPredicate;
|
||||
import org.springframework.data.util.CastUtils;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
@@ -46,13 +43,32 @@ import com.querydsl.core.types.Predicate;
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @author Matías Hermosilla
|
||||
* @author Mark Paluch
|
||||
* @since 1.11
|
||||
*/
|
||||
public class QuerydslPredicateArgumentResolver extends QuerydslPredicateArgumentResolverSupport
|
||||
implements HandlerMethodArgumentResolver {
|
||||
|
||||
/**
|
||||
* Create a new {@link QuerydslPredicateArgumentResolver}.
|
||||
*
|
||||
* @param factory the {@link QuerydslBindingsFactory} to use, must not be {@literal null}.
|
||||
* @param conversionService the optional {@link ConversionService} to use, must not be {@literal null}. Defaults to
|
||||
* {@link DefaultConversionService} if {@link Optional#empty() empty}.
|
||||
*/
|
||||
public QuerydslPredicateArgumentResolver(QuerydslBindingsFactory factory,
|
||||
Optional<ConversionService> conversionService) {
|
||||
super(factory, conversionService.orElseGet(DefaultConversionService::getSharedInstance));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link QuerydslPredicateArgumentResolver}.
|
||||
*
|
||||
* @param factory the {@link QuerydslBindingsFactory} to use, must not be {@literal null}.
|
||||
* @param conversionService the {@link ConversionService} to use, must not be {@literal null}.
|
||||
* @since 2.5
|
||||
*/
|
||||
public QuerydslPredicateArgumentResolver(QuerydslBindingsFactory factory, ConversionService conversionService) {
|
||||
super(factory, conversionService);
|
||||
}
|
||||
|
||||
@@ -65,25 +81,8 @@ public class QuerydslPredicateArgumentResolver extends QuerydslPredicateArgument
|
||||
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
|
||||
|
||||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
|
||||
|
||||
for (Entry<String, String[]> entry : webRequest.getParameterMap().entrySet()) {
|
||||
parameters.put(entry.getKey(), Arrays.asList(entry.getValue()));
|
||||
}
|
||||
|
||||
Optional<QuerydslPredicate> annotation = Optional
|
||||
.ofNullable(parameter.getParameterAnnotation(QuerydslPredicate.class));
|
||||
TypeInformation<?> domainType = extractTypeInfo(parameter).getRequiredActualType();
|
||||
|
||||
Optional<Class<? extends QuerydslBinderCustomizer<?>>> bindingsAnnotation = annotation //
|
||||
.map(QuerydslPredicate::bindings) //
|
||||
.map(CastUtils::cast);
|
||||
|
||||
QuerydslBindings bindings = bindingsAnnotation //
|
||||
.map(it -> bindingsFactory.createBindingsFor(domainType, it)) //
|
||||
.orElseGet(() -> bindingsFactory.createBindingsFor(domainType));
|
||||
|
||||
Predicate result = predicateBuilder.getPredicate(domainType, parameters, bindings);
|
||||
MultiValueMap<String, String> queryParameters = getQueryParameters(webRequest);
|
||||
Predicate result = getPredicate(parameter, queryParameters);
|
||||
|
||||
if (!parameter.isOptional() && result == null) {
|
||||
return new BooleanBuilder();
|
||||
@@ -94,4 +93,16 @@ public class QuerydslPredicateArgumentResolver extends QuerydslPredicateArgument
|
||||
: result;
|
||||
}
|
||||
|
||||
private static MultiValueMap<String, String> getQueryParameters(NativeWebRequest webRequest) {
|
||||
|
||||
Map<String, String[]> parameterMap = webRequest.getParameterMap();
|
||||
MultiValueMap<String, String> queryParameters = new LinkedMultiValueMap<>(parameterMap.size());
|
||||
|
||||
for (Entry<String, String[]> entry : parameterMap.entrySet()) {
|
||||
queryParameters.put(entry.getKey(), Arrays.asList(entry.getValue()));
|
||||
}
|
||||
|
||||
return queryParameters;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,12 +21,17 @@ import java.util.Optional;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBinderCustomizer;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBindings;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBindingsFactory;
|
||||
import org.springframework.data.querydsl.binding.QuerydslPredicate;
|
||||
import org.springframework.data.querydsl.binding.QuerydslPredicateBuilder;
|
||||
import org.springframework.data.util.CastUtils;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
|
||||
import com.querydsl.core.types.Predicate;
|
||||
@@ -38,101 +43,120 @@ import com.querydsl.core.types.Predicate;
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @author Matías Hermosilla
|
||||
* @since 1.11
|
||||
* @since 2.5
|
||||
*/
|
||||
public abstract class QuerydslPredicateArgumentResolverSupport {
|
||||
|
||||
private static final ResolvableType PREDICATE = ResolvableType.forClass(Predicate.class);
|
||||
protected static final ResolvableType OPTIONAL_OF_PREDICATE = ResolvableType.forClassWithGenerics(Optional.class,
|
||||
PREDICATE);
|
||||
private static final ResolvableType PREDICATE = ResolvableType.forClass(Predicate.class);
|
||||
|
||||
protected final QuerydslBindingsFactory bindingsFactory;
|
||||
protected final QuerydslPredicateBuilder predicateBuilder;
|
||||
static final ResolvableType OPTIONAL_OF_PREDICATE = ResolvableType.forClassWithGenerics(Optional.class, PREDICATE);
|
||||
|
||||
/**
|
||||
* Creates a new {@link QuerydslPredicateArgumentResolver} using the given {@link ConversionService}.
|
||||
*
|
||||
* @param factory
|
||||
* @param conversionService defaults to {@link DefaultConversionService} if {@literal null}.
|
||||
*/
|
||||
public QuerydslPredicateArgumentResolverSupport(QuerydslBindingsFactory factory,
|
||||
Optional<ConversionService> conversionService) {
|
||||
protected final QuerydslBindingsFactory bindingsFactory;
|
||||
protected final QuerydslPredicateBuilder predicateBuilder;
|
||||
|
||||
this.bindingsFactory = factory;
|
||||
this.predicateBuilder = new QuerydslPredicateBuilder(conversionService.orElseGet(DefaultConversionService::new),
|
||||
factory.getEntityPathResolver());
|
||||
}
|
||||
/**
|
||||
* Creates a new {@link QuerydslPredicateArgumentResolver} using the given {@link ConversionService}.
|
||||
*
|
||||
* @param factory
|
||||
* @param conversionService
|
||||
*/
|
||||
protected QuerydslPredicateArgumentResolverSupport(QuerydslBindingsFactory factory,
|
||||
ConversionService conversionService) {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.web.method.support.HandlerMethodArgumentResolver#supportsParameter(org.springframework.core.MethodParameter)
|
||||
*/
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
Assert.notNull(factory, "QuerydslBindingsFactory must not be null");
|
||||
Assert.notNull(conversionService, "ConversionService must not be null");
|
||||
|
||||
ResolvableType type = ResolvableType.forMethodParameter(parameter);
|
||||
this.bindingsFactory = factory;
|
||||
this.predicateBuilder = new QuerydslPredicateBuilder(conversionService, factory.getEntityPathResolver());
|
||||
}
|
||||
|
||||
if (PREDICATE.isAssignableFrom(type) || OPTIONAL_OF_PREDICATE.isAssignableFrom(type)) {
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.web.method.support.HandlerMethodArgumentResolver#supportsParameter(org.springframework.core.MethodParameter)
|
||||
*/
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
|
||||
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()));
|
||||
}
|
||||
ResolvableType type = ResolvableType.forMethodParameter(parameter);
|
||||
|
||||
return false;
|
||||
}
|
||||
if (PREDICATE.isAssignableFrom(type) || OPTIONAL_OF_PREDICATE.isAssignableFrom(type)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the domain type information from the given method parameter. Will favor an explicitly registered on
|
||||
* through {@link QuerydslPredicate#root()} but use the actual type of the method's return type as fallback.
|
||||
*
|
||||
* @param parameter must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected static TypeInformation<?> extractTypeInfo(MethodParameter parameter) {
|
||||
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()));
|
||||
}
|
||||
|
||||
Optional<QuerydslPredicate> annotation = Optional
|
||||
.ofNullable(parameter.getParameterAnnotation(QuerydslPredicate.class));
|
||||
return false;
|
||||
}
|
||||
|
||||
return annotation.filter(it -> !Object.class.equals(it.root()))//
|
||||
.<TypeInformation<?>> map(it -> ClassTypeInformation.from(it.root()))//
|
||||
.orElseGet(() -> detectDomainType(parameter));
|
||||
}
|
||||
@Nullable
|
||||
Predicate getPredicate(MethodParameter parameter, MultiValueMap<String, String> queryParameters) {
|
||||
|
||||
private static TypeInformation<?> detectDomainType(MethodParameter parameter) {
|
||||
Optional<QuerydslPredicate> annotation = Optional
|
||||
.ofNullable(parameter.getParameterAnnotation(QuerydslPredicate.class));
|
||||
TypeInformation<?> domainType = extractTypeInfo(parameter).getRequiredActualType();
|
||||
|
||||
Method method = parameter.getMethod();
|
||||
Optional<Class<? extends QuerydslBinderCustomizer<?>>> bindingsAnnotation = annotation //
|
||||
.map(QuerydslPredicate::bindings) //
|
||||
.map(CastUtils::cast);
|
||||
|
||||
if (method == null) {
|
||||
throw new IllegalArgumentException("Method parameter is not backed by a method!");
|
||||
}
|
||||
QuerydslBindings bindings = bindingsAnnotation //
|
||||
.map(it -> bindingsFactory.createBindingsFor(domainType, it)) //
|
||||
.orElseGet(() -> bindingsFactory.createBindingsFor(domainType));
|
||||
|
||||
return detectDomainType(ClassTypeInformation.fromReturnTypeOf(method));
|
||||
}
|
||||
return predicateBuilder.getPredicate(domainType, queryParameters, bindings);
|
||||
}
|
||||
|
||||
private static TypeInformation<?> detectDomainType(TypeInformation<?> source) {
|
||||
/**
|
||||
* Obtains the domain type information from the given method parameter. Will favor an explicitly registered on through
|
||||
* {@link QuerydslPredicate#root()} but use the actual type of the method's return type as fallback.
|
||||
*
|
||||
* @param parameter must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected static TypeInformation<?> extractTypeInfo(MethodParameter parameter) {
|
||||
|
||||
if (source.getTypeArguments().isEmpty()) {
|
||||
return source;
|
||||
}
|
||||
Optional<QuerydslPredicate> annotation = Optional
|
||||
.ofNullable(parameter.getParameterAnnotation(QuerydslPredicate.class));
|
||||
|
||||
TypeInformation<?> actualType = source.getActualType();
|
||||
return annotation.filter(it -> !Object.class.equals(it.root()))//
|
||||
.<TypeInformation<?>> map(it -> ClassTypeInformation.from(it.root()))//
|
||||
.orElseGet(() -> detectDomainType(parameter));
|
||||
}
|
||||
|
||||
if (actualType == null) {
|
||||
throw new IllegalArgumentException(String.format("Could not determine domain type from %s!", source));
|
||||
}
|
||||
private static TypeInformation<?> detectDomainType(MethodParameter parameter) {
|
||||
|
||||
if (source != actualType) {
|
||||
return detectDomainType(actualType);
|
||||
}
|
||||
Method method = parameter.getMethod();
|
||||
|
||||
if (source instanceof Iterable) {
|
||||
return source;
|
||||
}
|
||||
if (method == null) {
|
||||
throw new IllegalArgumentException("Method parameter is not backed by a method!");
|
||||
}
|
||||
|
||||
return detectDomainType(source.getRequiredComponentType());
|
||||
}
|
||||
return detectDomainType(ClassTypeInformation.fromReturnTypeOf(method));
|
||||
}
|
||||
|
||||
private static TypeInformation<?> detectDomainType(TypeInformation<?> source) {
|
||||
|
||||
if (source.getTypeArguments().isEmpty()) {
|
||||
return source;
|
||||
}
|
||||
|
||||
TypeInformation<?> actualType = source.getActualType();
|
||||
|
||||
if (actualType == null) {
|
||||
throw new IllegalArgumentException(String.format("Could not determine domain type from %s!", source));
|
||||
}
|
||||
|
||||
if (source != actualType) {
|
||||
return detectDomainType(actualType);
|
||||
}
|
||||
|
||||
if (source instanceof Iterable) {
|
||||
return source;
|
||||
}
|
||||
|
||||
return detectDomainType(source.getRequiredComponentType());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2021 the original author or authors.
|
||||
* Copyright 2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,76 +19,66 @@ import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.core.types.Predicate;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBinderCustomizer;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBindings;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBindingsFactory;
|
||||
import org.springframework.data.querydsl.binding.QuerydslPredicate;
|
||||
import org.springframework.data.util.CastUtils;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.reactive.BindingContext;
|
||||
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.core.types.Predicate;
|
||||
|
||||
/**
|
||||
* {@link HandlerMethodArgumentResolver} to allow injection of {@link com.querydsl.core.types.Predicate} into Spring
|
||||
* WebFlux controller methods.
|
||||
*
|
||||
* @author Matías Hermosilla
|
||||
* @since 1.11
|
||||
* @author Mark Paluch
|
||||
* @since 2.5
|
||||
*/
|
||||
public class ReactiveQuerydslPredicateArgumentResolver extends QuerydslPredicateArgumentResolverSupport
|
||||
implements HandlerMethodArgumentResolver {
|
||||
implements SyncHandlerMethodArgumentResolver {
|
||||
|
||||
public ReactiveQuerydslPredicateArgumentResolver(QuerydslBindingsFactory factory,
|
||||
Optional<ConversionService> conversionService) {
|
||||
ConversionService conversionService) {
|
||||
super(factory, conversionService);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @seeorg.springframework.web.reactive.result.method.HandlerMethodArgumentResolver#resolveArgument(org.springframework.core.MethodParameter, org.springframework.web.reactive.BindingContext, org.springframework.web.server.ServerWebExchange)
|
||||
* @see org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver(org.springframework.core.MethodParameter, org.springframework.web.reactive.BindingContext, org.springframework.web.server.ServerWebExchange)
|
||||
*/
|
||||
@Override
|
||||
public Mono<Object> resolveArgument(MethodParameter parameter, BindingContext bindingContext,
|
||||
public Object resolveArgumentValue(MethodParameter parameter, BindingContext bindingContext,
|
||||
ServerWebExchange exchange) {
|
||||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
|
||||
|
||||
for (Entry<String, List<String>> entry : exchange.getRequest().getQueryParams().entrySet()) {
|
||||
parameters.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
Optional<QuerydslPredicate> annotation = Optional
|
||||
.ofNullable(parameter.getParameterAnnotation(QuerydslPredicate.class));
|
||||
TypeInformation<?> domainType = extractTypeInfo(parameter).getRequiredActualType();
|
||||
|
||||
Optional<Class<? extends QuerydslBinderCustomizer<?>>> bindingsAnnotation = annotation //
|
||||
.map(QuerydslPredicate::bindings) //
|
||||
.map(CastUtils::cast);
|
||||
|
||||
QuerydslBindings bindings = bindingsAnnotation //
|
||||
.map(it -> bindingsFactory.createBindingsFor(domainType, it)) //
|
||||
.orElseGet(() -> bindingsFactory.createBindingsFor(domainType));
|
||||
|
||||
Predicate result = predicateBuilder.getPredicate(domainType, parameters, bindings);
|
||||
MultiValueMap<String, String> queryParameters = getQueryParameters(exchange);
|
||||
Predicate result = getPredicate(parameter, queryParameters);
|
||||
|
||||
if (!parameter.isOptional() && result == null) {
|
||||
return Mono.just(new BooleanBuilder());
|
||||
return new BooleanBuilder();
|
||||
}
|
||||
|
||||
return OPTIONAL_OF_PREDICATE.isAssignableFrom(ResolvableType.forMethodParameter(parameter)) //
|
||||
? Mono.justOrEmpty(Optional.ofNullable(result)) //
|
||||
: Mono.justOrEmpty(result);
|
||||
? Optional.ofNullable(result) //
|
||||
: result;
|
||||
}
|
||||
|
||||
private static MultiValueMap<String, String> getQueryParameters(ServerWebExchange exchange) {
|
||||
|
||||
MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
|
||||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>(queryParams.size());
|
||||
|
||||
for (Entry<String, List<String>> entry : queryParams.entrySet()) {
|
||||
parameters.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user