Unable to convert a json array into java list - java

I have the following Json string:
String jsonString = "[
{
"nameOnCard": "Test T",
"active": true,
"declineReason": null
},
{
"nameOnCard": "TestT",
"active": false,
"declineReason": "payment_stolen"
}
]";
The string is contained in an object called ApiResponse in a field called data. E.g.
APIResponse apiResponse = APIResponse.builder()
.data(jsonString)
.build();
I am trying to map the contents of the string into a list of PaymentObject.
The payment object looks like this:
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class PaymentObject {
private String declineReason;
private String nameOnCard;
private String active;
}
I am using the following to convert the String into a List<PaymentObject> by the following:
List<PaymentObject> paymentObjectDTOs = mapper.convertValue(apiResponse.getData(), new TypeReference<>() {});
where mapper is ObjectMapper from Jackson 2.13.2.2.
But I am getting the following error:
Cannot deserialize value of type `java.util.ArrayList<com.abc.PaymentObject>` from String value (token `JsonToken.VALUE_STRING`)
at [Source: UNKNOWN; byte offset: #UNKNOWN]
I can't see what's going wrong.

You're missing the referenced type. This will work:
List<PaymentObject> paymentObjectDTOs =mapper.readValue(apiResponse.getData(), new TypeReference<List<PaymentObject>>(){});
But make sure you've all the getters and setters methods on the PaymentObject class, as well as the default constructor.

Related

Issue with serializing JSON from a rest call

Newbie developer here. I am trying to make a call to a public API. The API receives the name of a drink as a string and returns information and recipe for that name. The response from the API looks like this:
{
"drinks":[
{
"id": ...
"name": ...
"recipe": ...
"category": ...
"alcoholic": ...
... many other fields ...
},
{
...
}
...
]
}
I am only interested in name, recipe and category. I have a domain class for this purpose that looks like this
#Data
#NoArgsConstructor
#AllArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class Drink {
#JsonProperty("name")
private String name;
#JsonProperty("category")
private String category;
#JsonProperty("recipe")
private String recipe;
}
I also implemented a client to call the endpoint using restTemplate. Here is the call that client makes:
ResponseEntity<List<Drink>> response = restTemplate.exchange(
url,
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<Drink>>() {
});
My goal is to call the API, get the response and only the fields that I want and store it in a list of Drink. However when I try to run the app locally and make a call I am getting this error:
Caused by: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.util.ArrayList<Drink>` from Object value (token `JsonToken.START_OBJECT`); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `java.util.ArrayList<Drink>` from Object value (token `JsonToken.START_OBJECT`)
When I use ResponseEntity<String> instead, it works but returns the whole json as a string, which does not seem like a good approach. How can I get this approach to work?
The problem is mismatch between json structure and object structure. The object you deserialize into must represent correctly the json. It's an object with a field drinks, which is an array of objects(drinks in your case). Correct java class would be:
public class Wrapper {
private List<Drink> drinks;
//getters and setters
#Override
public String toString() {
return "Wrapper{" +
"drinks=" + drinks +
'}';
}
}
Other option would be to write custom deserializer, which can extract drinks from the tree before deserializing directly into a list.]
Edit: Added toString() override for debugging purposes.

no String-argument constructor/factory method to deserialize from String value - Exception while deserializing json object from restTemplate

Facing issue while making call to retrieve a json response and parse it.
[
{
"name": "john doe",
"age": "24",
"address": "{\"state\":\"LA\",\"country\":\"US\"}"
}
]
Models:
Person.java
#Data
#NoArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class Person {
private String name;
private String age;
private Address address;
}
Address .java
#Data
#NoArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class Address {
private String state;
private String country;
}
Code to read this data,
ResponseEntity<List<Person>> response = restTemplate.exchange(builder.toUriString(), HttpMethod.GET,requestEntity,new ParameterizedTypeReference<List<Person>>() {});
However i get below exception,
RestClientException while invoking ABS ServiceError while extracting response for type [java.util.List<com.bp.model.Person>] and content type [application/json;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of com.bp.model.Address (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"state":"LA","country":"US"}'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of com.bp.model.Address (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"state":"IN","brand":"anthem"}')
at [Source: (PushbackInputStream); line: 1, column: 325] (through reference chain: java.util.ArrayList[0]->com.bp.model.Person["address"])
The code is correct but there's a problem with the JSON. The address is a string and not a JSON object. For it to work, it would need to be something like:
"address": {"state": "LA", "country": "US"}
Without the outer quotes and the escape characters.
Here we can try to set the values during runtime.
#JsonProperty("address")
public void setCustomAddress(String addressFromJson){
this.address = new Gson().fromJson(addressFromJson, Address.class);
}
JSON string to Map:
String json = "{"name":"mkyong", "age":"37"}";
Output {name=mkyong, age=37}
public static void main(String[] args) {
ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"mkyong\", \"age\":\"37\"}";
try {
// convert JSON string to Map
Map<String, String> map = mapper.readValue(json, Map.class);
// it works
//Map<String, String> map = mapper.readValue(json, new TypeReference<Map<String, String>>() {});
System.out.println(map);
} catch (IOException e) {
e.printStackTrace();
}
}
Map to JSON string:
{"name":"mkyong","age":"37"}
{
"name" : "mkyong",
"age" : "37"
}
public static void main(String[] args) {
ObjectMapper mapper = new ObjectMapper();
Map<String, String> map = new HashMap<>();
map.put("name", "mkyong");
map.put("age", "37");
try {
// convert map to JSON string
String json = mapper.writeValueAsString(map);
System.out.println(json); // compact-print
json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(map);
System.out.println(json); // pretty-print
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
In Jackson, we can use mapper.readValue(json, Map.class) to convert a JSON string to a Map. Dependency
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>

Map JSON to POJO Using Jackson

I'm trying to get map a JSON to a POJO using jackson and I keep getting the following error:
> Can not deserialize instance of java.lang.String out of START_OBJECT token\n at [Source: (String)\"{\"checkstyle\
The JSON Im trying to parse is the following:
{
"checkstyle": {
"file": [
{
"name": "src\\main\\java\\com\\report\\uploader\\controller\\RandomController.java",
"error": [
{
"severity": "error",
"line": 0,
"source": "com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocPackageCheck",
"message": "Missing package-info.java file."
}
]
}
],
"version": 6.18
}
}
For this I create the following classes:
public class Checkstyle {
#JsonProperty("checkstyle")
private Linter linterName;
}
public class Linter {
#JsonProperty("file")
private List<File> files;
#JsonProperty("version")
private String version;
}
public class File {
#JsonProperty("name")
private String name;
#JsonProperty("error")
private List<Error> errores;
}
public class Error {
#JsonProperty("severity")
private String severity;
#JsonProperty("line")
private int line;
#JsonProperty("source")
private String source;
#JsonProperty("message")
private String message;
}
But when I run the code I get the error mentioned above. The way I get this JSON is by converting an XML file to a JSONObject using the org.json dependency and then the JSONobject I convert it to a String.
Then I convert then I try to convert the String into my POJO the following way:
ObjectMapper mapper = new ObjectMapper();
Checkstyle checkstyle = mapper.readValue(object.toString(), Checkstyle.class);
If anyone could point me out what I'm doing wrong I would appreciate.
This is the line causing error in your program mapper.readValue(object.toString(), Checkstyle.class). You have already read the json into an anonymous object, and then using its toString() representation in ObjectMapper to map to Checkstyle class, which will never work. As you already have lost the json string into java default toString representation of object: someObjectClassname#hashcodenumber.
Below are the some of the commonly used signature of readValue method to do correrct de-serialization:
readValue(InputStream in, Class c)
readValue(Reader rd, Class c)
readValue(String json, Class c)

How to unmarshall json lists using Spring Boot RestTemplate

I have to parse a REST response in json and it has a lot of nested lists with many objects.
The response contains an item called "ObjectList" which has a list and inside, two elements, "ObjectA" and "ObjectB". I don't know how to parse the response to objects using Jackson annotations.
The json looks like this:
"ObjectList": [
{
"ObjectA": {
"property1": false,
"property2": true
},
"ObjectB": {
"property1": 66,
"property2": true
},
{
"ObjectA": {
"property1": false,
"property2": true
},
"ObjectB": {
"property1": 66,
"property2": true
}
}
]
}
My code looks like this
ResponseEntity<Response> response = restTemplate.exchange(URL, HttpMethod.GET, request, Response.class);
Response response = response.getBody();
Response is:
#JsonIgnoreProperties(ignoreUnknown = true)
public class TimesheetListResponse {
#JsonProperty("ObjectA")
private List<ObjectA> objectAList;
#JsonProperty("ObjectB")
private List<ObjectB> objectBList;
That does not work at all, and I'm confused about how to map this.
According to your requirement the model structure may look like below. Within the objectList map in Response object, you need to add HashMap with keys as "ObjectA"/"ObjectB" string and value as instance of ObjectA/ObjectB. I have taken value type of Map as Object, so that any object type A/B can fit in there. Add corresponding #JsonXXX annotations.
public class Response {
private List<Map<String,Object>> objectList;
//Getters & Setters
}
public class ObjectB {
String propB1;
String propB2;
}
public class ObjectA {
String propA;
String propA1;
}
I also would consider the entry in the list as another wrapper object that can either ObjectA or ObjectB. I.e.
#JsonIgnoreProperties(ignoreUnknown = true)
public final class Parent {
#JsonProperty("ObjectList")
private List<ChildWrapper> objectList = new ArrayList<>();
}
#JsonIgnoreProperties(ignoreUnknown = true)
public final class ChildWrapper {
#JsonProperty("ObjectA")
private Child ObjectA;
#JsonProperty("ObjectB")
private Child ObjectB;
}
#JsonIgnoreProperties(ignoreUnknown = true)
public final class Child {
#JsonProperty("property1")
private int property1;
#JsonProperty("property2")
private boolean property2;
}
It seems that the mapping was fine, I only had to initialize the Arraylist. The main issue was that the endpoint was returning empty because of a parameter that I forgot.

Ignore a java bean field while converting to jSON

Ignore a java bean field while converting to jSON
I am having a java bean and sending JSON as response , In that java bean I want to have
some transient fields , that should not come into JSON .
#XmlRootElement(name = "sample")
class Sample{
private String field1;
#XmlTransient
private String transientField;
//Getter and setters
public String toJSON() throws Exception {
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(this);
return json;
}
}
When I am calling toJSON method I am still getting "transientField" in JSON.
And I have a get rest API that returns this Sample JSON as response.
#GET
#Path("/somePath/")
#Produces({"application/json"})
Sample getSample();
In this response also I am getting that transient field .
Am I doing something wrong? Please help me to do this .
Try using #JsonIgnore instead.
method 1: use annotation #JsonIgnoreProperties("fieldname") to your POJO
example : #JsonIgnoreProperties(ignoreUnknown = true, value = {"fieldTobeIgnored"})
method 2:#JsonIgnore for a specific field that is to be ignored deserializing JSON

Categories

Resources