Parse a json list into list of object Java - java

I have a response as follows
[
{
"segmentId": "Source_2021-09-01_2021-10-01",
"columns": [
"merchantRefNum",
"customerId",
"firstName",
],
"events": [
{
"merchantRefNum": "67456456",
"customerId": rfgvkhbj,
"firstName": "peter",
},
{
"merchantRefNum": "654584856",
"customerId": null,
"firstName": "peter"
}
]
}
]
I want to map this json to a POJO object and have created this class
public class MyClass {
private String segmentId;
private List<String> columns;
private List<KeyValuePair> events;
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#JsonIgnoreProperties(ignoreUnknown = true)
public static class KeyValuePair {
Map<String, String> event;
}
}
I am currently using this way to read this
List<MyClass> responses = new ObjectMapper().readValue(jsonString,new TypeReference<List<MyClass>>(){});
The size of events is 2 but each event is coming as null instead of a map.
Can Someone please help me ?

To achieve your goal you have to adjust your JSON as follows:
[
{
"segmentId":"Source_2021-09-01_2021-10-01",
"columns":[
"merchantRefNum",
"customerId",
"firstName"
],
"events":[
{
"event":{
"merchantRefNum":"67456456",
"customerId":"rfgvkhbj",
"firstName":"peter"
}
},
{
"event":{
"merchantRefNum":"654584856",
"customerId":null,
"firstName":"peter"
}
}
]
}
]
Notice the event fields that have been added.
Or, change your DTO, like this:
class MyClass {
private String segmentId;
private List<String> columns;
private List<Map<String, String>> events;
}

Related

Parsing JSON to Java having multiple data types for the same field

I have been given the below JSON:
{
"dataBlock": [
{
"headingName": {
"name": "Operational Information",
"position": "1",
"attributes": [
{
"name": "Brand",
"position": "1",
"value": [
"A",
"B"
]
},
{
"name": "Data Model Id",
"position": "2",
"value": "000001"
}
]
}
},
{
"headingName": {
"name": "CRA",
"position": "6",
"attributes": [
{
"name": "Company",
"position": "1",
"value": "private_limited_company"
},
{
"name": "Address",
"position": "3",
"value": {
"line1": "AAA",
"line2": "BBB",
"line3": "CCC",
"line4": "DDD",
"postalCode": "AB XYZ",
"countryCode": "GBR"
}
}
]
}
}
]
}
I need to convert it to Java. One thing you may notice is that "value" field of every "attribute" may be of type String. Object, Array or even a nested "attribute". How do I handle this case?
This is what I attempted:
MyService.java:
#Slf4j
#Service
public class MyService {
public MyResponse getCustomerDetails() {
ObjectMapper mapper = new ObjectMapper();
try {
File file = getFile("classpath:data.json");
if (file.exists()) {
return mapper.readValue(file, MyResponse.class);
}
} catch (IOException e) {
log.error(e.getMessage());
}
return null;
}
}
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class MyResponse {
private List<DataBlock> dataBlocks;
}
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class DataBlock {
#JsonProperty("headingName")
private ComplianceSection section;
}
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class ComplianceSection {
private String name;
private String position;
private List<ComplianceAttribute> attributes;
}
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class ComplianceAttribute {
private String name;
private String position;
// private ComplianceAttributeValue value; ???
}
Not sure how can I map the value as it's structurally different for each attribute node.
try a custom deserializer
public class ComplianceAttributeValueDeserializer extends StdDeserializer<ComplianceAttributeValue> {
public ComplianceAttributeValueDeserializer() {
this(null);
}
public ComplianceAttributeValueDeserializer(Class<?> vc) {
super(vc);
}
#Override
public ComplianceAttributeValue deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonNode node = jp.getCodec().readTree(jp);
// detect value type and create object, e.g. for string type
return new ComplianceAttributeStringValue(...);
}
}
also use ComplianceAttributeValue as base class and derived classes for all known types like ComplianceAttributeStringValue or use generics
#JsonDeserialize(using = ComplianceAttributeValueDeserializer.class)
public class ComplianceAttributeValue {
...
}
https://www.baeldung.com/jackson-deserialization

