Spring MVC #ResponseBody issue - java

I just learn about spring mvc for few days and there are some codes I wrote :
#RequestMapping(value = "/login", method = {RequestMethod.POST, RequestMethod.GET}, consumes = "*/*", produces = "application/json")
#ResponseBody
public Object userLogin(#RequestParam(value = "userName") String userName,#RequestParam(value = "password") String password) {
String password2 = userService.selectUserPassword(userName);
JSONObject object = new JSONObject();
if(password2.equals(password)){
object.put("login", "true");
}else{
object.put("login", "false");
}
return object;
}
It doesn't work, but if I change the code to this
public Map<String, String> userLogin(#RequestParam(value = "userName") String userName,
#RequestParam(value = "password") String password) {
String password2 = userService.selectUserPassword(userName);
Map<String, String> map = new HashMap<String, String>(1);
//JSONObject object = new JSONObject();
if(password2.equals(password)){
map.put("login", "true");
}else{
map.put("login", "false");
}
return map;
}
then it works. So I was wondering why?

To understand a difference between your two methods, note the following
The #ResponseBody annotation indicates that the return type is written to the response body.
Spring converts the returned object to a response body by using an appropriate HttpMessageConverter
Since you've indicated the produces = "application/json" the converter that will kick in is MappingJackson2HttpMessageConverter An HttpMessageConverter implementation that can read and write JSON using Jackson’s ObjectMapper
this is a powerfull feature that Spring MVC does automatically, it resolve the representation, and converts automatically.
In your first method you've attempted doing this manually which is not needed and wrong. What the framework attempted is to convert your JsonObject to JSON representation, which either fails or gives you JSON properties containing the fileds of the JsonObject class.
In the later method you poplated the values to a Map, and let the Spring MVC convert to JSON. As Jackson libraries knows how to convert the Map to JSON, your later method works without issues

Related

Append Object property to RestEasy InputStream containerRequestContext

I'm trying to add the principal id to every incoming request as part of the body. This is the code I am using:
InputStream in = containerRequestContext.getEntityStream();
String jsonRequestString = IOUtils.toString(in, encoding);
ObjectMapper mapper = new ObjectMapper();
JsonFactory factory = mapper.getFactory();
JsonParser parser = factory.createParser(jsonRequestString);
JsonNode jsonNode = mapper.readTree(parser);
((ObjectNode) jsonNode).put(PRINCIPAL_ID, containerRequestContext.getSecurityContext().getUserPrincipal().getName());
containerRequestContext
.setEntityStream(IOUtils.toInputStream(mapper.writeValueAsString(jsonNode), encoding));
This is my resource:
#POST
#Path("/service")
#RolesAllowed(USER_ROLE)
#Produces(MediaType.APPLICATION_JSON)
public Response myService(String principalId, String input){
// do stuff
}
When request hits the resource, I can see the new json string being bind on principalId argument e.g.
principalId = {"principalId": "id", "input":"input"}
is there a way to bind each property to the respective argument?
You have two options here:
write interceptor (with AspectJ, for instance) which handle all your endpoints and populates principalId to your method's parameter or POJO.
write a servlet filter. This option is required to read the same request twice. The first read will occur in the filter with your following preprocessing and the second one in the Spring servlet.

Can I get a ResponseEntity (Spring) parametrized with a type either parametrized?

I'm using RestTemplate and SpringBoot 2.0.
I have this class which represents a custom JSON response to rest calls.
MyCustomResponse<T> {
private T content;
public T getContent() {
return content;
}
}
The code snippet below is a example of use:
String LOCALHOST = "http://localhost:8900";
final HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.ACCEPT, "application/json");
String url = String.format("%s/ticket/%s", LOCALHOST, protocol);
final HttpEntity<Ticket> request = new HttpEntity<>(headers);
This works fine:
ResponseEntity<MyCustomResponse> response =
testRestTemplate.getForEntity(url, RespostaPadrao.class);
But it's not what I need, because getContent returns a object that looks like:
Map< Map < String, Map < String, Map < String, Map < String, Integer >>>>>
and because I want to test a Ticket object instead.
In this line, can I use reflection to parametrize the response or this is impossible?
ResponseEntity<MyCustomResponse> response =
testRestTemplate.getForEntity(url, MyCustomResponse.class);
I know how to fix it with ResponseEntity<String> and parse the JSON to my Ticket. But what I really need is know if is possible delegate this task to RestTemplate or not.
Thanks!

Sending raw JSON using Postman value is null

