6

Below is my controller method definition

@Autowired
private HttpServletRequest request;

@PostMapping(path = "/abc")
public String createAbc(@RequestBody HttpServletRequest request)
        throws IOException {

    logger.info("Request body: "+request.getInputStream());

    return "abc";

}

All i want to do is print contents to request body. But when i make a POST request i see below error:

Type definition error: [simple type, class javax.servlet.http.HttpServletRequest]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of javax.servlet.http.HttpServletRequest (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information\n at [Source: (PushbackInputStream); line: 1, column: 2]",

I'm using Spring boot 2.x version.Any idea what's wrong in my code?

1
  • You already have autowired your request. Where did you get @RequestBody HttpServletRequest request from ? Commented Sep 12, 2019 at 1:18

2 Answers 2

18

First, remove the @Autowired field. It's wrong and you're not using it anyway.

Now you have two choices:

  1. Let Spring process the request body for you, by using the @RequestBody annotation:

    @PostMapping(path = "/abc")
    public String createAbc(@RequestBody String requestBody) throws IOException {
        logger.info("Request body: " + requestBody);
        return "abc";
    }
    
  2. Process it yourself, i.e. don't use the @RequestBody annotation:

    @PostMapping(path = "/abc")
    public String createAbc(HttpServletRequest request) throws IOException {
        StringBuilder builder = new StringBuilder();
        try (BufferedReader in = request.getReader()) {
            char[] buf = new char[4096];
            for (int len; (len = in.read(buf)) > 0; )
                builder.append(buf, 0, len);
        }
        String requestBody = builder.toString();
        logger.info("Request body: " + requestBody);
        return "abc";
    }
    

Don't know why you'd use option 2, but you can if you want.

Sign up to request clarification or add additional context in comments.

7 Comments

remove the @Autowired field. It's wrong - can you please explain why it is wrong ? Seen in stackoverflow.com/questions/3320674/…
@ScaryWombat Well, true, it is wrong for a singleton bean. It is not wrong in that link you provided, since it explicitly says that it is a request-scoped bean. Since this question didn't specify that, the default type of bean is singleton, so it would be wrong. Besides, why create a request-scoped bean, when a singleton bean will suffice? Anyway, it is surely wrong to have HttpServletRequest as both an autowired field and as a parameter.
the default type of bean is singleton, so it would be wrong - Thanks
@ScaryWombat Yeah, you have to add another annotation to change the scope, e.g. @Scope(WebApplicationContext.SCOPE_REQUEST). Without a @Scope annotation, the bean is singleton.
@Andreas one of the reasons you'd like to go for option 2 is when you don't receive the post as plain text but something like a gzip, that is sent by the client. You of course would not use the string builder to unzip the data but something like GZIPInputStream and dump it to a normal String, but that's one of the reasons why you would need to have access to HttpServletRequest. So, thanks for the answer mate, very helpful!
|
1

if you want to take it out easily:

private ObjectMapper objectMapper;

byte[] bytes = request.getInputStream().readAllBytes();

User u = objectMapper.readValue(bytes, User.class);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.