Json map to java object from inner - nested json property - java

Suppose I have JSON as follow.
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "users",
"_type": "students",
"_id": "AWAEqh945A0BWjveqnd0",
"_score": 1,
"_source": {
"college": {
"sport": {
"name": "cricket",
"category": "batsman"
}
}
}
}
]
}
}
I want to map data to College object which start from _source field.
Is there way to say to Jackson or Gson to from where mapping should start ?
in this example from _source
The Response we get from ES server.
ES server hosted on AWS.
So we suppose to communicate through ES Java API RestClient.
Is it ok Query through ES Java API QueryBuilder.
What is Recommended. ?

I used below mention way.
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(resultJson);
String sourceString = jsonNode.at("/hits/hits/0/_source").toString();
College college = objectMapper.readValue(sourceString, College.class);

You can do the following using Gson:
JSONObject object = new JSONObject(s); // s is you String Json
JSONObject hits1 = object.getJSONObject("hits");
JSONArray hits = hits1.getJSONArray("hits");
for (Object jsonObj : hits) {
JSONObject json = (JSONObject) jsonObj;
JSONObject source = json.getJSONObject("_source");
College college = new Gson().fromJson(source.getJSONObject("college").toString(), College.class);
}
You also need these two Pojos:
public class College {
private Sport sport;
public College() {
}
public Sport getSport() {
return sport;
}
public void setSport(Sport sport) {
this.sport = sport;
}
}
public class Sport {
private String name;
private String category;
public Sport() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
}

Related

Add a list of customers to an object in Spring

