arminas
arminas

Reputation: 421

Custom Spring annotation for request parameters

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 ?

Upvotes: 31

Views: 30418

Answers (2)

Kevin Yue
Kevin Yue

Reputation: 392

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;
}

Upvotes: 1

Master Slave
Master Slave

Reputation: 28519

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) 

Upvotes: 52

Related Questions