Skip to content

Commit

Permalink
DATACMNS-1785 - Polishing.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mp911de committed Jan 25, 2021
1 parent a839690 commit d57fb3e
Show file tree
Hide file tree
Showing 6 changed files with 348 additions and 148 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,16 @@
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;
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;
Expand All @@ -48,7 +47,7 @@
@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;

Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,15 @@
*/
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;
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;
Expand All @@ -34,24 +32,24 @@
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
*/
Expand All @@ -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
Expand All @@ -69,10 +67,14 @@ public QuerydslBindingsFactory querydslBindingsFactory() {
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));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -46,13 +43,32 @@
* @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);
}

Expand All @@ -65,25 +81,8 @@ public QuerydslPredicateArgumentResolver(QuerydslBindingsFactory factory,
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();
Expand All @@ -94,4 +93,16 @@ public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewC
: 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;
}

}
Loading

0 comments on commit d57fb3e

Please sign in to comment.