I have this object that I'm retrieving from antoher microservice.
#Service
public class WebClientService {
public Mono<CuCoPerson> getCuCoPerson(Integer cucoId, String GS_AUTH_TOKEN) {
WebClient webClient = WebClient.create();
return webClient.get()
.uri(GET_RELATION_BY_ID + cucoId)
.header("Accept", "application/json")
.header("Authorization", GS_AUTH_TOKEN)
.retrieve()
.bodyToMono(CuCoPerson.class)
.map(cuCoPerson -> {
List<CustomerRelation> matches = cuCoPerson.getRelatedCustomers()
.stream()
.filter(relation -> relation.getSystemId().equals(400) || relation.getSystemId().equals(300) || relation.getSystemId().equals(410))
.filter(relation -> relation.getCustomerId().contains("F"))
.collect(Collectors.toList());
cuCoPerson.setRelatedCustomers(matches);
return cuCoPerson;
});
}
The controller is as follows:
#GetMapping("/getCucoId/{cucoId}")
public Mono<CuCoPerson> getCucoRelationById(#PathVariable Integer cucoId, #RequestHeader(value="Authorization") String GS_AUTH_TOKEN) {
return webClientService.getCuCoPerson(cucoId, GS_AUTH_TOKEN);
}
It returns a list of related customers like this:
{
"id": 1,
"relatedCustomers": [
{
"customerId": "xxx",
"systemId": 999
}
]
}
And now I need to add this list of customers to my PeopleDTO class which is as follows:
public class PeopleDTO {
private String processType;
private String operation;
private String entity;
private String entityType;
private Long id;
private Document document;
#Getter
#Setter
class Customer {
private String systemId;
private String customerId;
}
private List<Customer> customers;
}
UPDATE:
Here I'm hardcoding my PeopleDTO just as an example:
public PeopleDTO createPeople(Long id) {
PeopleDTO people = new PeopleDTO();
people.setProcessType("ONLINE");
people.setOperation("UPDATE");
people.setEntity("DOCUMENT");
people.setEntityType("DOCUMENT");
people.setIdCuco(id);
people.setDocument(new Document());
people.setCustomers(......);
}
So the result should be something like this:
{
"type": "ONLINE",
"operation": "UPDATE",
"id": 1,
"entity": "DOCUMENT",
"entityType": "NIE",
"documents": {
"id": 1,
"additionals": {
"issuing_authority": "Spain",
"country_doc": "ES",
"place_of_birth": "",
"valid_from": "1995-08-09",
"valid_to": "0001-01-01"
},
"code": "X12345",
"typeDocument": "NIE"
},
"id": 1,
"relatedCustomers": [
{
"customerId": "xxx",
"systemId": 999
}
]
}
The controller that supposed to retrieve this info is:
#GetMapping("getId/{cucoId}")
public PeopleDTO getFullPeople(#PathVariable Long id) {
return webClientService.createPeople(id);
}
How should I set the customers in here?

Getting rid of extra placeholders when serializing/deserializing a map of json using Gson

I am trying to serialize/deserialize a nested Map of Json string using Gson library.
The issue is, it is creating an extra place holder key("empMap")in the final Json .
Is there a way to get rid of this extra place holder key? I am sharing the pojo classes that I am using below.
Json that I am getting:
{
"empMap": {
"1": {
"id": 1,
"name": "Alex",
"dob": {
"year": 1990,
"month": 1,
"day": 1
}
}
}
}
Json that I want:
{
"1": {
"id": 1,
"name": "Alex",
"dob": {
"year": 1990,
"month": 1,
"day": 1
}
}
The pojos that I am using:
Employee.java
public class Employee {
private Long id;
private String name;
private LocalDate dob;
public Employee(Long id, String name, LocalDate dob) {
super();
this.id = id;
this.name = name;
this.dob = dob;
}
}
MappedJson.java (Final Json)
public class MappedJson {
private Map<String, Employee> empMap;
public MappedJson(Map<String, Employee > empMap) {
super();
empMap = empMap;
}
public Map<String, Employee > getEmpMap() {
return empMap;
}
public void setPageMap(Map<String, Employee > empMap) {
this.empMap = empMap;
}
}

Jackson : deserializing a map

I'm using Jackson to deserialize a json file from a HTTP Response:
ObjectMapper mapper = new ObjectMapper();
InputStream responseBody = response.getBody().in();
RawDataBody rawdataBody = mapper.readValue(responseBody, RawDataBody.class);
I also tries this but it doesn't work :
RawDataBody rawdataBody = mapper.readValue(responseBody.toString(), RawDataBody.class);
This is the error that I'm getting :
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of com.ubiant.hemis.accounts.TineaSeas.Model.RawDataBody out of START_ARRAY token at [Source: java.io.ByteArrayInputStream#19da0cd; line: 1, column: 1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:575)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:569)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromArray(BeanDeserializerBase.java:1120)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:148)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:123)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2888)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2080)
at com.ubiant.hemis.accounts.TineaSeas.Test.main(Test.java:46)
The JSON File :`
[
{
"tag":"Volume_D1_10m",
"value":0.0,
"quality":1,
"site":1,
"supplier":2,
"zone":0,
"timestamp":1470297561000
},
{
"tag":"Tmoy_T4_10m",
"value":19.2,
"quality":1,
"site":1,
"supplier":2,
"zone":0,
"timestamp":1470297561000
}
]
This is my model :`
public class RawDataBody implements Serializable {
#JsonProperty("rawDatas")
#JsonDeserialize
private ArrayList<RawData> rawDatas = new ArrayList<RawData>();
public RawDataBody(){
}
public RawDataBody rawDatas(ArrayList<RawData> rawDatas) {
this.rawDatas = rawDatas;
return this;
}
#JsonProperty("rawDatas")
public ArrayList<RawData> getRawDatas() {
return rawDatas;
}
#JsonProperty("rawDatas")
public void setRawDatas(ArrayList<RawData> rawDatas) {
this.rawDatas = rawDatas;
}
public class RawData implements Serializable {
private String tag = null;
private Double value = null;
private Integer quality = null;
private Integer site = null;
private Integer supplier = null;
private Integer zone = null;
private BigDecimal timestamp = null;
#JsonProperty("tag")
public String getTag() {
return tag;
}
#JsonProperty("tag")
public void setTag(String tag) {
this.tag = tag;
}
#JsonProperty("value")
public Double getValue() {
return value;
}
#JsonProperty("value")
public void setValue(Double value) {
this.value = value;
}
#JsonProperty("quality")
public Integer getQuality() {
return quality;
}
#JsonProperty("quality")
public void setQuality(Integer quality) {
this.quality = quality;
}
#JsonProperty("site")
public Integer getSite() {
return site;
}
#JsonProperty("site")
public void setSite(Integer site) {
this.site = site;
}
#JsonProperty("supplier")
public Integer getSupplier() {
return supplier;
}
#JsonProperty("supplier")
public void setSupplier(Integer supplier) {
this.supplier = supplier;
}
#JsonProperty("zone")
public Integer getZone() {
return zone;
}
#JsonProperty("zone")
public void setZone(Integer zone) {
this.zone = zone;
}
#JsonProperty("timestamp")
public BigDecimal getTimestamp() {
return timestamp;
}
#JsonProperty("timestamp")
public void setTimestamp(BigDecimal timestamp) {
this.timestamp = timestamp;
}
}
Can anyone help me with this ?
There are two possible approaches:
Approach 1
Considering the existing JSON:
[
{
"tag": "Volume_D1_10m",
"value": 0,
"quality": 1,
"site": 1,
"supplier": 2,
"zone": 0,
"timestamp": 1470297561000
},
{
"tag": "Tmoy_T4_10m",
"value": 19.2,
"quality": 1,
"site": 1,
"supplier": 2,
"zone": 0,
"timestamp": 1470297561000
}
]
It can be serialized into a RawData array, as following:
String json = "[{\"tag\":\"Volume_D1_10m\",\"value\":0.0,\"quality\":1,\"site\":1,\"supplier\":2,\"zone\":0,\"timestamp\":1470297561000},{\"tag\":\"Tmoy_T4_10m\",\"value\":19.2,\"quality\":1,\"site\":1,\"supplier\":2,\"zone\":0,\"timestamp\":1470297561000}]";
ObjectMapper mapper = new ObjectMapper();
RawData[] rawDataArray = mapper.readValue(json, RawData[].class);
Approach 2
Modify your JSON to be like:
{
"rawDatas": [
{
"tag": "Volume_D1_10m",
"value": 0,
"quality": 1,
"site": 1,
"supplier": 2,
"zone": 0,
"timestamp": 1470297561000
},
{
"tag": "Tmoy_T4_10m",
"value": 19.2,
"quality": 1,
"site": 1,
"supplier": 2,
"zone": 0,
"timestamp": 1470297561000
}
]
}
And then serialize it into a RawDataBody:
String json = "{\"rawDatas\":[{\"tag\":\"Volume_D1_10m\",\"value\":0.0,\"quality\":1,\"site\":1,\"supplier\":2,\"zone\":0,\"timestamp\":1470297561000},{\"tag\":\"Tmoy_T4_10m\",\"value\":19.2,\"quality\":1,\"site\":1,\"supplier\":2,\"zone\":0,\"timestamp\":1470297561000}]}";
ObjectMapper mapper = new ObjectMapper();
RawDataBody rawDataBody = mapper.readValue(json, RawDataBody.class);

How to convert JSON objects to POJO from Gson

I am trying to convert JSON objects to POJO's with GSON.
JSON String
[
{
"automation_project": {
"user_id": null,
"name": "Untitled Project",
"updated_at": "2015-06-16T19:39:42Z",
"group_id": 764496,
"created_at": "2014-11-23T01:01:59Z",
"id": 16214
}
},
{
"automation_project": {
"user_id": null,
"name": "newintropage",
"updated_at": "2015-06-16T21:20:47Z",
"group_id": 764496,
"created_at": "2015-06-16T20:39:04Z",
"id": 29501
}
}
]
The AutomationProjectsList class used with GSON
public class AutomationProjectsList {
private List<AutomationProject> automationProject = new ArrayList<AutomationProject>();
public List<AutomationProject> getAutomationProject() {
return automationProject;
}
public void setAutomationProject(List<AutomationProject> automationProject) {
this.automationProject = automationProject;
}
#Override
public String toString() {
return "AutomationProjectsList [automationProject=" + automationProject
+ "]";
}}
Automation Project POJO
public class AutomationProject {
private Object userId;
private Integer groupId;
private Integer id;
private String name;
private String updatedAt;
private String createdAt;
public Object getUserId() {
return userId;
}
public void setUserId(Object userId) {
this.userId = userId;
}
public Integer getGroupId() {
return groupId;
}
public void setGroupId(Integer groupId) {
this.groupId = groupId;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(String updatedAt) {
this.updatedAt = updatedAt;
}
public String getCreatedAt() {
return createdAt;
}
public void setCreatedAt(String createdAt) {
this.createdAt = createdAt;
}}
The code I'm using
JSONArray jsonArray = new JSONArray(response.getEntity(String.class));
for(int i = 0; i < jsonArray.length(); i++){
if(jsonArray.get(i) instanceof JSONObject){
JSONObject jsnObj = (JSONObject)jsonArray.get(i);
AutomationProjectsList obj = new Gson().fromJson(jsnObj.toString(), AutomationProjectsList.class);
System.out.println(obj.getAutomationProject().get(0).getId());
}
}
But it gives an exception :
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:653)
at java.util.ArrayList.get(ArrayList.java:429)
at br.usp.icmc.teste.ConnectionRestClient.getBrowserStackProjects(ConnectionRestClient.java:74)
at br.usp.icmc.teste.TestePrincipal.main(TestePrincipal.java:9)
Why am I receiving an IndexOutOfBoundsException exception? Where am I wrong?
Your class or your JSON are incorrect. I'd suggest your JSON is.
A JSON matching your POJO class would be:
{
"automationProjects":[
{
"user_id": null,
"name": "Untitled Project",
"updated_at": "2015-06-16T19:39:42Z",
"group_id": 764496,
"created_at": "2014-11-23T01:01:59Z",
"id": 16214
},
{
"user_id": null,
"name": "newintropage",
"updated_at": "2015-06-16T21:20:47Z",
"group_id": 764496,
"created_at": "2015-06-16T20:39:04Z",
"id": 29501
}
]
}
Notice I used the name automationProjects for the list as it makes more sense, so your class would be:
public class AutomationProjectsList {
private List<AutomationProject> automationProjects = new ArrayList<AutomationProject>();
public List<AutomationProject> getAutomationProjects() {
return automationProjects;
}
public void setAutomationProjects(List<AutomationProject> automationProjects) {
this.automationProjects = automationProjects;
}
#Override
public String toString() {
return "AutomationProjectsList [automationProject=" + automationProject
+ "]";
}
}
And finally to convert JSON to AutomationProjectsList object:
AutomationProjectsList projectsList = new Gson().fromJson(jsonArray.toString(), AutomationProjectsList.class);
Then if you want to log each project:
for(AutomationProject project : projectsList.automationProjects){
System.out.println(porject.getId());
}
In conclusion, your code seems to have the fallowing issues:
Do you have a list of lists or just a single list of projects? If the list is just one, why do you iterate jsonArray like its sub-objects are lists themselves?
If you model your class correctly on the JSON then you don't need to iterate the JSON to obtain your objects
The JSON you posted is quite weird and uneasy to use with Gson, is it a requirement or can you edit it as you please?
Hope this helps
EDIT
Since you stated you cannot change the JSON you get, then it gets a little more complex, but everything is up to modelling the classes on the JSON format. So let's start form this JSON:
[
{
"automation_project": {
"user_id": null,
"name": "Untitled Project",
"updated_at": "2015-06-16T19:39:42Z",
"group_id": 764496,
"created_at": "2014-11-23T01:01:59Z",
"id": 16214
}
},
{
"automation_project": {
"user_id": null,
"name": "newintropage",
"updated_at": "2015-06-16T21:20:47Z",
"group_id": 764496,
"created_at": "2015-06-16T20:39:04Z",
"id": 29501
}
}
]
Now, this is quite nasty, but let's see what we have here: we have an unnamed array of objects with a single attribute "automationProject" which is our actual AutomationProject Object. So in terms of structure, it is a list of objects which wrap an actual AutomationProject.
Thus you'll need to get rid of your AutomationProjectList and change it with the more meaningful AutomationProjectWrapper looking as fallows:
public class AutomationProjectsWrapper {
private AutomationProject automation_project = new AutomationProject();
public AutomationProject getAutomationProject() {
return automation_project;
}
public void setAutomationProject(AutomationProject automationProject) {
this.automation_project = automationProject;
}
#Override
public String toString() {
return "AutomationProjectsList [automationProject=" + automation_project
+ "]";
}
}
See this class is equivalent to the JSON Object:
{
"automation_project": {
"user_id": null,
"name": "Untitled Project",
"updated_at": "2015-06-16T19:39:42Z",
"group_id": 764496,
"created_at": "2014-11-23T01:01:59Z",
"id": 16214
}
}
Finally you'll have an array of such wrapper objects as your jsonArray so you can write:
AutomationProjectWrapper[] projectsList = new Gson().fromJson(jsonArray.toString(), AutomationProjectWrapper[].class);
Then to log your objects:
for(AutomationProjectWrapper wrapper : projectsList){
System.out.println(wrapper.getAutomationProject().getId());
}
EDIT 2
Sorry for the mistake, in AutomationProjectWrapper class the AutomationProject field should be named automation_project.
Fixed in code above.
According to your JSON String the value you are trying to access is :
jsonString[i].automation_project.user_id
In your code you have: obj.getAutomationProject().get(0).getId()
I think is should be: obj[i].getAutomationProject().getId()

GSON parsing of nested array

Im having difficulties understanding if GSON can handle this kind of json by default or do I need to implement deserializers for every sub element.
json input
{
"services":[
{
"id": 2,
"name": "Buy"
},
{
"id": 3,
"name": "Sell"
}
]
"status": {
"code": 0,
"message": ""
}
}
The best case result on my part is to have the following class contain all the data
java [ POJO ]
public class Services {
public List<ServiceItem> services;
public Status status;
public class ServiceItem {
public int id;
public String name;
}
public class Status {
public int code;
public String message;
}
}
Is it possible to let GSON the class and the json and just let it work? Or do I need to create deserializers for each sub class?
Correct your json input as follow (you forgot a comma before status field)
{
"services":[
{
"id": 2,
"name": "Buy"
},
{
"id": 3,
"name": "Sell"
}
],
"status": {
"code": 0,
"message": ""
}
}
Then let's consider your classes as follow
public class Services {
public List<ServiceItem> services;
public Status status;
// getters and setters
#Override
public String toString() {
return "["+services.toString()+status.toString()+"]";
}
public class ServiceItem {
public int id;
public String name;
// getters and setters
#Override
public String toString() {
return "("+id+","+name+")";
}
}
public class Status {
public int code;
public String message;
// getters and setters
#Override
public String toString() {
return ",("+code+","+message+")";
}
}
}
If the input is a file jsonInput.json then
Gson gson = new Gson();
Services data = gson.fromJson(new BufferedReader(new FileReader(
"jsonInput.json")), new TypeToken<Services>() {
}.getType());
System.out.println(data);
If the input is a json String jsonInput then
Gson gson = new Gson();
Services data = gson.fromJson(jsonInput, Services.class);
System.out.println(data);
Output:
[[(2,Buy), (3,Sell)],(0,)]

Categories