Search code examples
javaspringspring-restcontrollerspring-boot-actuator

Possible to have Spring @RequestBody and HttpEntity at the same time?


I have the following code in my Spring Boot app:

@RestController
@RequestMapping("/execute")
public class RestCommandExecutor {

  @PostMapping
  public Response executeCommand(@RequestBody Command command, 
                                 HttpEntity<String> httpEntity) {
    System.out.println(command);
    System.out.println("********* payload is: " + httpEntity.getBody());

    return new Response("Hello text", new Long(123));
  }
}

When a POST request comes in with the proper Command, I get an I/O error:

.w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: I/O error while reading input message; nested exception is java.io.IOException: Stream closed

I'd like Spring to translate the request body into Command, but since the JSON holds more than what is part of the Command class, I'd like to get the full JSON in raw as well.

Is there a way to achieve this through mapping in the method? I know I can always do this public Response executeCommand(HttpEntity<String> httpEntity) and then manually translate it into Command using Jackson, but I would rather not have to do that manually.

Is that possible?


Solution

  • The reason you can’t both read the HttpEntity’s body and use @RequestBody is that both read from the HttpRequest’s InputStream and close it afterwards. Since you can’t read again from the InputStream after it’s closed, the last operation fails as you see.

    It seems what you actually want is to access some properties that aren’t mapped in the Command class, particularly into a class specified using a type property. You can do this using Jackson’s @JsonTypeInfo and @JsonSubtype annotations, which allow you customize the deserialization for a class hierarchy.