Spring MVC Controller adds request object to response - json

I am building a JSON REST service with Spring 3.0.5 and my response contains the object from my request although I did not add it. I am using the MappingJacksonJsonView and Jackson 1.6.4 for rendering the ModelAndView object to JSON.
The User object is simple
public class SimpleUser {
private String username;
private String password;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password;
}
}
One of the requests looks like this
#RequestMapping(value = "/register", method = RequestMethod.GET)
public ModelAndView register(SimpleUser user) {
ModelAndView mav = new ModelAndView();
mav.addObject("ok", "success");
return mav;
}
Then I call the service with
curl 'http://localhost:8080/register?username=mike&password=mike'
The response I expect is
{"ok": "success"}
The response I get is
{"ok":"success","simpleUser":{"username":"mike","password":"mike"}}
Where and why is the user object added to the ModelAndView and how can I prevent that?
Possible solution
One way to work around this is to use Model instead of SimpleUser. This seems to work but it should be possible to use the business object.
This works:
#RequestMapping(value = "/register", method = RequestMethod.GET)
public ModelAndView register(Model model) {
log.debug("register(%s,%s)", model.asMap().get("usernmae"), model.asMap().get("password"));
ModelAndView mav = new ModelAndView();
mav.addObject("ok", "success");
return mav;
}

It looks like you're trying to process a form submission and retrieve the result via ajax. If this is the case, you don't want to return a ModelAndView object. Use the #ResponseBody annotation to have Jackson represent your return object as a json object.
public #ResponseBody Map registerUser(SimpleUser user){
Map responseMap = new HashMap();
if(registerUser(user)){
responseMap.put("OK", "Success");
} else {
responseMap.put("OK", "Failure");
}
return responseMap;
}

For Spring 3.1.x You can set the modelKey property in org.springframework.web.servlet.view.json.MappingJacksonJsonView in your *servlet.xml like below:
Servlet.xml:
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="modelKey" value="appResponse"/>
</bean>
Request Method:
#RequestMapping(value="/access")
public #ResponseBody Model getAccess(Model model) {
...
model.addAttribute("appResponse", responseDetails);
...
return model;
}
When you set a specific modelKey, all other attributes attached the the model will be ignored, hence the form parameters/request parameters. In additional, this provides a clearer design if your are presenting views for multiple media types (application/xml or application/json).

Related

Spring boot application POST request not works and not update the database

