简体   繁体   中英

Spring MVC @RequestBody receive an Object wrapper with non-primitive attributes

I create the JSON as follows:

    var manager = {
        username: "admin",
        password: "admin"
    };
    var userToSubscribe = {
        username: "newuser",
        password: "newpassword",
        email: "user@1and1.es"
    };

    var openid = "myopenid";

    var subscription = {
            manager: manager,
            userToSubscribe : userToSubscribe,
            openid : openid
    };

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

This is the JSON that is sent:

{"subscription":{"manager":{"username":"admin","password":"admin"},"userToSubscribe":{"username":"newuser","password":"newpassword","email":"user@1and1.es"},"openid":"myopenid"}}  

And I would like to map this JSON to a Wrapper Class. This is the wrapper:

private class Subscription{
    private User manager;
    private User userToSubscribe;
    private String openid;
    public User getManager() {
        return manager;
    }
    public void setManager(User manager) {
        this.manager = manager;
    }
    public User getUserToSubscribe() {
        return userToSubscribe;
    }
    public void setUserToSubscribe(User userToSubscribe) {
        this.userToSubscribe = userToSubscribe;
    }
    public String getOpenid() {
        return openid;
    }
    public void setOpenid(String openid) {
        this.openid = openid;
    }
}

The jackson dependency in the pom.xml (I'm using spring 3.1.0.RELEASE):

    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>1.9.10</version>
    </dependency>

The mapping in rest-servlet.xml

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
   <property name="messageConverters">
       <list>
           <ref bean="jsonConverter" />
       </list>
   </property>
</bean>

<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
   <property name="supportedMediaTypes" value="application/json" />
</bean>

And the header of the controller method:

public @ResponseBody SimpleMessage subscribeUser(@RequestBody Subscription subscription)

As a result of the POST I receive a 400 Incorrect request error. Is it possible to do this or do i need to do it with @RequestBody String or @RequestBody Map<String,Object> and decode the JSON myself?

Thanks!

Looking at your JSON

{
    "subscription": {
        "manager": {
            "username": "admin",
            "password": "admin"
        },
        "userToSubscribe": {
            "username": "newuser",
            "password": "newpassword",
            "email": "user@1and1.es"
        },
        "openid": "myopenid"
    }
}

The root element is subscription and it is a JSON object. Your Subscription class doesn't have a subscription field. So there is nothing to map the subscription element to and it therefore fails with a 400 Bad Request.

Create a class SubscriptionWrapper

public class SubscriptionWrapper {
    private Subscription subscription;

    public Subscription getSubscription() {
        return subscription;
    }

    public void setSubscription(Subscription subscription) {
        this.subscription = subscription;
    }
}

and change your handler method to accept an argument of this type

public @ResponseBody SimpleMessage subscribeUser(@RequestBody SubscriptionWrapper subscriptionWrapper)

You might need to configure the ObjectMapper in MappingJacksonHttpMessageConverter (FYI you should be using MappingJackso2nHttpMessageConverter ), so that it ignores missing properties.

I'm going to answer my own question. First of all special thanks to Sotirios Delimanolis because he gave me the key in order to investigate what it was happening.

As you know, I create the following json from the view:

{"manager":{"username":"admin","password":"admin"},"userToSubscribe":{"username":"newuser","password":"newpassword","email":"user@1and1.es"},"openid":"https://myopenid..."}

I changed it a little bit because I realised that is not necessary to create a object Subscription and a var Subscription. If you build the JSON like this, it will work perfectly:

var manager = {
    username: "admin",
    password: "admin"
};
var userToSubscribe = {
    username: "newuser",
    password: "newpassword",
    email: "user@1and1.es"
};

var openid = "https://myopenid...";

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

The controller receives this json:

@RequestMapping(method=RequestMethod.POST, value="/isUserSuscribed.json")
public @ResponseBody ResponseMessageElement<Boolean> isUserSuscribed(@RequestBody SubscriptionWrapper subscription){

And the SubscriptionWrapper...

private static class SubscriptionWrapper {
    BasicUser manager;
    BasicUser userToSubscribe;
    String openid;

    public BasicUser getManager() {
        return manager;
    }
    public void setManager(BasicUser manager) {
        this.manager = manager;
    }
    public BasicUser getUserToSubscribe() {
        return userToSubscribe;
    }
    public void setUserToSubscribe(BasicUser userToSubscribe) {
        this.userToSubscribe = userToSubscribe;
    }
    public String getOpenid() {
        return openid;
    }
    public void setOpenid(String openid) {
        this.openid = openid;
    }
}

So... What is the problem? I was receiving an Incorrect Request 400 error... I debugged the MappingJackson2HttpMessageConverter as Sotirios suggested and there was an exception (No suitable constructor). Jackson Mapping is not able to build an inner class whether this class is not static. Setting SubscriptionWrapper to static was the solution to my problem.

You can also check these answers: http://stackoverflow.com/questions/8526333/jackson-error-no-suitable-constructor

http://stackoverflow.com/questions/12139380/how-to-convert-json-into-pojo-in-java-using-jackson

And if you have problems to deserialize, check this: http://stackoverflow.com/questions/17400850/is-jackson-really-unable-to-deserialize-json-into-a-generic-type

Thanks for all the replies.

You don't need to do this by yourself. You need to add this dependency in your pom:

<dependencies>
    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>1.8.5</version>
    </dependency>
  </dependencies>

After that Spring will do conversion for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM