JSON object and Multipart file upload not working - json

We have Angular Controller as follows
$scope.uploadData = function (files, data) {
var fd = new FormData();
fd.append("CustomerName", "Mahesh"); //As of now mocking the entities for creating form data
fd.append("CustomerID ", "44444");
fd.append("ProductList", JSON.stringify([{ProductID: '0001', ProductName: 'Samsung'},{ProductID: '0002', ProductName: 'Voldats'}]));
fd.append("file", files[0]);
fd.append("file", files[1]);
inventoryService.Postfile(fd);
}
Restangular post as follows
Postfile : function (formData) {
return restangular.all("postfile").withHttpConfig({transformRequest: angular.identity}).customPOST(formData, '', undefined, {'Content-Type': undefined});
},
Java VOs as follows
public class ProductList implements Serializable{
private String ProductID;
private String ProductName;
public String getProductID() {
return ProductID;
}
public void setProductID(String productID) {
ProductID = productID;
}
public String getProductName() {
return ProductName;
}
public void setProductName(String productName) {
ProductName = productName;
}
}
and
public class CustomerList implements Serializable{
String CustomerName;
String CustomerID;
List<ProductList> ProductList;
public String getCustomerName() {
return CustomerName;
}
public void setCustomerName(String customerName) {
CustomerName = customerName;
}
public String getCustomerID() {
return CustomerID;
}
public void setCustomerID(String customerID) {
CustomerID = customerID;
}
public List<ProductList> getProductList() {
return ProductList;
}
public void setProductList(List<ProductList> productList) {
ProductList = productList;
}
}
Spring controller as follows
#ResponseStatus(HttpStatus.OK)
#RequestMapping(value = "/api/postfile", method = RequestMethod.POST)
public #ResponseBody
IhmsVO postfile(#RequestParam("file") List<MultipartFile> files,
#ModelAttribute(value = "data") CustomerList vo, BindingResult bindingResult, Model model) {
System.out.println("Post file");
System.out.println(vo.getProductList());
System.out.println("Files :: " + files + " " + files.size());
return null;
}
We have uploaded two files and JSON Object, CustomerName and CustomerID mapped properly with corresponding VO, but ProductList not mapped with the VO.We are getting null in ProductList, Debug mode screenshot attached for refrence. May help to resolve this?

