I currently have this RequestMapping
where I use validation through a regular expression:
@RequestMapping(value = "/example/{id}", method = GET)
public Response getExample(
@PathVariable("id") String id,
@RequestParam(value = "myParam", required = true) @Valid @Pattern(regexp = MY_REGEX) String myParamRequest,
@RequestParam(value = "callback", required = false) String callback,
@RequestHeader(value = "X-API-Key", required = true) @Valid @Pattern(regexp = SEGMENTS_REGEX) String apiKeyHeader) {
// Stuff here...
}
However, the regulare expression is not enough. Instead, I would like to do some custom validation on the header attribute i.e.
if (!API_KEY_LIST.contains(apiKeyHeader)) {
throw Exception();
}
Is this possible?
Best way to do this IMO is to create a custom HandlerMethodArgumentResolver
that would look something like this using a custom annotation @Segment
:
public class SegmentHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(String.class)
&& parameter.getParameterAnnotation(Segment.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
String apiKey = webRequest.getHeader("X-API-Key");
if (apiKey != null) {
if (!API_KEY_LIST.contains(apiKey)) {
throw new InvalidApiKeyException();
}
return apiKey;
} else {
return WebArgumentResolver.UNRESOLVED;
}
}
}
Then your controller signature looks like this:
@RequestMapping(value = "/example/{id}", method = GET)
public Response getExample(
@PathVariable("id") String id,
@RequestParam(value = "myParam", required = true) @Valid @Pattern(regexp = MY_REGEX) String myParamRequest,
@RequestParam(value = "callback", required = false) String callback,
@Segment String apiKeyHeader) {
// Stuff here...
}
You'll register the handler method argument resolver in you WebMvcConfigurationAdapter:
@Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(segmentHandler());
}
@Bean
public SegmentHandlerMethodArgumentResolver segmentHandler() {
return new SegmentHandlerMethodArgumentResolver();
}
}
There is aleardy a feature request Spring backlog, checkout JIRA. However, i was able to achieve what you are trying using @Validated
annotation on Controller.
@RestController
@RequestMapping("/user")
@Validated
public class UserController {
@GetMapping("/{loginId}")
public User getUserBy(@PathVariable @LoginID final String loginId) {
// return some user
}
}
Here @LoginID
is custom validator. And @Validated
is from org.springframework.validation.annotation.Validated
which does the trick.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With