Mapping a List inside a List using SerializedName

I have an object class, called Device, inside that there is a List of objects, which also contains a List of objects.
Model looks like this:
public class Device {
#SerializedName("tests")
public List<Test> tests;
public static class Test {
#SerializedName("id")
public String id;
#SerializedName("testInfo")
private List<TestInfo> testInfo = new ArrayList<TestInfo>();
}
public static class TestInfo {
#SerializedName("id")
private String id;
}
}
Now when it is mapping the request, it maps the first List, meaning when printing the result I get this:
Test{id='123', testInfo = []}
Test{id='124', testInfo = []}
The testInfo is always an empty list, even though the data is there. I tried it with and without the new ArrayList. Is the problem here that SerializedName does not know how to map a list inside a list or am I doing somthing wrong?
EDIT
Data that is being mapped:
"tests": [
{
"id": "123",
"testInfo": [
{
"id": "321",
},
{
"id": "322",
}
]
},
{
"id": "124",
"testInfo": [
{
"id": "421",
},
{
"id": "422",
}
]
},
]

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.

Mapping JSON with multiple entries to an array

I have a JSON file with multiple entries that have same attribute names, but different attribute values, such as:
{
"name" : { "first" : "A", "last" : "B" },
"gender" : "MALE",
"married" : false,
"noOfChildren" : 2
},
{
"name" : { "first" : "C", "last" : "D" },
"gender" : "FEMALE",
"married" : true,
"noOfChildren" : 1
}
The class that it should be mapped is:
public class Human {
private Name name;
private String gender;
private int age;
<getter, setters etc>
}
EDIT:
Service code is :
List<Human> humans = null;
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
try {
humans= objectMapper.readValue(json, new TypeReference<List<Human>>(){});
} catch (IOException e) {
e.printStackTrace();
}
JSON is parsed from HTTP entity and with correct format and now I added the annotation ass suggested in the answers.
As you can see, they have some attributes in common, but differ in others, and I would like to map those common fields. Is it possible to map the JSON this way ? I have tried mapping JSON to a collection/list/array of JsonNodes, but I keep getting erros about deserialization, while mapping only one instance of JSON entry works just fine. Is there another way of doing this ?
Use
#JsonIgnoreProperties(ignoreUnknown = true)
public class Human {
private Name name;
private String gender;
// getters, settets, default constructor
}
Or if you are using Lombok then it will be
#Data
#NoArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class Human {
private Name name;
private String gender;
}
use
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
while deserializing json to POJO class.
The JSON you have provide in question will give following error, as it is not a valid one.
Can not deserialize instance of java.util.ArrayList out of START_OBJECT token
Valid Json would be like this:
[
{
"name": {
"first": "A",
"last": "B"
},
"gender": "MALE",
"married": false,
"noOfChildren": 2
},
{
"name": {
"first": "C",
"last": "D"
},
"gender": "FEMALE",
"married": true,
"noOfChildren": 1
}
]

Jackson Serialize without field name

