简体   繁体   中英

Spring returns a modified JSONObject with @ResponseBody

I'm using Spring MVC and trying to return a JSONObject as response from my Controller. I have annotated the method with @ResponseBody so that it puts the JSONObject returned by my controller into the ResponseBody . Here's my Controller:

@GetMapping(value="/student/{roll}",produces="application/json")
@ResponseBody
private JSONObject getStudentDetails(@PathVariable(value="roll") String roll) {
    JSONObject response = new JSONObject();
    Student student = studentDAO.getStudent(roll);
    response.put("firstName",student.getFirstName());
    response.put("lastName",student.getLastName());
    response.put("roll",student.getRoll());
    response.put("email",student.getEmail());
    response.put("course",student.getCourse());
    response.put("stream",student.getStream());
    response.put("year",student.getYear());
    response.put("gender",student.getGender());
    String date = null;
    DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    try {
        date = String.valueOf(df.parse(student.getSignUpDate()).getTime());
    } catch (ParseException e) {
        e.printStackTrace();
    }
    response.put("signUpDate", date);
    System.out.println("Response Body::::: "+response.toString());
    return response;
}

A valid response should be like this:

{
  "firstName": "John",
  "lastName": "Doe",
  "gender": "M",
  "stream": "cse",
  "year": 3,
  "roll": "2013BT2011",
  "course": "btech",
  "signUpDate": "1476224877000",
  "email": "john@doe.com"
}

But I am getting this:

{
  "map": {
    "firstName": "John",
    "lastName": "Doe",
    "gender": "M",
    "stream": "cse",
    "year": 3,
    "roll": "2013BT2011",
    "course": "btech",
    "signUpDate": "1476224877000",
    "email": "john@doe.com"
  }
}

Here, the object returned by my controller is wrapped into a map object and then returned by Spring.

Could someone tell me what is wrong here. Any help would be appreciated. :)

spring mvc use jackson databind to serialize Object to JSON /deserialize JSON to Object. So it is not needed to return JSONObject with @ResponseBody. There are some way:

Define a class (view object) with need fields, then new , fill an instance and return it.

Use java.util.Map. So your code will be like following:

@GetMapping(value="/student/{roll}",produces="application/json")
@ResponseBody
private Map<String, Object> getStudentDetails(@PathVariable(value="roll") String roll) {
      Map<String, Object> response = new HashMap<>();
  Student student = studentDAO.getStudent(roll);
  response.put("firstName",student.getFirstName());
  response.put("lastName",student.getLastName());
  response.put("roll",student.getRoll());
  response.put("email",student.getEmail());
  response.put("course",student.getCourse());
  response.put("stream",student.getStream());
  response.put("year",student.getYear());
  response.put("gender",student.getGender());
  String date = null;
  DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  try {
    date = String.valueOf(df.parse(student.getSignUpDate()).getTime());
  } catch (ParseException e) {
    e.printStackTrace();
  }
  response.put("signUpDate", date);
  System.out.println("Response Body::::: "+response.toString());
  return response;
}

You can return Student(PO) with proper Jackson annotations on Student class( https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations ). If you want to limit returned fields, you can add JsonView annotation.

public class Student {
  public static class Response {}
  private String firstName;
  private String lastName;
  private String roll;
  private String email;
  private String course;
  private String stream;
  private String year;
  private String gender;

  private Date getSignUpDate;

  @JsonView(Response.class)
  public String getFirstName() {
    return firstName;
  }

  @JsonView(Response.class)
  public String getLastName() {
    return lastName;
  }

  @JsonView(Response.class)
  public String getRoll() {
    return roll;
  }

  @JsonView(Response.class)
  public String getEmail() {
    return email;
  }

  @JsonView(Response.class)
  public String getCourse() {
    return course;
  }

  @JsonView(Response.class)
  public String getStream() {
    return stream;
  }

  @JsonView(Response.class)
  public String getYear() {
    return year;
  }

  @JsonView(Response.class)
  public String getGender() {
    return gender;
  }

  @JsonView(Response.class)
  @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
  public Date getGetSignUpDate() {
    return getSignUpDate;
  }
  /// setters are not written.
}


public class StudentCtl {

  @GetMapping(value="/student/{roll}",produces="application/json")
  @ResponseBody
  @JsonView(Student.Response.class)
  private Map<String, Object> getStudentDetails(@PathVariable(value="roll") String roll) {
    return studentDAO.getStudent(roll);
  }
}

Assume you already have student class with these properties. Hence what you can do is simple return the object as below hopefully this should work.

private JSONObject getStudentDetails(@PathVariable(value="roll") String roll) {
    Student student = studentDAO.getStudent(roll);
    System.out.println("Response Body::::: "+response.toString());
    return student ;
}

Even if you want to change the name of these fields you can annotate them like

class Student {
 @JsonProperty("firstName")
 private String fname;

 @JsonProperty("signUpDate") 
 @JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss") 
  private Date date; 
 //getters
 //setters
}

You can simply return student from the Controller method spring will do the marshaling.

   @GetMapping(value="/student/{roll}",produces="application/json")
    @ResponseBody
    private Student getStudentDetails(@PathVariable(value="roll") String roll) {
       return studentDAO.getStudent(roll);            
    }

But since you are doing a date formatting I also suggest you create a separate class something like StudentView and map student to StudentView

  class StudentView{
    private String signUpDate;
    ......
    ......
    }

and return studentView from controller. so it would be something like

@GetMapping(value="/student/{roll}",produces="application/json")
@ResponseBody
private StudentView getStudentDetails(@PathVariable(value="roll") String roll) {
   Student student=studentDAO.getStudent(roll);            
   return toStudentView(student);
}

private static StudentView toStudentView(Student stu){
  ......
}

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