Is it possible to wire a Spring MVC Interceptor using annotations? - spring

Is it possible to wire a Spring MVC Interceptor using annotations and if so could someone provide me with an example of how to do so?
By wire via annotation I am referring to doing as little in the XML configuration as possible. For example in this configuration file I found at http://www.vaannila.com/spring/spring-interceptors.html;
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" p:interceptors-ref="loggerInterceptor" />
<bean id="loggerInterceptor" class="com.vaannila.interceptor.LoggerInterceptor" />
How little configuration could you get away with there? I imagine an #Autowired would remove the need to explicitly declare the bean in line 2, but would it be possible to get rid of line 1 with an annotation as well?

Stumbled upon this question while searching exactly this. Finally I found out that it works in Spring 3.1 using #EnableWebMVC in conjunction with WebMvcConfigurerAdapter.
Simple Example:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages="webapp.base.package")
public class WebApplicationConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoggerInterceptor());
}
}

As far as I know, there are no ways to configure Spring MVC interceptors without XML at all.
However, there are some simplifications with mvc namespace in the latest versions of Spring 3.0.x (not Spring 3.0.0!):
<mvc:interceptors>
<bean class="com.vaannila.interceptor.LoggerInterceptor" />
</mvc:interceptors>
See also:
MVC Simplifications in Spring 3.0

I implemented a working solution using a custom #Interceptor annotation in the spirit of Spring's #Controller annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE})
#Documented
#Component
public #interface Interceptor {
String[] pathPatterns() default {};
String[] excludePathPatterns() default {};
}
This annotation should be applied to HandlerInterceptor types like so:
#Interceptor
public class BuildTimestampInterceptor extends HandlerInterceptorAdapter {
private final String buildTimestamp;
public BuildTimestampInterceptor(#Value("${build.timestamp}") String buildTimestamp) {
this.buildTimestamp = buildTimestamp;
}
#Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
req.setAttribute("buildTimestamp", buildTimestamp);
return true;
}
}
Finally, the processor class, InterceptorProcessor, is a Spring bean that extends WebMvcConfigurerAdapter and implements BeanPostProcessor in order to scan for the custom #Interceptor annotations and register beans having that anntation as HandlerInterceptors inside the overridden addInterceptors method:
#Component
public class InterceptorProcessor extends WebMvcConfigurerAdapter implements BeanPostProcessor {
private final Map<HandlerInterceptor,Interceptor> interceptors = new HashMap<>();
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
scanForInterceptorAnnotation(bean, beanName);
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String string) throws BeansException {
return bean;
}
protected void scanForInterceptorAnnotation(Object bean, String beanName) {
Optional<Interceptor> optionalInterceptor = getInterceptorAnnotation(bean.getClass());
if (optionalInterceptor.isPresent() && bean instanceof HandlerInterceptor) {
interceptors.put((HandlerInterceptor) bean, optionalInterceptor.get());
}
}
private Optional<Interceptor> getInterceptorAnnotation(Class cls) {
Annotation[] annotations = cls.getAnnotationsByType(Interceptor.class);
if (hasValue(annotations)) {
return Optional.of((Interceptor) annotations[0]);
}
return Optional.empty();
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
interceptors.forEach((HandlerInterceptor key, Interceptor val) -> {
InterceptorRegistration registration = registry.addInterceptor(key);
if (hasValue(val.pathPatterns())) {
registration.addPathPatterns(val.pathPatterns());
}
if (hasValue(val.excludePathPatterns())) {
registration.excludePathPatterns(val.excludePathPatterns());
}
});
}
private static <T> boolean hasValue(T[] array) {
return array != null && array.length > 0;
}
}
Just remember to have your spring application scan for this processor bean in order to have it actually register your #Interceptors. Something like:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"org.my.controller", "org.my.utils.processor"})
public class WebConfig extends WebMvcConfigurerAdapter {...

I dont know about spring-AOP but if you're using AspectJ via Spring you can use #Aspect, #Pointcut, #Advise and more...
there's also a nice article on howto use these annotation with Spring AOP here:
http://java-x.blogspot.com/2009/07/spring-aop-with-aspecj-annotations.html

like Markus Kreusch'answers,It also could work like this
#Configuration
#EnableWebMvc
#ComponentScan(basePackages="webapp.base.package")
public class WebApplicationConfig extends WebMvcConfigurerAdapter {
#Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping RequestMappingHandlerMapping= super.requestMappingHandlerMapping();
Object[] interceptors = new Object[1];
interceptors[0] = new RoleInterceptor();
RequestMappingHandlerMapping.setInterceptors(interceptors);
return RequestMappingHandlerMapping;
}
}

Related

Spring requests preprocessing per session