This is slight extension of my previous question. So based on dambros' answer, the json now looks like:
"Foo": {
"title": {
"type": "title",
"value": "...",
"variable": "..."
},
"message": {
"type": "message",
"value": "...",
"variable": "..."
}
}
But what I really want is:
"Foo": [
{
{
"type": "title",
"value": "...",
"variable": "..."
},
{
"type": "message",
"value": "...",
"variable": "..."
}
}
]
Is there any way to write the Foo field as an array and also not display the variable names as fields (i.e remove "title" :).
That is not valid JSON, however this is:
{
"Foo": [
{
"type": "title",
"value": "...",
"variable": "..."
},
{
"type": "message",
"value": "...",
"variable": "..."
}
]
}
This is a JSON object with a single field named Foo that is an array of objects.
You should read the JSON spec.
Alternatively, if you have a List<Foo>, you can serialize the list directly, giving you a JSON array as the root, instead of a JSON object as the root:
[
{
"type": "title",
"value": "...",
"variable": "..."
},
{
"type": "message",
"value": "...",
"variable": "..."
}
]
It seems that what you're trying to accomplish is to represent your java object in a way that you can send the object type and fields. Under that assumption, I'd try to get away from manual serialization. Just create a DTO with the format that you need, that you can populate with the domain objects you have. This would be an example:
public class FooSerialization {
public static class Foo {
private String title;
private String message;
}
public static class Foo2 {
private String value;
private String variable;
}
public static class ClassDTO {
private String type;
private List<FieldDTO> fields;
}
public static class FieldDTO {
private String type;
private String value;
private String fieldName;
}
public static void main(String[] args) throws JsonProcessingException {
Foo2 foo2 = new Foo2();
foo2.setValue("valueMessage");
foo2.setVariable("variableMessage");
Foo foo = new Foo();
foo.setMessage("messageMessage");
foo.setTitle("titleMessage");
ObjectMapper mapper = new ObjectMapper();
List<ClassDTO> dtos = new ArrayList<ClassDTO>();
dtos.add(convert(foo));
dtos.add(convert(foo));
System.out.println(mapper.writeValueAsString(dtos));
}
private static ClassDTO convert(Object obj) {
ClassDTO dto = new ClassDTO();
dto.setType(obj.getClass().getSimpleName());
List<FieldDTO> fieldDTOs = new ArrayList<FieldDTO>();
dto.setFields(fieldDTOs);
for (Field field : obj.getClass().getDeclaredFields()) {
field.setAccessible(true);
FieldDTO fieldDto = new FieldDTO();
try {
fieldDto.setFieldName(field.getName());
fieldDto.setValue(field.get(obj).toString());
fieldDto.setType(field.getType().getSimpleName());
fieldDTOs.add(fieldDto);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return dto;
}
}
Getters and Setters are omitted for simplicity. This basically converts from Foo or Foo2 to certain ClassDTO, that contains type and a list of FieldDTOs that have the field details.
Output looks like this:
[
{
"type": "Foo",
"fields": [
{
"fieldName": "title",
"type": "String",
"value": "titleMessage"
},
{
"fieldName": "message",
"type": "String",
"value": "messageMessage"
}
]
},
{
"type": "Foo2",
"fields": [
{
"fieldName": "value",
"type": "String",
"value": "valueMessage"
},
{
"fieldName": "variable",
"type": "String",
"value": "variableMessage"
}
]
}
]
It looks to me that you can solve lots of problems if you can use something like this:
#JsonFormat(shape=JsonFormat.Shape.ARRAY)
public static class Foo {
#JsonProperty public Foo1 title;
#JsonProperty public Foo2 message;
}
#JsonTypeInfo(use= JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="type")
#JsonSubTypes({#JsonSubTypes.Type(value = Foo1.class, name = "title"),
#JsonSubTypes.Type(value = Foo2.class, name = "message")})
public static class FooParent{
#JsonProperty private String value;
#JsonProperty private String variable;
}
public static class Foo1 extends FooParent{}
public static class Foo2 extends FooParent{}
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
Foo foo = new Foo();
foo.title = new Foo1();
foo.message = new Foo2();
String serialized = mapper.writeValueAsString(foo);
System.out.println(serialized);
}
Result is:
[
{"type":"title","value":null,"variable":null},
{"type":"message","value":null,"variable":null}
]
Read following blog json in java
This post is a little bit old but still i want to answer you Question
Step 1: Create a pojo class of your data.
Step 2: now create a object using json.
Foo foo = null;
ObjectMapper mapper = new ObjectMapper();
try{
foo = mapper.readValue(newFile("/home/sumit/foo.json"),Foo.class);
} catch (JsonGenerationException e){
e.printStackTrace();
}
For further reference you can refer following link
Thanks

Categories