31

I would like to write custom annotations, that would modify Spring request or path parameters according to annotations. For example instead of this code:

@RequestMapping(method = RequestMethod.GET)
public String test(@RequestParam("title") String text) {
   text = text.toUpperCase();
   System.out.println(text);
   return "form";
}

I could make annotation @UpperCase :

@RequestMapping(method = RequestMethod.GET)
   public String test(@RequestParam("title") @UpperCase String text) {
   System.out.println(text);
   return "form";
}

Is it possible and if it is, how could I do it ?

2
  • 4
    Look at the HandlerMethodArgumentResolver interface. Commented Jun 8, 2015 at 17:47
  • 1
    You can also do this with spring AOP; you'd use a method annotated like @Before("@annotation(my.pkg.annotation.UpperCase)"), then transform the parameter in the method. Commented Jun 8, 2015 at 17:51

2 Answers 2

52

As the guys said in the comments, you can easily write your annotation driven custom resolver. Four easy steps,

  1. Create an annotation e.g.

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UpperCase {
    String value();
}
  1. Write a resolver e.g.

public class UpperCaseResolver implements HandlerMethodArgumentResolver {

    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterAnnotation(UpperCase.class) != null;
    }

    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
            WebDataBinderFactory binderFactory) throws Exception {
        UpperCase attr = parameter.getParameterAnnotation(UpperCase.class);
        return webRequest.getParameter(attr.value()).toUpperCase();
    }
}
  1. register a resolver

<mvc:annotation-driven>
        <mvc:argument-resolvers>
            <bean class="your.package.UpperCaseResolver"></bean>
        </mvc:argument-resolvers>
</mvc:annotation-driven>

or the java config

    @Configuration
    @EnableWebMvc
    public class Config extends WebMvcConfigurerAdapter {
    ...
      @Override
      public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
          argumentResolvers.add(new UpperCaseResolver());
      }
    ...
    }
  1. use an annotation in your controller method e.g.

public String test(@UpperCase("foo") String foo) 
Sign up to request clarification or add additional context in comments.

6 Comments

Shouldn't it be : <bean class="your.package.UpperCaseResolver"></bean> ?
this answer needs a relative high version of springframework. I tried 4.1.4,does not work, 4.2.4 can work.
I created a custom annotation of my own. Used it in a sample application. It works fine. But when I tried to Integrate the same code with my project, it doesn't work. Not sure why is it not getting picked up
Since Spring 5 you should just implement the interface WebMvcConfigurer instead of extending (the now deprecated) WebMvcConfigurerAdapter
@master-slave i have used both the mvc:annotation/config but the custom resolver is not getting called in spring mvc project. It works in spring boot application. I dont know spring boot, is it related to spring boot?
|
2

Below is the implementation using Spring AOP. The benefit is that you don't need to specify the request parameter in the annotation and it can be used for any method.

  1. The UpperCase annotation marks the parameter that needs to be converted to uppercase.
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UpperCase {
}
  1. The UpperCaseAspect class intercepts the method call and converts the parameter to uppercase.
@Aspect
@Component
public class UpperCaseAspect {

    // Match any method that has at least one argument annotated with `@UpperCase`.
    @Around("execution(* *(.., @UpperCase (*), ..))")
    public Object convertToUpperCase(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Parameter[] parameters = method.getParameters();

        // Find the argument annotated with `@UpperCase`, and replace it with the uppercase value.
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            if (parameter.isAnnotationPresent(UpperCase.class) && args[i] != null) {
                args[i] = ((String) args[i]).toUpperCase();
            }
        }

        return joinPoint.proceed(args);
    }
}

The @Around expression matches any 1..N annotated parameters regardless of their position in the method signature. (credit to https://stackoverflow.com/a/52889642/2457861)

  1. Use an annotation in your controller method e.g.
@RequestMapping(method = RequestMethod.GET)
public String test(@RequestParam("title") @UpperCase String text) {
   System.out.println(text);
   return "form";
}

public String upperCase(@UpperCase String text) {
    return text;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.