#RequestBody is always empty in Spring - java

The JSONObject is always coming as empty for the method below.
#RequestMapping(value = "/package/{id}", method = RequestMethod.PUT)
#ResponseStatus(HttpStatus.OK)
#ResponseBody
public SPackage updatePackage(#PathVariable String id, #RequestBody JSONObject
sPackage) {
}
and my ajax is like this. I am ways getting the object as empty map on the server side
var jsonObject= {"customerName":$('#customerName').val()}
var jsonData = JSON.stringify(jsonObject);
$.ajax({
type: "PUT",
url: "http://localhost:8081/someproj/package/" + $('#id').val(),
dataType: "json",
data: jsonData,
async: false,
contentType: "application/json; charset=utf-8",
beforeSend : function() {
openModal();
},
success: function(data) {
closeModal();
$('#success').show();
console.log(data);
}
});

I guess spring doesn't know to convert your json to JSONObject, the best thing would be to accept a POJO object which has similar structure to your json,
#RequestMapping(value = "/package/{id}", method = RequestMethod.PUT)
#ResponseStatus(HttpStatus.OK)
#ResponseBody
public SPackage updatePackage(#PathVariable String id, #RequestBody YourJsonPOJO
sPackage) {
}

Are you sure there're no exceptions occurring in your Spring code. When converting from JSON to custom object in Spring, you need to specify a custom class that has same fields & format as the JSON coming in. Otherwise, Spring doesn't know who to convert HTTP POST data into a Java object.
In your case, you could do define a POJO like this:
public class MyRequestObj {
private String customerName;
// add more fields for any other keys from JSON
}
And put this in your Controller class:
#RequestMapping(value = "/package/{id}", method = RequestMethod.PUT)
#ResponseStatus(HttpStatus.OK)
#ResponseBody
public SPackage updatePackage(#PathVariable String id, #RequestBody MyRequestObj
myRequestObj) {
String customerName = myRequestObj.getCustomerName();
}
Of course, if you only want to pass in the customer name as a String to your Controller, then you could also pass it as query string (append ?customerName=someCustomer) and you can retrieve it in Spring as:
#RequestMapping(value = "/package/{id}", method = RequestMethod.PUT)
#ResponseStatus(HttpStatus.OK)
#ResponseBody
public SPackage updatePackage(#PathVariable String id, #RequestParam("customerName") String customerName) {
}

You can use this workaround:
#RequestBody Map<String, String> json
That way you can continue using Jackson HttpMessageConverter and work with custom objects in payload.
You can check extended explanaition why this happens at answer here
#RequestBody gives empty JsonObject when making a POST Request

Related

XML response from API with PathVariable

I have the API:
#GetMapping(path = "/users/{userId}")
public ResponseEntity<UserDTO> getUserById(#PathVariable(value = "userId") Long userId) {
//logic here
}
it returns JSON response, as it should.
And there's another app that I don't have access to, and it calls my API as, for example, GET /users/123.xml in order to receive XML response.
But in this case, my API fails with 400 error, because it cannot parse 123.xml into Long.
Option #GetMapping(value = {"/users/{userId}", "/users/{userId}.xml"}) fails with the same error.
What can I do to respond with XML syntax when calling /{userId}.xml and in the mean time, respond with JSON syntax when calling /{userId}?
EDIT:
I want it to do without specifically adding 'Accept' headers, and without writing any additional logic, that'll parse {userId}.xml and then set the appropriate response type.
That's can be done by using a ContentNegotiationConfigurer, you can configure it as follow :
#Configuration
#EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer
.defaultContentType(MediaType.APPLICATION_JSON)
.mediaType("xml", MediaType.APPLICATION_XML)
.mediaType("json", MediaType.APPLICATION_JSON);
}
}
It should work fine with your endpoint :
#GetMapping(path = "/users/{userId}", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<UserDTO> getUserById(#PathVariable(value = "userId") Long userId) {
return new ResponseEntity<>(userService.get(userId), HttpStatus.OK);
}
The easiest solution that I can think right off will be to have an optional Request parameter "responseType" with default value as json, and if someone wants XML response, they can call the url like :GET /users/123?responseType=xml
Since the default value of the parameter will be 'json' and it will have property "required= false", you wouldn't need to worry in use cases where json response is desired, and if someone wants XML response, they can add the optional RequestParam. Also, I guess you will need to specify produces with json and xml return types for the controller to let spring-boot know that it can produce different kinds of responses, something like -
#RequestMapping(value = "/users/{userid}", method = RequestMethod.GET,
produces = { MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_XML_VALUE }, consumes = MediaType.ALL_VALUE)
public ResponseEntity<User> getuserById(#PathVariable String
userid,#RequestParam(required=
false,defaultValue="json",name="responseType"),#RequestHeader ("content-type") String
contentType)
)
EDIT : You can use either the request param or the Request header, I provided both in the example for your reference
As an owner of the API you should declare what kind of a responses you are able to produce - in your case it is either JSON or XML:
#GetMapping(path = "/users/{userId}", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<UserDTO> getUserById(#PathVariable(value = "userId") Long userId) {
return new ResponseEntity<>(userService.get(userId), HttpStatus.OK);
}
Any client of the API can now choose which response format is preferred using Accept header - for example Accept: application/xml. Spring will respect that and return response in requested format.
To make it work you need to add additional dependency that will be used by Spring to produce XML responses:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
If you really need to go in /users/123.xml direction you'll have to change userId type to String and parse it yourself like this:
#GetMapping(path = "/users/{userId}")
public ResponseEntity<UserDTO> getUserById(#PathVariable(value = "userId") String userId) {
if (hasXMLExtension(userId)) {
return ResponseEntity
.ok()
.contentType(MediaType.XML)
.body(requestdUser);
} else {
return ResponseEntity
.ok()
.contentType(MediaType.JSON)
.body(requestdUser);
}
}