I have java Spring Boot application. When I’m sending data POST request through POSTman. JSONObject cannot be returned, POSTman showing {"false"}
This is my controller,
package com.lagoma.demo.controller;
#RestController
#RequestMapping(value = "/user")
public class User {
#Autowired
private UserService userService;
#GetMapping
public List<UserModel> getUsers() {
return userService.getUsers();
}
#RequestMapping(method = RequestMethod.GET, value = "/get")
public UserModel getOneUser(#RequestParam(value = "id", required = false, defaultValue = "00") int id) {
return userService.getUser(id);
}
#RequestMapping(method = RequestMethod.POST, value = "/save")
public boolean updateUser(#RequestBody UserModel userModel){
return userService.updateUser(userModel);
}
Spring Controller can't return primitive type or its wrapper .
You need to return some object.
If you dont have any object in scope, returning a Map will also do.
Change your updateUser to something like this
#RequestMapping(method = RequestMethod.POST, value = "/save")
public Map<String, Boolean> updateUser(#RequestBody UserModel userModel){
return Collections.singletonMap("result", userService.updateUser(userModel));
}
or with a Object
#RequestMapping(method = RequestMethod.POST, value = "/save")
public User updateUser(#RequestBody UserModel userModel){
// assuming userService.updateUser will return User object
User user = userService.updateUser(userModel);
return user;
}

Spring Web Socket Session throws Jackson Exception

In chat application, there are many rooms(Map type), which consist of Strings, boolean, and List<WebSocketSession>.
I think the problem is List<WebSocketSession> can't be written to JSON.
#RequestMapping(value = "/api/v1/lobby/roomList", method = RequestMethod.GET)
public ResponseEntity<Object> getRooms(
HttpServletRequest request,
HttpServletResponse response) {
logger.debug("RoomCtrl - getRooms");
Map<Integer, Room> rooms = roomService.getRooms();
Map<String, Object> returnMap = new HashMap<>();
returnMap.put("rooms", rooms);
return new ResponseEntity<>(
returnMap,
HttpStatus.OK);
}
This is my method to get rooms from roomService. What I have to do to receive that response correctly?
For giving more information to you, I post Room Class.
public class Room {
private String host, title;
private List<WebSocketSession> members = new ArrayList<>();
private boolean status;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public List<WebSocketSession> getMembers() {
return members;
}
public void setMembers(List<WebSocketSession> members) {
this.members = members;
}
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
}
A WebSocketSession is an abstraction to send messages over a WebSocket.
In the backend you can maintain WebSocketSession instances (while generally you maintain some specific values of WebSocketSession such as id) to perform some matching (who does the request and so for...) but you will never expose and send them in a JSON object to the clients.
Why send such a payload to the clients ? Why should they know the network details of the other users (IP, sessionID and so for) ? It will just create an overhead and decrease the security level of your application.
So WebSocketSession doesn't implement Serializable and so is defacto not serializable by Jackson (that requires that as most of JSON processing API in Java).
To resolve your issue :
Since the users need to know the name of the other chat room users you should
create a mapping between WebSocketSession.id and their unique pseudo/username with a Map<String, String> for example.
And now expose List<String> users in the JSON object returned.
Yes, you are right, WebSocketSession not json serializable, and anyway you better dont send this info to clientside.
You can use json ignore annotation here
#JsonIgnore
private List<WebSocketSession> members
so Jackson will ignore this field, when trying to serialize Room object

how do you define custom serializer for list of object before adding it to modelAttribute in Spring 4?

#Controller
public class ManageEmployee{
#ModelAttribute("employeeForm")
public EmployeeForm createEmployeeForm(Model model, HttpSession session){
EmployeeForm eform = new EmployeeForm ();
List<EmployeeDTO> eList = employeeService.getEmployeeList(employeeId)//employeeId comes from session
eform.setEmployeeDTO(eList );
model.addAttribute("empoyeeList",eList );
return eform;
}
#RequestMapping(value = LogInUris.MANAGE_EMPLOYEE, method = RequestMethod.GET)
public String showEmployee(Model model, ModelMap map) throws ServiceException{
return "employeeView";
}
}
public class EmployeeDTO{
private String eId;
private String eName;
private String eLastName;
private String positon;
private String role;
//getter//setter
}
when user calls MANAGE_EMPLOYEE url then I return employeeView(jsp) where I have to display list of employees so that user can edit and save it back again. I know I can user #JsonSerialize(using=EmployeeDTOSerializer.class) at my DTO with http request to Controller and annotating #ResponseBody but here I am adding it to model attribute so i want to know how to serialize list of object before i send it to JSP.
You'll have to do it yourself using one of the libraries. For example you could use ObjectMapper from Jackson :
// In configuration:
ObjectMapper mapper=new ObjectMapper();
and
//In Controller
#ModelAttribute("employeeForm")
public EmployeeForm createEmployeeForm(Model model, HttpSession session){
EmployeeForm eform = new EmployeeForm ();
List<EmployeeDTO> eList = employeeService.getEmployeeList(employeeId)//employeeId comes from session
eform.setEmployeeDTO(eList );
model.addAttribute("empoyeeList", mapper.writeValueAsString(eList) );
return eform;
}
This (probably with some modifications) will write json string to the model. However I would not recommend this. I suggest adding an AJAX call to your jsp which would retrieve the list of employees. Then you'll have to add a method to your controller which would return a list and annotate it with #ResponseBody.

Exposing data from spring, hibernate application as restful

The work has been derived from this link
http://www.javacodegeeks.com/2013/04/spring-mvc-hibernate-maven-crud-operations-example.html. I have tried made an attempt of releasing the data of the application in a json format for which I have made further modifications in controller class
#Controller
#RequestMapping(value="/team")
public class TeamController {
#Autowired
private TeamService teamService;
#RequestMapping(value="/add", method=RequestMethod.GET)
public ModelAndView addTeamPage() {
ModelAndView modelAndView = new ModelAndView("add-team-form");
modelAndView.addObject("team", new Team());
return modelAndView;
}
#RequestMapping(value="/add", method=RequestMethod.POST)
public ModelAndView addingTeam(#ModelAttribute Team team) {
ModelAndView modelAndView = new ModelAndView("home");
teamService.addTeam(team);
String message = "Team was successfully added.";
modelAndView.addObject("message", message);
return modelAndView;
}
#RequestMapping(value="/list")
public ModelAndView listOfTeams() {
ModelAndView modelAndView = new ModelAndView("list-of-teams");
List<Team> teams = teamService.getTeams();
modelAndView.addObject("teams", teams);
return modelAndView;
}
#RequestMapping(value="/edit/{id}", method=RequestMethod.GET)
public ModelAndView editTeamPage(#PathVariable Integer id) {
ModelAndView modelAndView = new ModelAndView("edit-team-form");
Team team = teamService.getTeam(id);
modelAndView.addObject("team",team);
return modelAndView;
}
#RequestMapping(value="/edit/{id}", method=RequestMethod.POST)
public ModelAndView edditingTeam(#ModelAttribute Team team, #PathVariable Integer id) {
ModelAndView modelAndView = new ModelAndView("home");
teamService.updateTeam(team);
String message = "Team was successfully edited.";
modelAndView.addObject("message", message);
return modelAndView;
}
#RequestMapping(value="/delete/{id}", method=RequestMethod.GET)
public ModelAndView deleteTeam(#PathVariable Integer id) {
ModelAndView modelAndView = new ModelAndView("home");
teamService.deleteTeam(id);
String message = "Team was successfully deleted.";
modelAndView.addObject("message", message);
return modelAndView;
}
#RequestMapping(value = "/api/team", method = RequestMethod.GET)
// public #ResponseBody String listUsersJson (ModelMap model) throws JSONException {
public #ResponseBody
String listTeamJson () throws JSONException {
JSONArray userArray = new JSONArray();
for (Team team : teamService.getTeams()) {
JSONObject userJSON = new JSONObject();
userJSON.put("id", team.getId());
userJSON.put("Name", team.getName());
userJSON.put("Rating", team.getRating());
userArray.put(userJSON);
}
return userArray.toString();
}
}
But This code is showing error 404. How can I implement my application in order to release the data in json format?
Change your JSON code to following:
#RequestMapping(value = "/api/team", method = RequestMethod.GET)
public #ResponseBody List<TEAMS_OBJECT_TYPE>listTeamJson () throws JSONException {
return teamService.getTeams();
}
}
NOTE: TEAMS_OBJECT_TYPE needs to be replaced by the type that teamService.getTeams() returns.
#ResponseBody will automatically convert it into JSON, so all you need to do is read it properly on client side.