You have to use Blob with correct content type to pass the JSON data and add it to the form (https://developer.mozilla.org/en/docs/Web/API/Blob), e.g.:
fd.append("ProductList", new Blob([ JSON.stringify([{ProductID: '0001', ProductName: 'Samsung'},{ProductID: '0002', ProductName: 'Voldats'}]) ], { type: "application/json" }));
EDIT: Updated the code to be absolutely clear and avoid any typos, case sensitivity issues, wrong placement of parenthesis etc.

Related

SpringBoot JSON not deserializing into my request model

I am using SpringBoot and trying to deserialize JSON like:
{
"userId": "Dave",
"queryResults": {
"id": "ABC",
"carData": {.....},
"carId": "Honda",
"status": 0,
"model": "X"
}
}
, into MyRequestModel clas:
public class MyRequestModel {
private String userId;
private String: queryResults;
}
, that is received as #RequestBody parameter in my #PostMapping method that looks like:
#PostMapping
public String postDate(#RequestBody MyRequestModel data) {
...
return "posted";
}
The above queryResults field is supposed to be stored as a CLOB in a database.
Problem I am having is that if I send this JSON to hit my endpoint (PostMapping) method, it cannot deserialize it into MyRequestModel and I get this error:
Cannot deserialize instance of java.lang.String out of START_OBJECT token
at [Source: (PushbackInputStream); line: 3, column: 18] (through reference chain: MyRequestModel["queryResults"])]
I guess the real answer to your question is: if you NEED the queryResults property to be a String, then implement a custom deserializer.
If not, then, use one of the alternatives that Jonatan and Montaser proposed in the other answers.
Implementing a custom deserializer within Spring Boot is fairly straightforward, since Jackson is its default serializer / deserializer and it provides a easy way to write our own deserializer.
First, create a class that implements the StdDeserializer<T>:
MyRequestModelDeserializer.java
public class MyRequestModelDeserializer extends StdDeserializer<MyRequestModel> {
public MyRequestModelDeserializer() {
this(null);
}
public MyRequestModelDeserializer(Class<?> vc) {
super(vc);
}
#Override
public MyRequestModel deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonNode node = p.getCodec().readTree(p);
String userId = node.get("userId").asText();
String queryResults = node.get("queryResults").toString();
MyRequestModel model = new MyRequestModel();
model.setQueryResults(queryResults);
model.setUserId(userId);
return model;
}
}
Second, mark your class to be deserialized using your custom deserializer by using the #JsonDeserialize annotation:
MyRequestModel.java
#JsonDeserialize(using = MyRequestModelDeserializer.class)
public class MyRequestModel {
private String userId;
private String queryResults;
}
It's done.
queryResults is a String on Java side but it is an Object on JSON side.
You will be able to deserialize it if you send it in as a String:
{
"userId": "Dave",
"queryResults": "foo"
}
or if you create classes that maps to the fields:
public class MyRequestModel {
private String userId;
private QueryResults queryResults;
}
public class QueryResults {
private String id;
private CarData carData;
private String carId;
private Integer status;
private String model;
}
or if you serialize it into something generic (not recommended):
public class MyRequestModel {
private String userId;
private Object queryResults;
}
public class MyRequestModel {
private String userId;
private Map<String, Object> queryResults;
}
public class MyRequestModel {
private String userId;
private JsonNode queryResults;
}
You have two options to deserialize this request:-
change the type of queryResults to Map<String, Object>, it will accepts everything as an object of key and value. (Not recommended)
public class MyRequestModel {
private String userId;
private Map<String, Object> queryResults;
}
You have to create a class that wraps the results of queryResults as an object.
class QueryResult {
private String id;
private Map<String, Object> carData;
private String carId;
private Integer status;
private String model;
public QueryResult() {}
public QueryResult(String id, Map<String, Object> carData, String carId, Integer status, String model) {
this.id = id;
this.carData = carData;
this.carId = carId;
this.status = status;
this.model = model;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Map<String, Object> getCarData() {
return carData;
}
public void setCarData(Map<String, Object> carData) {
this.carData = carData;
}
public String getCarId() {
return carId;
}
public void setCarId(String carId) {
this.carId = carId;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
}
and make the type of queryResult as shown:-
public class MyRequestModel {
private String userId;
private QueryResult queryResults;
}

JAX-RS Json response comes in one line

This is probably some basic question. I am using JAX-RS (jersey implementation) and my code is as follows.
#Path("/data")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Car handlerFn(#Context HttpServletResponse res)
{
res.setStatus(HttpServletResponse.SC_OK);
Car carObject = new Car(42,"Maruthi", "Alto");
return carObject;
}
Car Entity is as follows
public class Car {
int id;
String name;
String model;
public Car() {
}
public Car(int id, String name, String model)
{
this.id=id;
this.name = name;
this.model = model;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getModel() {
return model;
}
}
The output I am getting is in one line as follows
{"id":42,"model":"Alto","name":"Maruthi"}
In place of this I want the each member in different lines as follows
{
"id": 42,
"model": "Alto",
"name": "Maruthi"
}
How can I do that?

SpringBoot Rest response not deserialiazed with jackson

I am a running a project with SpringBoot. In this project I am calling an external Rest Service. I have modeled the response items into bean.
But when I get the response back the data are not serialised into the beans.
I guess there must be some configuration missing but I cannot find what.
I have added onfiguration spring-boot-starter-test to the configuration of Maven:
The rest client:
#RunWith(SpringRunner.class)
#SpringBootTest
public class RestClientTest {
#Autowired
private RestTemplateBuilder restTemplate;
#Test
public void sayHello() {
System.out.println("Hello");
assert(true);
}
#Test
public void testGetEmployee() {
RestTemplate template = restTemplate.build();;
HttpHeaders headers = new HttpHeaders();
List<MediaType> types = new ArrayList<MediaType>();
types.add(MediaType.APPLICATION_JSON);
types.add(MediaType.APPLICATION_XML);
headers.setAccept(types);
headers.set("Authorization", "Bearer gWRdGO7sUhAXHXBnjlBCtTP");
HttpEntity<Items> entity = new HttpEntity<Items>(headers);
String uri = "https://mytest.com/employees";
//ResponseEntity<String> rec = template.exchange(uri, HttpMethod.GET, entity, String.class);
//System.out.println("Received: " + rec);
ResponseEntity<Items> rec = template.exchange(uri, HttpMethod.GET, entity, Items.class);
System.out.println("Received: " + rec);
}
}
When I inspect the elements of the response it, I get a list, all the items are with null values
#JsonFormat(shape = JsonFormat.Shape.OBJECT)
public class Item implements Serializable {
#JsonProperty
private String id;
#JsonProperty
private String name;
#JsonProperty
private String email;
#JsonProperty
private String phone;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
#JsonFormat(shape = JsonFormat.Shape.OBJECT)
public class Items implements Serializable {
#JsonProperty
private List<Item> items = new ArrayList<Item>();
public List<Item> getItems() {
return items;
}
}
Do you see what I am missing here?
The response is like this:
{
"items": [
{
"item": {
"id": 0,
"name": "string",
"email": "string",
"phone": "string",
Do you see what I am missing here?
Thanks
Gilles
The way you have implemented will try to deserialize data into Items class. But it doesn't have the required properties to deserialize. When you need to get a list of data through rest template exchange, you can get them as follows.
Get data as an array and convert it into arrayList.
Item[] itemArray = template.exchange(uri, HttpMethod.GET, entity, Item[].class).getBody();
List<Item> itemList = Arrays,asList(itemArray);
or
Use ParameterizedTypeReference to get data as a list
ResponseEntity<List<Item>> itemList = template.exchange(uri, HttpMethod.GET, entity, new ParameterizedTypeReference<List<Item>>() {});
List<Item> itemList = template.exchange(uri, HttpMethod.GET, entity, new ParameterizedTypeReference<List<Item>>() {}).getBody(); // access list directly
You might need to add this to your ObjectMapper:
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
And on your entity add #JsonRootName("item")

How to use native query with spring repo mapped to custom object?

I have table t1:
id | title
1 | title1
2 | title2
and I have the following spring repo method:
#Query(nativeQuery = true, value = "select id, title from t1")
public List<T1> getAll();
The custom class is:
public class T1 {
#JsonProperty("id")
private Integer id;
#JsonProperty("title")
private String title;
public T1(Integer id, String title) {
this.id = id;
this.title = title;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
I'm expecting to get the following json response:
{[{"id":1, "title":"titl1"}, {"id":2, "title":"titl2"}]}
However i'm getting this one:
[[1,"title1"],[2,"title2"]]
I'm using #RestController
#RequestMapping(method = RequestMethod.GET, value = "/test", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntityTestResponse> test() {
List<T1> list = testRepository.getAll();
TestResponse response = new TestResponse(list);
return new ResponseEntity<TestResponse>(response, HttpStatus.OK);
}
TestResponse class is:
public class TestResponse implements Serializable {
private TreeSet<T1> list = new TreeSet<>();
public TestResponse(TreeSet<T1> list) {
this.list = list;
}
....
Can you help with that?
This response is classic Java List, if you need it as JSON object, you have to use for example GSON and then you should write something like this:
sonBuilder builder = new GsonBuilder();
Gson gson = builder.create();
System.out.println(gson.toJson(YOUR_LIST_OF_T1));
Here are examples (included that was i wrote) and here is GitHub repo.
You can do it manually by overrite toString() method in T1 class if u need it in specific signature, and u didn't got any API doing what you want.
So if u try some thing like that
List<T1> list = testRepository.getAll();
StringBuilder strBuilder = new StringBuilder();
for(T1 t : list){
strBuilder.append(t.toString() + ", ");
}
String result = "";
if(strBuilder.length()!=0){
result = "{[" + strBuilder.substring(0, strBuilder.length()-2) + "]}";
}
System.out.println(result);
and class should overrite toString() method
class T1{
#JsonProperty("id")
private Integer id;
#JsonProperty("title")
private String title;
public T1(Integer id, String title) {
this.id = id;
this.title = title;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
#Override
public String toString() {
return "{\"id:\"" + id + ", \"title:\"" + title + "}";
}
}
Also if you want to use pure java standard library you can do it like next code but you will need to download javax.json-xxxx.jar(for example >> javax.json-1.0.4.jar) (that include providers or the implementation) to your library project path
But this next code will generate something like that
[{"id":1,"title":"Title1"},{"id":2,"title":"Title2"},{"id":3,"title":"Title3"}]
List<T1> list = testRepository.getAll();
JsonArrayBuilder jsonArray = Json.createArrayBuilder();
for(T1 t : list) {
jsonArray.add(Json.createObjectBuilder()
.add("id", t.getId())
.add("title", t.getTitle()));
}
System.out.println(jsonArray.build());

Mapping json object to Spring object in REST service

I have a REST service defined in Spring as follows:
#RequestMapping(value = "/create", method = RequestMethod.POST)
#ResponseBody
public ResponseEntity<String> addArticle(#RequestBody Article article){
try{
articleService.addArticle(article.getTitle(),
article.getContent(),
article.getTags(),
article.getPublishStatus(),
article.getCompanyId(),
article.getCategory());
return new ResponseEntity<String>(HttpStatus.OK);
} catch (Exception e){
e.printStackTrace();
return new ResponseEntity<String>(e.getMessage(), HttpStatus.OK);
}
}
And my article is defined as follows:
public class Article {
private int id;
private String title;
private String content;
private String smsContent;
public String getSmsContent()
{
return smsContent;
}
public void setSmsContent(String smsContent)
{
this.smsContent = smsContent;
}
private String[] tags;
private int companyId;
private String category;
public String getCategory(){
return category;
}
public void setCategory(String category){
this.category = category;
}
private byte publishStatus;
public String getTitle(){
return title;
}
public void setTitle(String title){
this.title = title;
}
public String getContent(){
return content;
}
public void setContent(String content){
this.content = content;
}
public String[] getTags(){
return tags;
}
public void setTags(String[] tags){
this.tags = tags;
}
public int getCompanyId(){
return companyId;
}
public void setCompanyId(int companyId){
this.companyId = companyId;
}
public byte getPublishStatus(){
return publishStatus;
}
public void setPublishStatus(byte publishStatus){
this.publishStatus = publishStatus;
}
public int getId(){
return id;
}
public void setId(int id){
this.id = id;
}
}
How do I call this service using Angular? I tried following code:
function createArticle(name, companyId, title, content, tags, category) {
var request = $http({
method : 'POST',
url : '/inbound/api/article/create.json',
headers : {
'Content-Type' : 'application/x-www-form-urlencoded'
},
transformRequest : function(obj) {
var str = [];
for ( var p in obj)
str.push(encodeURIComponent(p) + "="
+ encodeURIComponent(obj[p]));
return str.join("&");
},
data : {
title : title,
content : content,
tags : tags,
companyId : companyId,
category: category
}
});
I am getting error 415 (Unsupported Media Type). Any ideas?
Since you're working with JSON, you need to set your form and handler accordingly.
REST handler
#RequestMapping(value = "/create", method = RequestMethod.POST, consumes = "application/json")
Angular
headers : {
'Content-Type' : 'application/json'
},
First
you have:
#RequestMapping(value = "/create", method = RequestMethod.POST)
just /create
Second
You have:
url : '/inbound/api/article/create.json',
Proceed to remove the .json that's the problem
Third
Be sure to indicate for the ajax event, the data you are sending is in JSON