A pleasant day.
I am having trouble with simply displaying string in raw JSON format using Postman.
This is what I have in my Java code:
#RestController
public class HeroController {
#RequestMapping(method = {RequestMethod.POST}, value = "/displayHero")
#ResponseBody
public Map<String, String> displayInfo(String name){
//System.out.println(name);
Map<String, String> imap = new LinkedHashMap<String, String>();
map.put("hero", name);
return imap;
}
}
Every time I test this in Postman, I always get null (again if I am using raw format):
{
"hero": null
}
But using form-data, on the other hand, displays just what I entered.
{
"hero": "wolverine"
}
Any information, or should do in Postman to make this raw format works instead of form-data? By the way, the raw format value is JSON(application/json), and in the Header Tab, the value of Content-Type is application/json; charset=UTF-8.
Thank you and have a nice day ahead.
Try the following code for consuming the request body as JSON, in spring boot:-
#RequestMapping(value = "/displayHero", method = POST, consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE)
#ResponseBody
public String displayInfo(HttpEntity<String> httpEntity) {
String json = httpEntity.getBody();
// json contains the plain json string
// now you can process the json object information as per your need
// and return output as per requirements.
return json;
}
This code will accept json body of POST Request and then return it as response.

Spring : Responding to a REST-ful API call

I am trying to implement REST API endpoints in y application.
#Controller
public class HerokuController {
#RequestMapping(value = "/heroku/resources/", method = RequestMethod.POST,produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<JSONObject> provision(#RequestBody JSONObject body){
System.out.println("called! \n");
JSONObject response = new JSONObject();
response.put("id", 555);
response.put("message", "Provision successful!");
return new ResponseEntity<JSONObject>(response,HttpStatus.OK);
}
So I wrote this class containing a method which mapping is (heroku/ressources).
But when I try to call it, I get a 404 error because /WEB-INF/heroku/resources.jsp not found. However, I don't even want to get a view but a HTTP response.
Can anyone tell me which configuration file should we generally modify to tell Spring that this controller doesn't want to send back a view but a HTTP response?
The method is however called if I change it to this :
#RequestMapping(value = "/heroku/resources/", method = RequestMethod.POST)
public ModelAndView provision(final HttpServletRequest request){
System.out.println("called! \n");
JSONObject response = new JSONObject();
response.put("id", 555);
response.put("message", "Provision successful!");
final Map<String, Object> result = new HashMap<String, Object>();
return new ModelAndView("jsonView",result);
}
So changing the return type to "ModelAndView".
thanks.
You are missing the #ResponseBody
#RequestMapping(value = "/heroku/resources/", method = RequestMethod.POST,produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody ResponseEntity<JSONObject> provision(#RequestBody JSONObject body){
System.out.println("called! \n");
JSONObject response = new JSONObject();
response.put("id", 555);
response.put("message", "Provision successful!");
return new ResponseEntity<JSONObject>(response,HttpStatus.OK);
}
I had the same problem once, for fix that you can use #RestController instead of #controller (this will send Json by default) and you can definy your method like this
#RequestMapping(value = "/heroku/resources/", method = RequestMethod.POST)
public JsonOut provision(#RequestBody JsonIn json)
I always made my object with the value that i will get from the client, and alway the definition of the output
Ex
public class JsonOut{
protected String id;
protected String message;
...set ....get
}
and you have to put in the spring xml file this two value
<mvc:annotation-driven />
<context:annotation-config/>
With this configuration you will have json always!
This will work with spring 4, i dont know if with spring 3 will work

In Spring, Is there a way to return different Content-Type values for the header?

I would like to set the produces = text/plain to produces = application/json when I encounter an error.
#RequestMapping(value = "/v0.1/content/body", method = RequestMethod.GET, produces = "text/plain")
#ResponseBody
public Object getBody(#RequestParam(value = "pageid") final List<String> pageid, #RequestParam(value = "test") final String test) {
if (!UUIDUtil.isValid(pageid)) {
Map map = new HashMap();
map.put("reason", "bad pageId");
map.put("pageId", pageId);
map.put("test", test);
return new ResponseEntity<Object>(map, HttpStatus.BAD_REQUEST);
}
return "hello";
}
The problem with this code is that it doesn't print the error as json when I send an invalid pageId. It gives me a HTTP 406 error Not acceptable, because it expects to produce text/plain but I didn't return a String.
The cleanest way to handle errors is to use #ExceptionHandler:
#ExceptionHandler(EntityNotFoundException.class) //Made up that exception
#ResponseBody
#ResponseStatus(value = HttpStatus.NOT_FOUND)
public ErrorObject handleException(Exception e) {
return new ErrorObject(e.getMessage());
}
Then assuming you've configured your resolvers properly and put the right JSON serialization library in the classpath, the instance of ErrorObject will be returned to the client as a JSON response.
Of course you can set up multiple #ExceptionHandler methods as needed.

Categories