I'd like create Spring request Interceptor which will be able to get some data from session and change some #Autowired components before request.
I can create Interceptor and register it, but it can't get access to session beans:
#Component
#Scope(value="session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class TokenInterceptor extends HandlerInterceptorAdapter {
#Autowired
private MyServicePerSession myServicePerSession;
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(myServicePerSession.getName()); // NullPointerException!!!
return true;
}
}
Above in the method preHandle(...) per each request I get NullPointerException.
Here is my config:
#Configuration
#EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {
//...
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TokenInterceptor());
}
}
How I said everything work fine except injecting MyServicePerSession.
I will really appreciate if you can give me advice about it, or some other ways to solve that problem.
You are trying to set a new object but you have to set a spring bean.
new TokenInterceptor() // is not spring bean
#Autowired private TokenInterceptor tokenInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenInterceptor);
// You have to set bean here
}
If this doesn't work, you can check this http://docs.spring.io/spring-javaconfig/docs/1.0.0.M4/reference/html/ch04s02.html

#Before #PostConstruct Spring AOP ineterception

I'm trying to write an aspect that can intercept PostConstruct methods. I've looked at related questions on SO and others, and following them, this is what I have so far:
The Spring configuration
#Configuration
#EnableAspectJAutoProxy
#EnableLoadTimeWeaving
#...//other config annotations
public class WebConfiguration {
#Bean
public CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor() {
return new CommonAnnotationBeanPostProcessor();
}
... // etc
}
The annotation:
#Retention(RetentionPolicy.RUNTIME)
public #interface Secured {
Permission[] permissions() default {};
}
The bean
#Component
#Scope("request")
public class SomeWebBean {
#Secured(permissions = Permission.SOME_PERMISSION)
#PostConstruct
public void secure() {
... // some stuff
}
}
The aspect
#Component
#Aspect
public class SecuredAspect {
#Before("#annotation(secured)")
public void doAccessCheck(Secured secured) {
... // actually do the access check
}
}
If I call someWebBean.secure() from a page, then the aspect is invoked. However, it is not invoked on bean creation.
So as a note to future me - this absolutely cannot be done in this way using Spring AOP.
However, the same effect can be achieved by implementing a BeanPostProcessor as below:
public class SecureBeanPostProcessor implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Secured secured = bean.getClass().getAnnotation(Secured.class);
if (secured != null) {
// do your security test here, throw an exception, return false, however you like
}
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
You can extend CommonAnnotationBeanPostProcessor and override postProcessBeforeInitialization(Object bean, String beanName)
Then register replace the original CommonAnnotationBeanPostProcessor with a BeanFactoryPostProcessor .
public class InitCommonAnnotationBeanPostProcessor extends CommonAnnotationBeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return super.postProcessBeforeInitialization(bean, beanName);
}
}
public class InitBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
RootBeanDefinition def = new RootBeanDefinition(InitCommonAnnotationBeanPostProcessor.class);
def.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AnnotationConfigUtils.COMMON_ANNOTATION_PROCESSOR_BEAN_NAME, def);
}
}
#Configuration
public class InitialisationMonitoringConfig {
public static final String BEAN_INIT_MONITOR = "BEAN_INIT_MONITOR";
#Bean
public static InitBeanFactoryPostProcessor initBeanFactoryPostProcessor() {
return new InitBeanFactoryPostProcessor();
}
}
This is ugly, but I had to do that to analyse startup times in dev environment.
Maybe it's enough to just declare InitCommonAnnotationBeanPostProcessor as a bean, I didn't tried.

#Autowired does not work with #Configurable

I am trying to do an image upload API. I have a ImageUpload task as follows,
#Component
#Configurable(preConstruction = true)
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class ImageUploadTask implements Callable<JSONObject> {
#Autowired
private ImageUploadService imageUploadService;
#Override
public JSONObject call() throws Exception {
....
//Upload image via `imageUploadService`
imageUploadService.getService().path('...').post('...'); // Getting null pointer here for imageUploadService which is a WebTarget
}
}
The ImageUploadService looks like the below,
#Component
public class ImageUploadService {
#Inject
#EndPoint(name="imageservice") //Custom annotation, battle tested and works well for all other services
private WebTarget imageservice;
public WebTarget getService() {
return imageservice;
}
}
Here is the spring boot application class,
#ComponentScan
#EnableSpringConfigured
#EnableLoadTimeWeaving(aspectjWeaving=EnableLoadTimeWeaving.AspectJWeaving.ENABLED)
#EnableAutoConfiguration
public class ImageApplication extends SpringBootServletInitializer {
#Bean
public InstrumentationLoadTimeWeaver loadTimeWeaver() throws Throwable {
InstrumentationLoadTimeWeaver loadTimeWeaver = new InstrumentationLoadTimeWeaver();
return loadTimeWeaver;
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
servletContext.addListener(new RequestContextListener());
}
public static void main(String[] args) throws IOException {
SpringApplication.run(ImageApplication.class);
}
}
Additional information :
Spring version of dependencies are at 4.2.5.RELEASE
pom.xml has dependencies added for spring-aspects and
spring-instrument
I am getting a NullPointerException in ImageUploadTask. My suspicion is that #Autowired doesn't work as expected.
Why wouldn't work and how do I fix this?
Is it mandatory to use #Autowired only when I use #Conigurable, why not use #Inject? (though I tried it and getting same NPE)
By default the autowiring for the #Configurable is off i.e. Autowire.NO beacuse of which the imageUploadService is null
Thus update the code to explicity enable it either as BY_NAME or BY_TYPE as below.
#Component
#Configurable(preConstruction = true, autowire = Autowire.BY_NAME)
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class ImageUploadTask implements Callable<JSONObject> { .... }
Rest of the configuration viz. enabling load time weaving seems fine.
Also regarding #Inject annotation have a look here which pretty much explains the difference (or similarity perhaps)

