receiving json and deserializing as List of object at spring mvc controller - spring

My code is as below:
controller
#RequestMapping(value="/setTest", method=RequestMethod.POST, consumes="application/json")
public #ResponseBody ModelMap setTest(#RequestBody List<TestS> refunds, ModelMap map) {
for(TestS r : refunds) {
System.out.println(r.getName());
}
// other codes
}
TestS pojo
public class TestS implements Serializable {
private String name;
private String age;
//getter setter
}
Json request
var z = '[{"name":"1","age":"2"},{"name":"1","age":"3"}]';
$.ajax({
url: "/setTest",
data: z,
type: "POST",
dataType:"json",
contentType:'application/json'
});
It's giving this error
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.air.cidb.entities.TestS
I am using spring 3.1.2 and jackson 2.0.4
Edit: I want to receive list of TestS objects at my controller method, and process them. I am not able to find if I am sending wrong json or my method signature is wrong.

Here is the code that works for me. The key is that you need a wrapper class.
public class Person {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
#Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
A PersonWrapper class
public class PersonWrapper {
private List<Person> persons;
/**
* #return the persons
*/
public List<Person> getPersons() {
return persons;
}
/**
* #param persons the persons to set
*/
public void setPersons(List<Person> persons) {
this.persons = persons;
}
}
My Controller methods
#RequestMapping(value="person", method=RequestMethod.POST,consumes="application/json",produces="application/json")
#ResponseBody
public List<String> savePerson(#RequestBody PersonWrapper wrapper) {
List<String> response = new ArrayList<String>();
for (Person person: wrapper.getPersons()){
personService.save(person);
response.add("Saved person: " + person.toString());
}
return response;
}
The request sent is json in POST
{"persons":[{"name":"shail1","age":"2"},{"name":"shail2","age":"3"}]}
And the response is
["Saved person: Person [name=shail1, age=2]","Saved person: Person [name=shail2, age=3]"]

This is not possible the way you are trying it. The Jackson unmarshalling works on the compiled java code after type erasure. So your
public #ResponseBody ModelMap setTest(#RequestBody List<TestS> refunds, ModelMap map)
is really only
public #ResponseBody ModelMap setTest(#RequestBody List refunds, ModelMap map)
(no generics in the list arg).
The default type Jackson creates when unmarshalling a List is a LinkedHashMap.
As mentioned by #Saint you can circumvent this by creating your own type for the list like so:
class TestSList extends ArrayList<TestS> { }
and then modifying your controller signature to
public #ResponseBody ModelMap setTest(#RequestBody TestSList refunds, ModelMap map) {

#RequestMapping(
value="person",
method=RequestMethod.POST,
consumes="application/json",
produces="application/json")
#ResponseBody
public List<String> savePerson(#RequestBody Person[] personArray) {
List<String> response = new ArrayList<String>();
for (Person person: personArray) {
personService.save(person);
response.add("Saved person: " + person.toString());
}
return response;
}
We can use Array as shown above.

Solution works very well,
public List<String> savePerson(#RequestBody Person[] personArray)
For this signature you can pass Person array from postman like
[
{
"empId": "10001",
"tier": "Single",
"someting": 6,
"anything": 0,
"frequency": "Quaterly"
}, {
"empId": "10001",
"tier": "Single",
"someting": 6,
"anything": 0,
"frequency": "Quaterly"
}
]
Don't forget to add consumes tag:
#RequestMapping(value = "/getEmployeeList", method = RequestMethod.POST, consumes="application/json", produces = "application/json")
public List<Employee> getEmployeeDataList(#RequestBody Employee[] employeearray) { ... }

I believe this will solve the issue
var z = '[{"name":"1","age":"2"},{"name":"1","age":"3"}]';
z = JSON.stringify(JSON.parse(z));
$.ajax({
url: "/setTest",
data: z,
type: "POST",
dataType:"json",
contentType:'application/json'
});

For me below code worked, first sending json string with proper headers
$.ajax({
type: "POST",
url : 'save',
data : JSON.stringify(valObject),
contentType:"application/json; charset=utf-8",
dataType:"json",
success : function(resp){
console.log(resp);
},
error : function(resp){
console.log(resp);
}
});
And then on Spring side -
#RequestMapping(value = "/save",
method = RequestMethod.POST,
consumes="application/json")
public #ResponseBody String save(#RequestBody ArrayList<KeyValue> keyValList) {
//Saving call goes here
return "";
}
Here KeyValue is simple pojo that corresponds to your JSON structure also you can add produces as you wish, I am simply returning string.
My json object is like this -
[{"storedKey":"vc","storedValue":"1","clientId":"1","locationId":"1"},
{"storedKey":"vr","storedValue":"","clientId":"1","locationId":"1"}]

