Search code examples
javajsonajaxstruts2struts2-json-plugin

Struts2 JSON to Java Action Object (can't find the error)


I have tried multiple versions and read several related answers, but I still cant figure out why Struts is not populating my Action property user.

This is my ajax call

function save_new_user() {

    var user = 
    {       username: $('#new_user_username').val(),
            email: $('#new_user_email').val(),
            password: $('#new_user_password').val()         
    };

    user_json = JSON.stringify(user);
    console.log(user_json);

    var data = {'user': user_json};

    $.ajax({
        type : 'GET',
        url : 'SaveNewUser',
        data: data,
        dataType : "json",
        contentType: 'application/json',
        success : function(data, textStatus, jqXHR) {
            if(data) {

            }
        },
    });
}

which, by the way, print this in the console

{"username":"dd","email":"ff","password":"gg"}

My Action class (with annotations), (I am not modifying the json-default interceptor from struts2-json-plugin-2.3.24.1) is

package coproject.cpweb.actions;

import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;

import com.opensymphony.xwork2.ActionSupport;

import coproject.cpweb.utils.db.entities.UserDum;
import coproject.cpweb.utils.db.services.DbServicesImp;

@Action("SaveNewUser")
@ParentPackage("json-default")
@Results({
    @Result(name="success", type="json"),
    @Result(name="input", location="/views/error.jsp")
})
public class SaveNewUser extends ActionSupport{

    private static final long serialVersionUID = 1L;

    /* Services  */
    DbServicesImp dbServices;

    public DbServicesImp getDbServices() {
        return dbServices;
    }

    public void setDbServices(DbServicesImp dbServices) {
        this.dbServices = dbServices;
    }

    /* Input Json  */
    private UserDum user = new UserDum();

    public UserDum getUser() {
        return user;
    }

    public void setUser(UserDum user) {
        this.user = user;
    }

    /* Execute */
    public String execute() throws Exception  {

        // dbServices.saveUser(user);

        System.out.println(user.getUsername());

        return "SUCCESS";
    }


}

And the UserDum entity is

package coproject.cpweb.utils.db.entities;

public class UserDum {

    private String username;
    private String email;
    private String password;

    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

However, when the request arrives, the json interceptor of struts-json-plugin gets an exception trying to set "user".

feb 04, 2016 12:20:14 PM com.opensymphony.xwork2.interceptor.ParametersInterceptor error
SEVERE: Developer Notification (set struts.devMode to false to disable this message):
Unexpected Exception caught setting 'user' on 'class coproject.cpweb.actions.SaveNewUser: Error setting expression 'user' with val
ue ['{"username":"dd","email":"ff","password":"gg"}', ]
feb 04, 2016 12:20:14 PM com.opensymphony.xwork2.util.LocalizedTextUtil warn
WARNING: Missing key [invalid.fieldvalue.user] in bundles [[org/apache/struts2/struts-messages, com/opensymphony/xwork2/xwork-mess
ages]]!

Any clues on what might be the error?


Solution

  • Extending json-default package doesn't set json interceptor to the defaultStack of interceptors, it just defines that there is such interceptor.

    Use interceptorRefs in your @Action annotation to set json interceptor and the defaultStack to the action.

    @Action(value="SaveNewUser", 
            interceptorRefs={ @InterceptorRef("json"), 
                              @InterceptorRef("defaultStack") })
    

    Or @InterceptorRefs at the class level to apply interceptors to all actions defined in that class.

    @InterceptorRefs({
        @InterceptorRef("json"),
        @InterceptorRef("defaultStack")
    })