In my Spring Boot application (2.5.5
) I get a large JSON body in the POST
request to a specific endpoint. On that request I need to get both the parsed object and that whole object as a string to do some validation. The JSON object contains a lot of information that I don't need so that is not included in the Object so I can't convert it to a string.
@RestController
@RequestMapping("/example")
public class ExampleController {
@PostMapping("")
public void example(
@RequestBody String stringBody,
@RequestBody ExampleRequest exampleRequest
) {
// Validate request with 'stringBody'
// Do things with 'exampleRequest'
}
}
The best idea I had so far is to just use @RequestBody String stringBody
and then convert that string to a JSON object but that is really not the ideal solution.
I know that you can't have two @RequestBody
but I really need to somehow have both.
CodePudding user response:
I believe that a custom HandlerMethodArgumentResolver
is your best option.
For that I suggest you create a custom annotation as follows:
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidJsonSignature { }
Now you need to implement the custom HandlerMethodArgumentResolver
:
public class JsonSignatureValidationArgumentResolver implements HandlerMethodArgumentResolver {
private final ObjectMapper objectMapper;
public JsonSignatureValidationArgumentResolver(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.getParameterAnnotation(ValidJsonSignature.class) != null;
}
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
HttpServletRequest httpServletRequest = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
String jsonPayload = StreamUtils.copyToString(httpServletRequest.getInputStream(), StandardCharsets.UTF_8);
// Do actual validation here
if (// Valid) {
// If valid, then convert String to method parameter type and return it
return objectMapper.treeToValue(objectMapper.readTree(jsonPayload), methodParameter.getParameterType());
} else {
// Throw exception if validation failed
}
}
}
Next, you need to register JsonSignatureValidationArgumentResolver
as an argument resolver:
@Configuration
public class JsonSignatureValidationConfiguraion implements WebMvcConfigurer {
@Autowired
private ObjectMapper objectMapper;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new JsonSignatureValidationArgumentResolver(objectMapper));
}
}
Last but not the least, you need to annotate the Controller attribute with @ValidJsonSignature
as follows:
@RestController
@RequestMapping("/example")
public class ExampleController {
@PostMapping("")
public void example(@ValidJsonSignature ExampleRequest exampleRequest) {
}
}