Related

can I send Criteria in a spring feign client GetMapping request?

I'm trying to get userConfig from Organisation microservice, the app is getting quite large to I had too fetch UserConfig with userConfigCriteria for further use,
I wrote my feign service like this:
#AuthorizedFeignClient(name = "organization")
#Service
public interface UserConfigFeignService {
#RequestMapping(
value = "/api/feign-user-configs",
consumes = "application/json",
produces = "application/json",
method = RequestMethod.GET
)
ResponseEntity<List<UserConfigFein>> getUserConfig(UserConfigFeignCriteria criteria);
}
implemented like this:
public List<UserConfigFein> UserConfigByDepartment(UserConfigFeignCriteria criteria) {
try {
return userConfigFeignService.getUserConfig(criteria).getBody();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("feign error: couldn't get all userConfigs with criteria " + criteria);
}
}
in the Organisation microservice I created this end pt
#GetMapping("/feign-user-configs")
public ResponseEntity<List<UserConfigDTO>> getUserConfig(UserConfigCriteria criteria) {
log.debug("REST request to get a page of UserConfigs by criteria: {}", criteria);
//bla bla code that is not reached
}
an error is thrown at this point
throw new RuntimeException("feign error: couldn't get all userConfigs with criteria " + criteria);
[405 Method Not Allowed] during [GET] to [http://organization/api/feign-user-configs] [UserConfigFeignService#getUserConfigByDepartmentId(UserConfigFeignCriteria)]: [{
"title" : "Method Not Allowed",
"status" : 405,
"detail" : "Request method 'POST' not supported",
"path" : "/api/feign-user-configs",
"message" : "error.http.405"
}]
the end point in Organization is not being reached.
any ideas ?
I'm expecting
UserConfigFeignCriteria
to be sent to Organisation microservice
edit: here's UserConfigFeignCriteria
#ParameterObject
public class UserConfigFeignCriteria implements Serializable, Criteria {
private LongFilter id;
private StringFilter userId;
private StringFilter nickname;
private Boolean focusMode;
private LongFilter departmentId;
private Boolean distinct;
public UserConfigFeignCriteria(UserConfigFeignCriteria other) {
this.id = other.id == null ? null : other.id.copy();
this.userId = other.userId == null ? null : other.userId.copy();
this.nickname = other.nickname == null ? null : other.nickname.copy();
this.focusMode = other.focusMode;
this.distinct = other.distinct;
}
public UserConfigFeignCriteria() {}
#Override
public UserConfigFeignCriteria copy() {
return new UserConfigFeignCriteria(this);
}
//getters and setters
#Override
public boolean equals(Object o)
#Override
public int hashCode()
#Override
public String toString()
}
I solved the issue by changing the request method in interface UserConfigFeignService to POST like so
#AuthorizedFeignClient(name = "organization")
#Service
public interface UserConfigFeignService {
#RequestMapping(
value = "/api/feign-user-configs",
consumes = "application/json",
produces = "application/json",
method = RequestMethod.POST
)
ResponseEntity<List<UserConfigFein>> getUserConfig(UserConfigFeignCriteria criteria);
}
I have to make more research for why criteria can not be sent with a get method when using feign client, cause fetching data with POST methos is not a good solution.

415--Unsupported Media Type in Spring

I am getting unsupported mediatype error.
My User Profile class looks like this
Class UserProfile{
private int age;
private String name,
private String currenecy;
}
And this is the method in controller
#RequestMapping(value = "/Create", method=RequestMethod.POST,consumes=MediaType.APPLICATION_JSON_VALUE, produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<UserProfileResponse> createUserProfile(#RequestBody UserProfile userProfile)
{
UserProfileResponse userProfileResponse = new UserProfileResponse();
int id = createUserProfileData(userProfile)
userProfileResponse.setId(id);
return new ResponseEntity<UserProfileResponse>(userProfileResponse,HTTPStatus.OK);
}
I am trying to send the request through POSTMAN but getting
Error 415--Unsupported Media Type
My Request in POstman looks like this
Content-Type:application/json
Accept:application/json
Method is : POST
{
"age":28,
"name":"Sam",
"currency": "INR"
}
Suggest me what I am missing?
Don't forget to select "JSON" format, filled in arbitrary JSON string in the textarea.
Also use either Accept or Content-type at a time.
If that doesn't work then can you check like below by removing consumes and adding headers manually.
#RequestMapping(value = "/Create", method=RequestMethod.POST, headers = "Accept=application/json",produces=MediaType.APPLICATION_JSON_VALUE)
I could see the response coming back with your code. I am deliberately returning the same object just to test the connectivity. Following is my code:
#RequestMapping(value = "/create", method= RequestMethod.POST,consumes= MediaType.APPLICATION_JSON_VALUE, produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<UserProfile> createUserProfile(#RequestBody UserProfile userProfile)
{
System.out.println("Got request");
return new ResponseEntity<>(userProfile, HttpStatus.OK);
}
Used getter and setter in UserProfile
public class UserProfile {
private int age;
private String name;
private String currenecy;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCurrenecy() {
return currenecy;
}
public void setCurrenecy(String currenecy) {
this.currenecy = currenecy;
}
}
Finally after after spending some time.. I figured out why it was not working.
In my java based spring configuration file I missed "#EnableWebMvc".
After adding it, my problem got resolved.
#Configuration
**#EnableWebMvc** // This annotation was missing.
#ComponentScan(basePackages="com.hemant.*")
public class TestConfiguration {}

