Deserializing complex json with matching objects by id (Jackson) - java

I have a proprietary API that return a complex JSON like:
{
"store": "store_name",
"address": "store_address",
"department": [
{
"name": "d1",
"type": "t1",
"items": [
"i1",
"i2"
]
},
{
"name": "d2",
"type": "t2",
"items": [
"i3"
]
}
],
"itemDescriptions": [
{
"id": "i1",
"description": "desc1"
},
{
"id": "i2",
"description": "desc2",
"innerItems": [
"i2"
]
},
{
"id": "i3",
"description": "desc3"
}
]
}
Is it possible to deserialize this JSON using Jackson into:
#AllArgsConstructor
class Store {
private final String store;
private final String address;
private final List<Department> departments;
/*some logic*/
}
#AllArgsConstructor
class Department {
private final String name;
private final String type;
private final List<Item> items;
/*some logic*/
}
#AllArgsConstructor
class Item {
private final String id;
private final String description;
private final List<Item> innerItems;
/*some logic*/
}
I tried to find answers, but find only this question without solution.
I know that I can do it in my code (deserialize as it is and create objects from result), but its very memory intensive (I have a lot of json and it can be large).
I know that I can write fully custom deserializer, but in this case, I have to describe the deserialization of each field myself - in case of some changes, I will have to change the deserializer, and not just the class(POJO/DTO).
Is there a way to do this with Jackson (or Gson) or with a minimal (preferably relatively generic) amount of my code?

Related

Error parsing JSON (MismatchedInputException)