Rest Custom HTTP Message Converter Spring Boot 1.2.3

I want to create a custom of HttpMessageConverter using Rest, Json, Spring Boot 1.2.3 and Spring 4, However my custom HTTPMessageConverter its' never called.
I have preformed the following steps :
1: Created a class that extends AbstractHttpMessageConverter
#Component
public class ProductConverter extends AbstractHttpMessageConverter<Employee> {
public ProductConverter() {
super(new MediaType("application", "json", Charset.forName("UTF-8")));
System.out.println("Created ");
}
#Override
protected boolean supports(Class<?> clazz) {
return false;
}
#Override
protected Employee readInternal(Class<? extends Employee> clazz,
HttpInputMessage inputMessage) throws IOException,
HttpMessageNotReadableException {
InputStream inputStream = inputMessage.getBody();
System.out.println("Test******");
return null;
}
#Override
protected void writeInternal(Employee t,
HttpOutputMessage outputMessage) throws IOException,
HttpMessageNotWritableException {
// TODO Auto-generated method stu
}
}
2: I create a configuration class to register HTTPMessageConverters
#Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter{
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
System.out.println("Configure Message Converters");
converters.add(new ProductConverter());
super.configureMessageConverters(converters);
//super.extendMessageConverters(converters);
}
}
3: The rest class method
#RequestMapping(value="/{categoryId}" ,method=RequestMethod.POST, consumes="application/json")
#PreAuthorize("permitAll")
public ResponseEntity<ProductEntity> saveProduct(#RequestBody Employee employee , #PathVariable Long categoryId) {
logger.log(Level.INFO, "Category Id: {0}" , categoryId);
ResponseEntity<ProductEntity> responseEntity =
new ResponseEntity<ProductEntity>(HttpStatus.OK);
return responseEntity;
}
My Custom HTTPMessageCoverter it's created but is never called ? Is there a configuration or step I'm missing ? any input or advice is appreciated.
After overriding the (AbstractHttpMessageConverter) class methods, I found out there's two annotations for achieving polymorphism #JsonTypeInfo and #JsonSubTypes. For anyone who wants achieve polymorphism can use these two annotations.
I believe you want to configure these message converters using the configureMessageConverters method in a configuration class that extends WebMvcConfigurerAdapter. I've done this myself with a converter for CSV content. I've included that code below. This link shows an example as well. This link may also be helpful. It seems like with Spring configuration it is not always clear on the best place to configure things. :) Let me know if this helps.
#Configuration
public class ApplicationWebConfiguration extends WebMvcConfigurerAdapter {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
super.configureMessageConverters(converters);
converters.add(new CsvMessageConverter());
}
}
You will also need top modify your supports() method to return true for classes supported by the converter. See the Spring doc for AbstractHttpMessageConverter supports method.

How do I autowire dependencies into Spring #Configuration instances?

I need to inject an object into my No XML Spring #Configuration object as follows:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "web.client")
public class WebApplicationConfiguration extends WebMvcConfigurerAdapter {
private static final Logger log = LoggerFactory.getLogger(WebApplicationConfiguration.class);
#Inject
private MonitoringExceptionResolver resolver; // always null
#Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
log.debug("configuring exception resolvers");
super.configureHandlerExceptionResolvers(exceptionResolvers);
exceptionResolvers.add(new DefaultHandlerExceptionResolver());
exceptionResolvers.add(new AnnotationMethodHandlerExceptionResolver());
exceptionResolvers.add(new ResponseStatusExceptionResolver());
exceptionResolvers.add(resolver); // passing null ref here
}
}
Where MonitoringExceptionResolver is defined as follows:
#Service
public class MonitoringExceptionResolver implements HandlerExceptionResolver {
private final Counters counters;
#Inject
public MonitoringExceptionResolver(Counters counters) {
super();
this.counters = counters;
}
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
Counter counter = counters.getCounterFor(ex.getClass());
if(counter != null) {
counter.increment();
}
return null;
}
}
However, I get NPE later in the execution chain because the "resolver" field above is null, even if I use #Autowired.
Other classes are being successfully wired in elsewhere using component scanning. Why is it always null in the above? Am I doing something wrong?
#Inject and #Autowired should work very similar in Spring.
Make sure that *BeanPostProcessor in use is aware of MonitoringExceptionResolver: mark it as #Component and make is subject of some #ComponentScan or make a #Bean factory method is some #Configuration class in use.

Resources