Spring rest controller giving unsupported content type

Hello all here is what i have:
StockController.java
#RestController
public class StockController {
#Autowired
private StockRepository repository;
#RequestMapping(value = "stockmanagement/stock")
public ResponseEntity<?> addStock(#RequestBody String stock
) {
System.out.println(stock);
return new ResponseEntity<>(HttpStatus.OK);
}
when I make a request like so using chrome advanced rest extension :
Raw Headers
Content-Type: application/json
Raw Payload
{"stock": {"productId": 2, "expiryAndQuantity" : {}, "id": 0}}
It works fine in that out comes a string of json
However when i try to replace String stock with Stock stock where stock looks like this:
public class Stock {
#Id
private String id;
private String productId;
private Map<LocalDateTime, Integer> expiryAndQuantity;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
public Map<LocalDateTime, Integer> getExpiryAndQuantity() {
return expiryAndQuantity;
}
public void setExpiryAndQuantity(Map<LocalDateTime, Integer> expiryAndQuantity) {
this.expiryAndQuantity = expiryAndQuantity;
}
#Override
public String toString() {
return String.format(
""
);
}
}
I get an error where by the following is fed back to me:
"status": 415
"error": "Unsupported Media Type"
"exception": "org.springframework.web.HttpMediaTypeNotSupportedException"
"message": "Content type 'application/json;charset=UTF-8' not supported"
"path": "/stockmanagement/stock"
My question is; how do i create a request which maps to my Stock object.
You can try with #JsonRootName annotation, by default Spring serialize using no root name value. like this:
{"productId": 2, "expiryAndQuantity" : {}, "id": 0}
But if you want that your serialization has a rootname you need to use #JsonRootName annotation.
#JsonRootName(value = "Stock")
And it'll produce something like this
{"Stock": {"productId": 2, "expiryAndQuantity" : {}, "id": 0}}
You can see more here
http://www.baeldung.com/jackson-annotations
instead of accepting a String Accept a Stock object.and accept it from a post request than having a get request
#RequestMapping(value = "stockmanagement/stock",method=RequestMethod.POST)
public ResponseEntity<?> addStock(#RequestBody Stock stock){
}
and your request should be sent like this
{
"productId": 2
,"expiryAndQuantity" : null
,"id": 0
}
all parameter names should be equal to the objects filed names,since spring has jackson binders on class path and object will be created inside the controller method. if you are planning on passing different parameters from the post request you can use
#JsonProperty("pid")
private String productId;
on the field name.

#ResourceMapping that accepts JSON from Ajax request

I'm searching how I can interprete a JSON parameter in my #ResourceMapping in Spring Portlet MVC. When I add #RequestBody, I got the message: #RequestBody is not supported... Really stuck on this one.
I have this:
View side:
<portlet:resourceURL var="getTest" id="ajaxTest" ></portlet:resourceURL>
<p>
<button onClick="executeAjaxTest();">Klik mij!</button>
<button onClick="$('#ajaxResponse').html('');">Klik mij!</button>
</p>
<p>
<h3>Hieronder het antwoord:</h3>
<h4 id="ajaxResponse"></h4>
</p>
<script>
function executeAjaxTest() {
var jsonObj = {
user: "Korneel",
password: "testpassword",
type: {
testParam: "test",
}
}
console.debug(JSON.stringify(jsonObj));
$.ajax({
dataType: "json",
contentType:"application/json",
mimeType: 'application/json',
url:"<%=getTest%>",
data:JSON.stringify(jsonObj),
success : function(data) {
$("#ajaxResponse").html(data['testString']);
}
});
}
</script>
Controller side:
#ResourceMapping(value="ajaxTest")
#ResponseBody
public void ajaxTestMethod(ResourceRequest request, ResourceResponse response) throws IOException, ParseException {
LOGGER.debug("ajax method");
JSONObject json = JSONFactoryUtil.createJSONObject();
json.put("testString", "Ik ben succesvol verstuurd geweest!");
response.getWriter().write(json.toString());
}
How can I use the spring magic to auto map this JSON data to my own model?
Note: It's Spring Portlet MVC, not regular Spring MVC..
#ResponseBody annotation is not supported out of the box in Spring MVC portlet framework, but you can implement #ResponseBody handling yourself.
We do it by implementing custom view type and model and view resolver.
Implement custom model and view resolver (ModelAndViewResolver), let's say JsonModelAndViewResolver.
In resolveModelAndView method, check whether controller method has #ResponseBody annotation (or more specific condition to identify JSON output - e.g. annotation + required supported mime type).
If yes, return your custom View implementation - let's say SingleObjectJson view (extending AbstractView).
Pass your to-be-serialized object to the view instance.
The view will serialize the object to JSON format and write it to the response (by using Jackson, Gson or other framework in renderMergedOutputModel method).
Register the new resolver as AnnotationMethodHandlerAdapter.customModelAndViewResolvers.
You need to build your json object like this:
var jsonObj = {
user: "Korneel",
password: "testpassword",
"type.testParam" : "test"
};
$.ajax({
dataType: "json",
contentType:"application/json",
mimeType: 'application/json',
url:"<%=getTest%>",
data:jsonObj,
success : function(data) {
$("#ajaxResponse").html(data['testString']);
}
});
In your Controller you should use the #ModelAttribute annotation:
#ModelAttribute(value = "jsonObj")
public JsonObjCommand obtenerJsonObjCommand() {
JsonObjCommand jsonObjCommand = new JsonObjCommand();
return jsonObjCommand;
}
#ResourceMapping(value = "ajaxTest")
public void ajaxTestMethod(
ResourceRequest request,
ResourceResponse response,
#ModelAttribute(value = "jsonObj") JsonObjCommand jsonObjCommand)
throws IOException, ParseException {
LOGGER.debug("USER: " + jsonObjCommand.getUser());
LOGGER.debug("Password: " + jsonObjCommand.getPassword());
LOGGER.debug("TestParam: " + jsonObjCommand.getType().getTestParam());
LOGGER.debug("ajax method");
JSONObject json = JSONFactoryUtil.createJSONObject();
json.put("testString", "Ik ben succesvol verstuurd geweest!");
response.getWriter().write(json.toString());
}
Don't forget your beans:
public class JsonObjCommand {
private String user;
private String password;
private TypeJson type;
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public TypeJson getType() {
return type;
}
public void setType(TypeJson type) {
this.type = type;
}
}
public class TypeJson {
private String testParam;
public String getTestParam() {
return testParam;
}
public void setTestParam(String testParam) {
this.testParam = testParam;
}
}
According to the documentation, #RequestBody is only supported in Servlet environments, not Portlet environments (same for #ResponseBody). So it seems you can't use that functionality.

How to return a list of object as Json in Spring MVC

I'm trying to get a list of objects to render on a Spring 3 MVC app and would like to do this via Ajax.
So in my Spring class I have:
#RequestMapping(value = "/viewSearchEnquiriesAjax", method = RequestMethod.GET, headers = "Accept=application/json")
public #ResponseBody List<Enquiry> getEnquiriesBySearchAjax(#RequestParam String name) {
Search search = new Search();
search.setFirstName(name);
return searchEnquiries(search);
}
But I get a 500 (Internal Server Error) when this is run. This manifests itself when I'm debugging in the browser as 'GET http://localhost:8080/SpringMVC/viewSearchEnquiriesAjax?name=peter 500 (Internal Server Error)'
I can successfully return a single object with no error. Can the Spring Json mapper(Jackson) convert correctly? Am I missing something fundamental?
My javascript is as follows:
function doAjaxPost() {
// get the form values
var firstName = $('#firstName').val();
$.getJSON("/SpringMVC/viewSearchEnquiriesAjax", { name: firstName }, function(result) {
alert("Success");
});
}
My Enquiry object is an Entity:
#Entity
#Table(name = "enquiries")
public class Enquiry implements java.io.Serializable{
private static final long serialVersionUID = -5093725544297637792L;
protected Long id;
protected Date created = new Date();
...
...
public Enquiry() {
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", unique = true, nullable = false)
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
...
...
For Jackson you have to create a strongly typed list class because of type erasure:
public class EnquiryList extends ArrayList<Enquiry> {
}
Then return this list from your controller:
#RequestMapping(value = "/viewSearchEnquiriesAjax", method = RequestMethod.GET, headers = "Accept=application/json")
public #ResponseBody EnquiryList getEnquiriesBySearchAjax(#RequestParam String name) {
EnquiryList list = new EnquiryList();
...
return list;
}
Also check out this answer on a similar question.

Resources