Last active
February 25, 2016 16:42
-
-
Save mbenson/bfaca20b70c2280dceec to your computer and use it in GitHub Desktop.
inheritance-aware Spring MethodArgumentResolver; spring-boot based workaround for SPR-11055
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.lang.reflect.Method; | |
import java.util.stream.Stream; | |
import org.apache.commons.lang3.ClassUtils.Interfaces; | |
import org.apache.commons.lang3.Validate; | |
import org.apache.commons.lang3.reflect.MethodUtils; | |
import org.springframework.core.DefaultParameterNameDiscoverer; | |
import org.springframework.core.MethodParameter; | |
import org.springframework.core.ParameterNameDiscoverer; | |
import org.springframework.core.annotation.SynthesizingMethodParameter; | |
import org.springframework.web.bind.support.WebDataBinderFactory; | |
import org.springframework.web.context.request.NativeWebRequest; | |
import org.springframework.web.method.support.HandlerMethodArgumentResolver; | |
import org.springframework.web.method.support.ModelAndViewContainer; | |
public class InheritanceAwareMethodArgumentResolverWrapper implements HandlerMethodArgumentResolver { | |
private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer(); | |
public static HandlerMethodArgumentResolver wrap(HandlerMethodArgumentResolver wrapped) { | |
return wrapped instanceof InheritanceAwareMethodArgumentResolverWrapper ? wrapped | |
: new InheritanceAwareMethodArgumentResolverWrapper(wrapped); | |
} | |
private static Stream<MethodParameter> parameterHierarchy(MethodParameter parameter) { | |
return MethodUtils.getOverrideHierarchy(parameter.getMethod(), Interfaces.INCLUDE).stream() | |
.map(m -> methodParameter(m, parameter.getParameterIndex())); | |
} | |
private static MethodParameter methodParameter(Method m, int index) { | |
final MethodParameter result = new SynthesizingMethodParameter(m, index); | |
result.initParameterNameDiscovery(PARAMETER_NAME_DISCOVERER); | |
return result; | |
} | |
private final HandlerMethodArgumentResolver wrapped; | |
public InheritanceAwareMethodArgumentResolverWrapper(HandlerMethodArgumentResolver wrapped) { | |
super(); | |
this.wrapped = Validate.notNull(wrapped); | |
} | |
@Override | |
public boolean supportsParameter(MethodParameter parameter) { | |
return parameterHierarchy(parameter).anyMatch(wrapped::supportsParameter); | |
} | |
@Override | |
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, | |
WebDataBinderFactory binderFactory) throws Exception { | |
final MethodParameter mp = parameterHierarchy(parameter).filter(wrapped::supportsParameter).findFirst().orElse(null); | |
return mp == null ? null : wrapped.resolveArgument(mp, mavContainer, webRequest, binderFactory); | |
} | |
} | |
// then create an autoconfiguration with: | |
@Bean | |
public BeanPostProcessor requestHandlerAdapterPostProcessor() { | |
return new BeanPostProcessor() { | |
@Override | |
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { | |
return bean; | |
} | |
@Override | |
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { | |
if (bean instanceof RequestMappingHandlerAdapter) { | |
final RequestMappingHandlerAdapter handlerAdapter = (RequestMappingHandlerAdapter) bean; | |
handlerAdapter.setArgumentResolvers(wrap(handlerAdapter.getArgumentResolvers())); | |
handlerAdapter.setCustomArgumentResolvers(wrap(handlerAdapter.getCustomArgumentResolvers())); | |
} | |
return bean; | |
} | |
private List<HandlerMethodArgumentResolver> wrap(List<HandlerMethodArgumentResolver> resolvers) { | |
return resolvers == null ? null : resolvers.stream().map(InheritanceAwareMethodArgumentResolverWrapper::wrap).collect(toList()); | |
} | |
}; | |
} |
package com.daimler.daivb.core.web.autoconfigure;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
@Configuration
@ConditionalOnClass(WebMvcConfigurer.class)
public class FeignAwareMvcResolverConfiguration {
// then create an autoconfiguration with:
@Bean
public BeanPostProcessor requestHandlerAdapterPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof RequestMappingHandlerAdapter) {
final RequestMappingHandlerAdapter handlerAdapter = (RequestMappingHandlerAdapter) bean;
handlerAdapter.setArgumentResolvers(wrap(handlerAdapter.getArgumentResolvers()));
handlerAdapter.setCustomArgumentResolvers(wrap(handlerAdapter.getCustomArgumentResolvers()));
}
return bean;
}
private List<HandlerMethodArgumentResolver> wrap(List<HandlerMethodArgumentResolver> resolvers) {
return resolvers == null ? null
: resolvers.stream().map(InheritanceAwareMethodArgumentResolverWrapper::wrap)
.collect(Collectors.toList());
}
};
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Finally, my autoconfiguration is annotated with: