8

I'm developing REST services which have to receive multiple info. In this case, two objects and an attribute.

This is the javascript where I'm testing the POST request

    var user = {
        username: "admin",
        password: "admin"
    };
    var userToSubscribe = {
        username: "newuser",
        password: "newpassword",
        email: "[email protected]"
    };

    var openid = "myopenid";

    $.ajax({
        url: '/myportal/rest/subscribeUser.json',
        type: 'POST',
        dataType: 'json',
        contentType: 'application/json',
        mimeType: 'application/json',
        data: JSON.stringify({ user: user, userToSubscribe: userToSubscribe, openid: openid})    
    });

The POST request:

    JSON


    openid
        "myopenid"

    user
        Object { username="admin", password="admin"}

    userToSubscribe
        Object { username="newuser", password="newpassword", email="[email protected]"}
    Source
    {"user":{"username":"admin","password":"admin"},"userToSubscribe":{"username":"newuser","password":"newpassword","email":"[email protected]"},"openid":"myopenid"}

And the controller which handles the POST:

    @RequestMapping(method=RequestMethod.POST, value="/subscribeUser.json")
public @ResponseBody Message subscribeUser(@RequestBody("user") User user, @RequestBody("userToSubscribe") User userToSubscribe, @RequestParam String openid){
    ...
}

And the error is

POST subscribeUser.json 400 Incorrect request localhost:8080 990 B [::1]:8080

What am i doing wrong?

Thank you

4
  • Is there any exception available in servlet container logs? Commented Oct 29, 2013 at 9:48
  • Thanks for answering me @Jk1. There is no exception in the logs. It seems that the POST is malformed and does not reach the controller :/ but i don't know what i'm doing wrong. Commented Oct 29, 2013 at 9:50
  • Even if request is rejected before reaching the controller exception is usualy logged. In case of Tomcat (for example) it will go in catalina.out by default. I suggest to look for the server side exception. It may also be some intermediate network agent, like proxy, which is rejecting the request long before the target server. Commented Oct 29, 2013 at 9:56
  • If I simplify the method only including the user and the post instead of doing Json.Stringfy including in the data directly: '{"user":{"username":"john","password":"johnjohn"}}' the controller is reached but the object User is not filled. Commented Oct 29, 2013 at 10:06

3 Answers 3

13

The request body will contain the entire JSON content. So when you want to map the JSON, you use only one RequestBody annotated-parameter. You will have to do something like this:

public @ResponseBody Message subscribeUser(@RequestBody String str)
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(str);

And then use the convertValue method of the mapper to get your different objects from the string.

JsonNode node = mapper.readTree(str);
User theUser = mapper.convertValue(node.get("user"), User.class);

Similarly for the other objects

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

2 Comments

I don't understand why Jackson can't do this when it's mapping the JSON to the controller parameter. It does it in other cases when you have a single model - what's preventing it from doing it here? How come it can handle other @RequestParam's, but not one that's a model if there's any other @RequestParam's?
No need to create an ObjectMapper each time as it is threadsafe. Better to store an ObjectReader in a static variable as a final field.
2

You cannot use @ModelAttributes in a RESTful method that accepts JSON. I believe the proper method is to use @RequestBody, as done here. You will most likely need to wrap the objects in some wrapper class, but I could be wrong there as I have never personally tried to pass multiple JSON objects in one request before.

That said, I think it would be a good idea if you rethought your REST api, removing the JSON arguments and instead passing them in as part of the URI path, if possible. I would suggest reading through this blog post.

3 Comments

Yes, I realised that ModelAttribute was not correct. I replaced ModelAttribute by RequestBody but it doesn't work as expected. I realised that i can't send multiple objects of different classes with JSON as i want with getElements(RequestBody ObjectType1, RequestBody ObjectType2..). It's possible send a list of the same object or sending different objects but you have to receive them as Map<String,Object>
You can receive it as a String, then parse the JSON on your own. However, I still think you should consider simplifying the API and using the URI path as part of the input.
Would you mind to explain more details about what you are talking about? Thank you
0

You can create a java bean(POJO) containing all the objects like..

class JavaBean{
    private User user;
    private UserTOSubscribe  userToSubscribe;
    private Long openId;

    // getter and setter
}

and pass this bean in to the Web service. so web service looks like..

@RequestMapping(method=RequestMethod.POST, value="/subscribeUser.json")
public @ResponseBody Message subscribeUser(@RequestBody JavaBean javaBean) {
    ...
}

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.