9

I have a Spring rest endpoint doing a simple hello app. It should accept a {"name":"something"} and return "Hello, something".

My controller is:

@RestController
public class GreetingController { 

    private static final String template = "Hello, %s!";

    @RequestMapping(value="/greeting", method=RequestMethod.POST)
    public String greeting(Person person) {
        return String.format(template, person.getName());
    }

}

Person:

public class Person {

    private String name;

    public Person() {
        this.name = "World";
    }

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

When I make a request to the service like

curl -X POST -d '{"name": "something"}' http://localhost:8081/testapp/greeting

I get

Hello, World!

Looks like it isn't deserializing the json into the Person object properly. It's using the default constructor and then not setting the name. I found this: How to create a POST request in REST to accept a JSON input? so I tried adding an @RequestBody on the controller but that causes some error about "Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported". I see that is covered here: Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported for @RequestBody MultiValueMap which suggests removing the @RequestBody

I have tried removing the default constructor which it doesn't like either.

This question covers null values REST webservice using Spring MVC returning null while posting JSON but it suggests adding @RequestBody but that conflicts with above...

Community
  • 1
  • 1
MichaelB
  • 1,092
  • 2
  • 16
  • 32

2 Answers2

17

You must set the @RequestBody to tell to Spring what should be use to set your personparam.

 public Greeting greeting(@RequestBody Person person) {
    return new Greeting(counter.incrementAndGet(), String.format(template, person.getName()));
} 
Zorglube
  • 664
  • 1
  • 7
  • 15
  • As I said in my description, that results in a "Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported" – MichaelB Apr 12 '17 at 15:23
  • Your Content type should be `Content type 'application/json` – Zorglube Apr 12 '17 at 15:38
  • You might use PostMan or some other Json client to test your app, i might be easier. – Zorglube Apr 12 '17 at 15:40
  • Nothing is wrong, it's just not the expected Content Type – Zorglube Apr 12 '17 at 16:09
  • Is there a way to make it work with that content-type? – MichaelB Apr 12 '17 at 16:10
  • Yes, but you shouldn't disable the controls, you should send the good information to your app. By the way if you prefer disable the controls try @PranayKumbhalkar advise. – Zorglube Apr 12 '17 at 16:15
  • The point is, there are already clients sending stuff to the old version that use that content-type. I need to be able to handle them until they get upgraded. And using the ALL_VALUE thing doesn't work anyway. – MichaelB Apr 12 '17 at 16:35
  • `ALL_VALUE` will not work, because your old sender is sending Json data without telling the receiver it's Json ; so the receiver will not know how to process the data because the declarated data type (I.e.:Content-Type) is not corresponding to the data convey. – Zorglube Apr 13 '17 at 09:02
  • @RequestBody also worked for me. earlier i was getting null values in the object parrameters – Deep Roy Jun 13 '21 at 06:10
0

You must set 'produces' with @RequestMapping(value="/greeting", method=RequestMethod.POST)

use below code

@RequestMapping(value="/greeting", method=RequestMethod.POST, produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE })
 public String greeting(@RequestBody Person person) {
        return String.format(template, person.getName());
    }
  • "produces" refers to the response. The response is fine. Also, since it's returning a plain string, it should be MediaType.TEXT_PLAIN_VALUE – MichaelB Apr 12 '17 at 15:49
  • try 'consumes = MediaType.ALL_VALUE' – Pranay Kumbhalkar Apr 12 '17 at 15:52
  • @PranayKumbhalkar, `consumes = MediaType.ALL_VALUE` isn't a solution. If you can't pass through an check, the solution isn't disabling the check ; the solution is changing what you're sending. – Zorglube Apr 12 '17 at 16:13