3

I went into a strange problem. Why does the first code accept input without quotation marks, but the second does not?

To be honest, the second one makes sense. But why is the first one accepting the input given without quotation marks?

I really would like to know why this decision was taken.

package com.example.corntest;

import lombok.extern.log4j.Log4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import static org.springframework.util.MimeTypeUtils.APPLICATION_JSON_VALUE;

@SpringBootApplication
@RestController
public class CornTestApplication {

    public static void main(String[] args) {
        SpringApplication.run(CornTestApplication.class, args);
    }

    //works - does NOT remove quotation marks
    //curl 'http://localhost:8080/test' -X POST -H 'Content-Type: application/json'  --data-raw '"SunGoesUp"' -vv

    //works - but doesnt make sense - in comp. to code made in the bottom
    //curl 'http://localhost:8080/test' -X POST -H 'Content-Type: application/json'  --data-raw 'SunGoesUp' -vv
    @PostMapping(value = "/test", consumes = APPLICATION_JSON_VALUE)
    void mytestPost(@RequestBody String myString){
        System.out.println(myString);
    }

    enum Test {
        TESTA,
        TESTB,
        TESTC
    }

    //works
    //curl 'http://localhost:8080/testEnum' -X POST -H 'Content-Type: application/json'  --data-raw '"TESTA"' -vv

    //does not work
    //curl 'http://localhost:8080/testEnum' -X POST -H 'Content-Type: application/json'  --data-raw 'TESTA' -vv

    //Why
    @PostMapping(value = "/testEnum", consumes = APPLICATION_JSON_VALUE)
    void myTestEnum(@RequestBody Test myEnumValue){
        System.out.println(myEnumValue);
    }
}
  • The first one accepts the body content as a string, regardless of the content-type. The second fails in the second case as without quotation marks it isn't a String in the JSON sense and is thus interpreted differently and you can only convert a String to an Enum. – M. Deinum Dec 16 '21 at 09:05
  • But the first one states it accepts APPLICATION_JSON_VALUE and a raw string (without quotations) is _not_ a valid json value. It should just not be acceped. On the other hand, a quoted string _is_ a valid json value and it would make sense to remove the quotes prior to creating the java string. – sne11ius Dec 16 '21 at 09:10
  • 1
    `@RequestBody` doesn't care about JSON or whatever content type. If you place it on a `String` it will put the body of the request in there regardless of the content type. When you place it on an object/enum whater it will use an `HttpMessageConverter` to convert the payload (the body) to the requested object. The payload can be whatever as long there is an `HttpMessageConverter` for it, in your case it will be the `JacksonHttpMessageConverter` for converting the payload to the object. – M. Deinum Dec 16 '21 at 09:12
  • Thanks for the clarification, I think I can understand how the behaviour comes to be. I must admit though, that I still find it a bit strange and don't like it to much. Maybe it's good advice to just never just use java string type with @RequestBody if you want to consume json. I'll try to keep in mind to "Just wrap it in an object". – sne11ius Dec 16 '21 at 09:31

1 Answers1

2

In the case where you are using @RequestBody String myString the payload of the http request is put in there as-is. So whatever you send will be placed in there. The content-type doesn't matter as it will copy the payload of the request as is.

In the second case, an actual JSON string is required to be able to convert to an enum. A JSON based String needs to have quotation marks else it isn't a JSON String. Something other than a string cannot be converted to an enum.

To convert from the payload of the body to the requested object Spring uses an [HttpMessageConverter]. It will select the correct HttpMessageConverter based on the Content-Type header. In your case, assuming the defaults, this will result in the MappingJackson2HttpMessageConverter. Which will use the body to convert to the enum. Which will then fail as it isn't a valid JSON string (no quotation marks).

What is a String in JSON is explained here.

M. Deinum
  • 115,695
  • 22
  • 220
  • 224