Home > Net >  Parse RequestBody as two different objects in Spring boot
Parse RequestBody as two different objects in Spring boot

Time:09-28

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) {
    }
}
  • Related