As suggested by fateddy, the easiest way to do this is by implementing a HandlerMethodArgumentResolver.
public class UsernameHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.getParameterType().equals(Username.class);
}
@Override
public Object resolveArgument(MethodParameter methodParameter,
ModelAndViewContainer modelAndViewContainer,
NativeWebRequest nativeWebRequest,
WebDataBinderFactory webDataBinderFactory) throws Exception {
String username = nativeWebRequest.getParameter("username");
if (username == null && nativeWebRequest.getUserPrincipal() != null) {
username = nativeWebRequest.getUserPrincipal().getName();
}
return new Username(username);
}
}
This requires a simple username class:
public class Username {
private String username;
public Username(String username) {
this.username = username;
}
public String getValue() {
return this.username;
}
}
as well as an annotation
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserRequest {}
In order to get this configured properly this requires a very minor change to the WebMvcConfigurerAdapter:
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new UsernameHandlerMethodArgumentResolver());
}
And that's it. Good to go. Now we can be simply drop the argument into a controller endpoint:
@RequestMapping(method = RequestMethod.GET)
public @ResponseBody ResponseEntity<WebUser> getUser(@UserRequest Username username) {
return ResponseEntity.ok(service.getUser(username, username.toLowerCase()));
}