I'm having problems parsing JSON, this is the error:
out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList<packagename....>` out of START_OBJECT token
And I know why it is happening I just don't know how to fix it. This JSON works:
{
"status_code": "SUCCESS",
"time": {
"date": "Mar 23, 2021 1:14:39 AM"
},
"info": [
{
"person": "2.2",
"role": "TEACHER"
},
{
"person": "2.3",
"role": "TEACHER"
}
]
}
This one does not:
{
"status_code": "SUCCESS",
"time": {
"date": "Mar 23, 2021 3:49:27 AM"
},
"info": {
"id": "1",
"person": [
{
"identifier": "John",
"role": "TEACHER"
},
{
"identifier": "Homer",
"role": "TEACHER"
},
{
"identifier": "Michael",
"role": "TEACHER"
},
{
"identifier": "Sarah",
"role": "TEACHER"
}
]
}
}
The problem seems to be the { character in front of the info field because with [ works. So this is the method I'm using to parse the JSON:
public Mono<PersonResponse> searchById(String id) {
return webClient.get().uri(id).retrieve().bodyToMono(PersonResponse.class);
}
Also tried:
public Mono<PersonResponse[]> searchById(String id) {
return webClient.get().uri(id).retrieve().bodyToMono(PersonResponse[].class);
}
Error right on line: 1, column: 1. Any suggestions of how to implement the method?
EDIT: Added classes.
PersonResponse:
public class PersonResponse implements Serializable{
private static final long serialVersionUID = 7506229887182440471L;
public String status_code;
public Timestamp time;
public List<PersonDetails> info;
public PersonResponse() {}
...getters / setters / toSting
PersonDetails:
public class PersonDetails implements Serializable{
private static final long serialVersionUID = 1294417456651475410L;
private int id;
private List<Person> person;
public PersonDetails(int version) {
super();
this.version = version;
}
...getters / setters / toSting
Person
public class Person implements Serializable{
private static final long serialVersionUID = 3290753964441709903L;
private String identifier;
private String role;
public Person(String identifier, String role) {
super();
this.identifier = identifier;
this.role = role;
}
...getters / setters / toSting
The problem isn't the JSON necessarily, it's that the JSON structure doesn't match your PersonResponse class. There's an info variable in PersonResponse that requires an array of what I assume to be persons, in the second example you're trying to push an object in there, which you can't. You have to either change your JSON, which you don't seem to want in this case, or the class you're trying to parse it to.
You need to restructure the info variable in PersonResponse to match the object you're trying to parse to it.

how to serialize a specific json format

I need to set json in a format provided below.
"Tyre": {
"title": "Tyre",
"cls": "TyreCondition",
"items": [
{
"firstItem": [
{
"title": "Front right tyre",
"value": "50%",
"subValue": "30,000 km Approx"
}
],
"secItem": [
{
"title": "title",
"value": "Front right tyre tread - 50%"
},
{
"title": "title",
"value": "Front right tyre tread - 50%"
}
]
}
]
}
class that i have created for this is looks like:
private String title;
private String cls;
#SerializedName("firstItem")
private List<UsedCarInspectionInfo> items;
#SerializedName("secItem")
private List<UsedCarTyreImage> imageList;
//getter and setter
when i run this code with this class structure, I am getting the json like-
"Tyre": {
"title": "Tyre",
"cls": "TyreCondition",
"firstItem": [
{
"title": "Front right tyre",
"value": "50%",
"subValue": "30,000 km Approx"
}
],
"secItem": [
{
"title": "title",
"value": "Front right tyre tread - 50%"
},
{
"title": "title",
"value": "Front right tyre tread - 50%"
}
]}
Any idea how i can get the firstItem and secItem array in Items array?
You get no items key in your JSON, because you override the items field in your Java class with #SerializedName.
You need something like this:
String title;
String cls;
List<Item> items;
static class Item {
List<FirstItem> firstItem;
List<SecItem> secItem;
}
static class FirstItem {
String title;
String value;
String subValue;
}
static class SecItem {
String title;
String value;
}

Unable Parse a JSON using Jackson

I have a mongo database call in my code. The response from the database is mapped using codehaus jackson.
Json:
[
{
"_id": "555",
"rates": 1,
"reviews": [
{
"author_name": "Instructor 9999",
"_authKey": "demo\\556",
"text": "asdfa",
"date": 551,
"_id": "5454-4920",
"title": "asdf",
"comments": []
}
],
"votedUsers": [
{
"mng\\39999": 4
}
],
"rating": 4
},
{
"_id": "45589",
"rates": 1,
"reviews": [
{
"author_name": "feef",
"_authKey": "ad\\ads",
"text": "Working perfect",
"date": 1498659163,
"_id": "asdas-319",
"title": "test",
"comments": []
}
],
"votedUsers": [
{
"abc\\bis#cdf.com": 4
}
],
"rating": 4
}
]
I have created the below DTO Stucture:
#JsonIgnoreProperties(ignoreUnknown = true)
public class MaterialReviewsDTO implements Serializable {
private static final long serialVersionUID = 1L;
private String _id;
private int rates;
private List<ReviewsDTO> reviews;
private List<VotedUsersDTO> votedUsers;
//List<TypeReference<HashMap<String, String>>> votedUsers;
private int rating;.
//Getter Setter
}
#JsonIgnoreProperties(ignoreUnknown = true)
public class VotedUsersDTO implements Serializable {
private static final long serialVersionUID = 1L;
private Map<String, String> votedUser;
//Getter Setter
}
Below is the code where I am firing the query:
List<MaterialReviewsDTO> materialReviewsDTOs = DBConnectionRealmByDBName
.find(query,
MaterialReviewsDTO.class,
CollectionNameConstant.REVIEWS_COLLECTION);
Problem is all the JSON is getting mapped in DTO except the below part:
"votedUsers" : [
{
"abc\\bis#cdf.com" : 4
}
]
VotedUserDTO is null in response. VotedUsers is a list of object containg data in key-value pair.
I am not mentioning ReviewsDTO as this is getting mapped perfectly. How can I map votedUsers part?
Note: I am using Spring for development.
Some of the observations from your JSON
1. Json should be designed with Fixed key and variable values in mind.
2. Since in above case both Key and values are variable, we can use Map
So final solution is
change from private List<VotedUsersDTO> votedUsers; to private List<Map<String, Integer>> votedUsers
private List<Map<String, String>> votedUsers;
Do not use the explicit votedUser DTO.
The votedUsers is expected to be a List of VotedUsersDTOs.
If you look at your VotedUsersDTO in the JSON:
{
"abc\\bis#cdf.com" : 4
}
This would imply there is a field abc\\bis#cdf.com where you want the value to be 4.
This doesn't comply with id or votedUser Map in the DTO definition.

serialize json to pojo class

I have a JSON response coming as shown below. I am trying to make a POJO for this so that I can serialize this JSON into my POJO.
{
"holder": [
{
"ids": [
{
"data": "abcdef1234",
"time": 1452720139465,
"days": 16813
},
{
"data": "abcdef12345678",
"time": 1452720139465,
"days": 16813
},
{
"data": "abcdef12345678901234",
"time": 1452720139465,
"days": 16813
}
],
"type": "HELLO"
}
]
}
And this is my POJO I was able to come up with but it doesn't look right.
public class TestResponse {
private List<Ids> holder;
private String type;
// getters and setters
public static class Ids {
private String data;
private long time;
private long days;
// getters and setters
}
}
My json is not getting serialized to my above POJO
go to this link www.jsonschema2pojo.org and past yout json and extract jar files and import in your project and do some changes link this.
$class TestResponse {
to
class TestResponse implement serializable{

GSON deserialization of object arrays

I have a class with the following attributes
public class JenkinsServer
{
private String url;
private String mode;
private String nodeName;
private String nodeDescription;
private String description;
private boolean useSecurity;
private boolean quietingDown;
private JenkinsServerView primaryView;
private List< JenkinsJob > jobs;
private List< JenkinsServerView > views;
}
Now I want GSON to deserialize/map a json document to it. It works well, except for my lists - they are empty. The json document looks as follows (snippet):
"jobs": [
{
"name": "AnotherJob",
"url": "https://build.example.com/jenkins/job/AnotherJob/",
"color": "disabled"
},
{
"name": "AnotherJob2",
"url": "https://build.example.com/jenkins/job/Build%20CI%20Build/",
"color": "blue"
},
"views": [
{
"name": "-All Views",
"url": "https://build.example.com/jenkins/view/-All%Views/"
},
{
"name": "Alle",
"url": "https://build.example.com/jenkins/"
},
The mapping works, even for the single instance of
JenkinsServerView primaryView
but not for the Lists. I'm starting the mapping this way:
Gson gson = gsonBuilder.create();
JenkinsServer server = gson.fromJson( reader, JenkinsServer.class );
looks your json data that you are trying to parse is invalid.
In your json jobs and views are arrays and both of them doesn't have the closing brace at the end.
The valid json will be as follows: (Observe the closing braces at the end of the array)
{
"jobs": [
{
"name": "AnotherJob",
"url": "https://build.example.com/jenkins/job/AnotherJob/",
"color": "disabled"
},
{
"name": "AnotherJob2",
"url": "https://build.example.com/jenkins/job/Build%20CI%20Build/",
"color": "blue"
}
],
"views": [
{
"name": "-All Views",
"url": "https://build.example.com/jenkins/view/-All%Views/"
},
{
"name": "Alle",
"url": "https://build.example.com/jenkins/"
}
]
}

Categories