Pass and Get Json String to Spring Controller

I want to pass and Get Json String From Controller.
I want to call controller by passing json String and also want to get json String at Controller.
Is there any way to do this.
I have 2 values in my url parameter :: api=asdf23&&jsonstr={"name":"myname","age":"20"}
How can i get these two parameters at controller
#RequestMapping(value = "/GetJSON", method = RequestMethod.GET, produces = "application/json")
public #ResponseBody String GetJSON(
HttpServletRequest request, HttpServletResponse response,
#RequestParam(value = "api") String apiKey,
#RequestParam(value = "jsonstr") String json)
throws ParseException {
System.out.println("JSON :: "+json);
return json;
}
I would recommend not using URL parameter to pass the whole JSON object, rather use POST method and put JSON in the body. However, if you have reasons to use GET with json as url parameter, take help from this link to encode Http URL properly.
For your case, your JSON object will look like this:
api%3Dasdf23%26jsonstr%3D%7B%22name%22%3A%22myname%22%2C%22age%22%3A%2220%22%7D
Create a pojo having 2 properties name and age
public class Test{
private String name;
private Integer age;
//getter and setters
}
then modify your controller to accept json in requestbody and change the request method to post
#RequestMapping(value = "/GetJSON", method = RequestMethod.POST, produces = "application/json")
public #ResponseBody String GetJSON(
HttpServletRequest request, HttpServletResponse response,
#RequestParam(value = "api") String apiKey,
#RequestBody Testjson testJson)
throws ParseException {
api=asdf23**&&**jsonstr={"name":"myname","age":"20"}
You only need one &
you can also use gson 2.2.2 jar
RequestMapping(value = "/GetJSON", method = RequestMethod.GET)
public #ResponseBody String GetJSON(
HttpServletRequest request, HttpServletResponse response,
#RequestParam(value = "api") String apiKey)
throws ParseException {
Gson gson=new Gson();
Emp emp=new Emp();
String json =gson.tojson(emp);
System.out.println("JSON :: "+json);
return json;
}`
Pass the JSON HTTP Request
using the body as a POST request.
using url encode.
below just for example :
jsonstr={"name":"myname","age":"20"}
url :80/GetJSON?jsonstr=%7B%22name%22%3A%22myname%22%2C%22age%22%3A%2220%22%7D
for more information on URL encoding refer below
Percent-encoding, also known as URL encoding, is a mechanism for
encoding information in a Uniform Resource Identifier (URI) under
certain circumstances. Although it is known as URL encoding it is, in
fact, used more generally within the main Uniform Resource Identifier
(URI) set, which includes both Uniform Resource Locator (URL) and
Uniform Resource Name (URN). As such, it is also used in the
preparation of data of the application/x-www-form-urlencoded media
type, as is often used in the submission of HTML form data in HTTP
requests.
https://en.wikipedia.org/wiki/Percent-encoding

Map post parameters to DTO in request

In my Spring boot application, I'm sending the POST data with the following (e.g) params:
data: {
'title': 'title',
'tags': [ 'one', 'two' ],
'latitude': 20,
'longitude': 20,
'files': [ ], // this comes from a file input and shall be handled as multipart file
}
In my #Controller I have:
#RequestMapping(
value = "/new/upload", method = RequestMethod.POST,
produces = BaseController.MIME_JSON, consumes = BaseController.MIME_JSON
)
public #ResponseBody HttpResponse performSpotUpload(final SpotDTO spot) {
// ...
}
where SpotDTO is a non-POJO class with all getters and setters.
public class SpotDTO implements DataTransferObject {
#JsonProperty("title")
private String title;
#JsonProperty("tags")
private String[] tags;
#JsonProperty("latitude")
private double latitude;
#JsonProperty("longitude")
private double longitude;
#JsonProperty("files")
private MultipartFile[] multipartFiles;
// all getters and setters
}
Unfortunately all fields are null when I receive the request. Spring is unable to map the parameters to my DTO object.
I guess I'm missing some configuration but I do not know which one.
Other similar questions are resolved by just setting fields accessors on the DTO class. This does not work for me.
Also I have noticed that if I specify each parameter in the method:
#RequestParam("title") final String title,
the method is not even reached by the request. I can see the incoming request in a LoggingInterceptor preHandle method, but nothing in postHandle. A 404 response is sent back.
I think you're just missing the #RequestBody annotation on your parameter:
#RequestMapping(
value = "/new/upload", method = RequestMethod.POST,
produces = BaseController.MIME_JSON, consumes = BaseController.MIME_JSON
)
public #ResponseBody HttpResponse performSpotUpload(#RequestBody final SpotDTO spot) {
// ...
}
You should add #RequestBody annotation before SpotDTO spot. i.e
#RequestBody SpotDTO spot
public #ResponseBody HttpResponse performSpotUpload(#RequestBody SpotDTO spot) {
// ...
}

Pass multiple parameters to rest API - Spring

I am trying to figure out if it is possible to pass a JSON object to rest API, Or pass a multiple parameters to that API ? And how to read these parameters in Spring ? Lets assume that the url looks like the below examples :
Ex.1 http://localhost:8080/api/v1/mno/objectKey?id=1&name=saif
Is it valid to pass a JSON object like in the url below ?
Ex.2 http://localhost:8080/api/v1/mno/objectKey/{"id":1, "name":"Saif"}
Questions:
1) Is it possible to pass a JSON object to the url like in Ex.2?
2) How can we pass and parse the parameters in Ex.1?
I tried to write some methods to achieve my goal, but could not find the right solution?
I tried to pass JSON object as #RequestParam
http://localhost:8080/api/v1/mno/objectKey?id=1 There was an unexpected error (type=Unsupported Media Type, status=415). Content type 'null' not supported
http://localhost:8080/api/v1/mno/objectKey/id=1 There was an unexpected error (type=Not Found, status=404). No message available
http://localhost:8080/api/v1/mno/objectKey/%7B%22id%22:1%7D There was an unexpected error (type=Not Found, status=404). No message available
#RequestMapping(value="mno/{objectKey}",
method = RequestMethod.GET,
consumes="application/json")
public List<Book> getBook4(#RequestParam ObjectKey objectKey) {
...
}
I tried to pass the JSON object as #PathVariable
#RequestMapping(value="ghi/{objectKey}",method = RequestMethod.GET)
public List<Book> getBook2(#PathVariable ObjectKey objectKey) {
...
}
I created this object to hold the id parameter and other parameters like name , etc ....
class ObjectKey{
long id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
(1) Is it possible to pass a JSON object to the url like in Ex.2?
No, because http://localhost:8080/api/v1/mno/objectKey/{"id":1, "name":"Saif"} is not a valid URL.
If you want to do it the RESTful way, use http://localhost:8080/api/v1/mno/objectKey/1/Saif, and defined your method like this:
#RequestMapping(path = "/mno/objectKey/{id}/{name}", method = RequestMethod.GET)
public Book getBook(#PathVariable int id, #PathVariable String name) {
// code here
}
(2) How can we pass and parse the parameters in Ex.1?
Just add two request parameters, and give the correct path.
#RequestMapping(path = "/mno/objectKey", method = RequestMethod.GET)
public Book getBook(#RequestParam int id, #RequestParam String name) {
// code here
}
UPDATE (from comment)
What if we have a complicated parameter structure ?
"A": [ {
"B": 37181,
"timestamp": 1160100436,
"categories": [ {
"categoryID": 2653,
"timestamp": 1158555774
}, {
"categoryID": 4453,
"timestamp": 1158555774
} ]
} ]
Send that as a POST with the JSON data in the request body, not in the URL, and specify a content type of application/json.
#RequestMapping(path = "/mno/objectKey", method = RequestMethod.POST, consumes = "application/json")
public Book getBook(#RequestBody ObjectKey objectKey) {
// code here
}
you can pass multiple params in url like
http://localhost:2000/custom?brand=dell&limit=20&price=20000&sort=asc
and in order to get this query fields , you can use map like
#RequestMapping(method = RequestMethod.GET, value = "/custom")
public String controllerMethod(#RequestParam Map<String, String> customQuery) {
System.out.println("customQuery = brand " + customQuery.containsKey("brand"));
System.out.println("customQuery = limit " + customQuery.containsKey("limit"));
System.out.println("customQuery = price " + customQuery.containsKey("price"));
System.out.println("customQuery = other " + customQuery.containsKey("other"));
System.out.println("customQuery = sort " + customQuery.containsKey("sort"));
return customQuery.toString();
}
Multiple parameters can be given like below,
#RequestMapping(value = "/mno/{objectKey}", method = RequestMethod.GET, produces = "application/json")
public List<String> getBook(HttpServletRequest httpServletRequest, #PathVariable(name = "objectKey") String objectKey
, #RequestParam(value = "id", defaultValue = "false")String id,#RequestParam(value = "name", defaultValue = "false") String name) throws Exception {
//logic
}
Yes its possible to pass JSON object in URL
queryString = "{\"left\":\"" + params.get("left") + "}";
httpRestTemplate.exchange(
Endpoint + "/A/B?query={queryString}",
HttpMethod.GET, entity, z.class, queryString);

How to access custom Java object sent as response in AJAX request, in JavaScript?

I am working on a Spring MVC application in which I need to show details of a Trip object. Following is my TripModel:
#Entity
#Table(name="Trip")
public class TripModel {
private String locationName;
private String userName;
#Id
#Column(name="tripid")
#GeneratedValue
private int tripId;
#Column(name="tripid")
private int tripId;
#Column(name="locationid")
private int tripStopLocationId;
#Column(name="datetime")
private String tripStopDateTime;
#Column(name="createts")
private Date tripStopCreateTime;
#Column(name="userid")
private int createUserId;
#Transient
private List<ItemTransactionModel> itemTransactionModelList;
}
How can I get trip details using trip id, in AJAX? TripModel has a list of ItemTransactionModel objects.
Following is my ajax code:
jQuery.ajax({
url: '<c:url value="/trip/tripdetailsbyajax" />',
type: 'POST',
data: "tripId="+tripId,
cache:false,
success:function(response){
alert("response = " + response);
},
error:function(jqXhr, textStatus, errorThrown){
alert(jqXhr);
alert(textStatus);
alert(errorThrown);
}
});
Following is my controller method:
#RequestMapping(value = "/tripdetailsbyajax", method = { RequestMethod.POST })
public #ResponseBody TripModel getTripDetailsByAjax(int tripId) {
TripModel tripModel = null;
tripModel = tripService.getTripModel(tripId);
return tripModel;
}
How can we send TripModel object as AJAX response, and how can we access that in JavaScript? TripModel object has a list of ItemTransactionModel objects.
You need to make a few changes to get your response as JSON,
Add a dataType:json to your ajax request so that it knows that it should expect the JSON from server
jQuery.ajax({
url: '<c:url value="/trip/tripdetailsbyajax" />',
type: 'POST',
dataType: 'json',
Add a produces="application/json" in the RequestMapping of your handler method. This will hint the representation to which the framework will convert the response
#RequestMapping(value = "/tripdetailsbyajax", method = { RequestMethod.POST }, produces="application/json")
Finally, access the values in your success method like response.userName etc
Note, make sure that you're entity has proper getters/setters, the jackson libraries that are in charge of converting your object to JSON, work on properties

Categories

Resources