serialize json to pojo class - java

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{

Related

Deserializing complex json with matching objects by id (Jackson)

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?

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.

JSON parse error: Can not deserialize instance - Java

I'm creating a REST service that receives a JSON input like this:
[
{
"person": {
"name": "string",
"surname": "string",
"address": "string",
"age": "data",
"info": {
"number": "string"
}
}
},
{
"person": {
"name": "string",
"surname": "string",
"address": "string",
"age": "data",
"info": {
"number": "string"
}
}
}
]
My items are(
I omitted getters and setters):
public class Request {
private List<Person> person;
}
public class Person{
private String name;
private String surname;
private String address;
private XMLGregorianCalendar age;
private Info info;
}
public class Info {
private String number;
}
how come i get the following error?
{
"timestamp": 1611142052198,
"status": 400,
"error": "Bad Request",
"exception": "org.springframework.http.converter.HttpMessageNotReadableException",
"message": "JSON parse error: Can not deserialize instance of com.myproject.model.Request out of
START_ARRAY
}
i need the json structure to be exactly that.
You are trying to de-serialize your input array to a Request object, which is not a collection, and thus you get that error.
To solve it you should de-serialize your input array to a List<Person> object and then set that object to your Request object:
Request request = ... // get the request
List<Person> person = ... // deserialize the input array
request.setPerson(person);
If you are using Jackson, you can also define a constructor for your Request class which takes a List<Person> argument and then mark that constructor with the #JsonCreator annotation (see here for an example):
public class Request {
private List<Person> person;
#JsonCreator
public Request(#JsonProperty("person") List<Person> person) {
this.person = person;
}
}
And then you can create your Request object directly from your input array.
By using the #JsonCreator annotation you keep your Request class immutable, because you don't need to define a setPerson(List<Person>) method for it.

Parsing specific JSON with Gson

I'm currently trying to parse a JSON response with the following structure using Gson:
{
data {
"1": {
"name": "John Doe"
},
"2": {
"name": "John Doe"
},
...
}
My response class:
class Response {
Map<String, ModelObj> data;
}
and model class:
class ModelObj {
String name;
}
But what I can't figure out is how to simply map everything to a single List where the id is placed within the ModelObj without having them separate as key/value pairs in a Map. So ideally my response class would be:
class Response {
List<ModelObj> data;
}
and model class:
class ModelObj {
String id;
String name;
}
How would this be accomplished?
[
{
"id": 1,
"name": "John Doe"
},
{
"id": 2,
"name": "John Doe"
}
]
If your response is of above form then only you will get the list of model object and you will get Array of ModelObj
then use below code to convert to List
public <T> List<T> getObjectToList(String json, Class<T[]> ObjectArrayClass) {
return Arrays.asList(gson.fromJson(json, ObjectArrayClass));
}
List< ModelObj > arrayList = getObjectToList(jsonResponseString, ModelObj[].class);

JSON generic collection deserialization

I've such DTO classes written in Java:
public class AnswersDto {
private String uuid;
private Set<AnswerDto> answers;
}
public class AnswerDto<T> {
private String uuid;
private AnswerType type;
private T value;
}
class LocationAnswerDto extends AnswerDto<Location> {
}
class JobTitleAnswerDto extends AnswerDto<JobTitle> {
}
public enum AnswerType {
LOCATION,
JOB_TITLE,
}
class Location {
String text;
String placeId;
}
class JobTitle {
String id;
String name;
}
In my project there is Jackson library used for serialization and deserialization of JSONs.
How to configure AnswersDto (use special annotations) or AnswerDto (annotation as well) classes to be able to properly deserialize request with AnswersDto in its body, e.g.:
{
"uuid": "e82544ac-1cc7-4dbb-bd1d-bdbfe33dee73",
"answers": [
{
"uuid": "e82544ac-1cc7-4dbb-bd1d-bdbfe33dee73",
"type": "LOCATION",
"value": {
"text": "Dublin",
"placeId": "121"
}
},
{
"uuid": "e82544ac-1cc7-4dbb-bd1d-bdbfe33dee73",
"type": "JOB_TITLE",
"value": {
"id": "1",
"name": "Developer"
}
}
]
}
Unfortunately Jackson by default maps value of AnswerDto object to LinkedHashMap instead of object of proper (Location or JobTitle) class type.
Should I write custom JsonDeserializer<AnswerDto> or configuration by use of #JsonTypeInfo and #JsonSubTypes could be enough?
To properly deserialize request with just one AnswerDto in form of
{
"uuid": "e82544ac-1cc7-4dbb-bd1d-bdbfe33dee73",
"type": "LOCATION",
"value": {
"text": "Dublin",
"placeId": "121"
}
}
I'm using:
AnswerDto<Location> answerDto = objectMapper.readValue(jsonRequest, new TypeReference<AnswerDto<Location>>() {
});
without any other custom configuration.
I've resolved issue by using Jackson's custom annotations #JsonTypeInfo and #JsonSubTypes:
public class AnswerDto<T> {
private String uuid;
private AnswerType type;
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(value = Location.class, name = AnswerType.Types.LOCATION),
#JsonSubTypes.Type(value = JobTitle.class, name = AnswerType.Types.JOB_TITLE)
})
private T value;
}
My suggestion is to make a separate interface for possible answer values and use #JsonTypeInfo on it. You can also drop type field from AnswerDto, AnswerType enum, and additional *AnswerDto classes becuse jackson will add type info for you. Like this
public class AnswerDto<T extends AnswerValue> {
private String uuid;
private T value;
}
#JsonTypeInfo(use = Id.CLASS, include = As.PROPERTY)
interface AnswerValue {}
class Location implements AnswerValue { /*..*/ }
class JobTitle implements AnswerValue { /*..*/ }
Resulting json will looks like this
{
"uuid": "e82544ac-1cc7-4dbb-bd1d-bdbfe33dee73",
"answers": [
{
"uuid": "e82544ac-1cc7-4dbb-bd1d-bdbfe33dee73",
"value": {
"#class": "com.demo.Location",
"text": "Dublin",
"placeId": "121"
}
},
{
"uuid": "e82544ac-1cc7-4dbb-bd1d-bdbfe33dee73",
"value": {
"#class": "com.demo.JobTitle",
"id": "1",
"name": "Developer"
}
}
]
}
Which will be parsed using
AnswersDto answersDto = objectMapper.readValue(json, AnswersDto.class);
But this solution applies only in cases when you are a producer of json data and you do not have to think about backward compatibility.
In other cases you'll have to make custom desetializer for AnswersDto class.

Categories