Reputation: 421
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
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.
UpperCase
annotation marks the parameter that needs to be converted to uppercase.@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UpperCase {
}
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)
@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
Reputation: 28519
As the guys said in the comments, you can easily write your annotation driven custom resolver. Four easy steps,
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UpperCase {
String value();
}
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();
}
}
<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());
}
...
}
public String test(@UpperCase("foo") String foo)
Upvotes: 52