issue KendoUI and SpringMVC with json binding

When I use a grid KendoUI, there is a problem with SpringMVC and jackson.
In fact, the grid datasource take a json with the format :
[{"name":"Apple","description":"a description","value":15}]
However, SpringMVC serialize it like :
{"name":"Apple","description":"a description","value":15}
without square bracket in String, so this grid doesn't bind values.
e.g code :
#RequestMapping(value="/product", method = RequestMethod.GET)
public #ResponseBody Product get(Model model) {
Product app = new Product("Apple", "a description", 15);
return app;
}
#RequestMapping(value="/product/json", method = RequestMethod.GET)
public #ResponseBody String getJson(Model model) {
return"[{\"name\":\"Apple\",\"description\":\"a description\",\"value\":15}]";
}
You can use dataSource.schema.parse to manually intercept and parse that string representing your JSON into valid JavaScript Array.
Below should work. Kendo Grid is expecting a JSON array, thus the block quotes.
For READ :
#RequestMapping(value = "/list", method = RequestMethod.GET)
public #ResponseBody
List<Product> list() {
Product apple = new Product("Apple", "a description", 15);
List<Product> listProduct = new ArrayList<Product>();
listProduct.add(apple);
return listProduct;
}
#RequestMapping(value="/product", method = RequestMethod.GET)
public #ResponseBody Product[] get(Model model) {
Product app = new Product("Apple", "a description", 15);
return new Product[]{app};
}
or
#RequestMapping(value="/product", method = RequestMethod.GET)
public #ResponseBody List<Product> get(Model model) {
List<Product> product = new ArrayList<Product>();
product.add(new Product("Apple", "a description", 15));
product.add(new Product("Guice","a guice",3));
return product;
}