Dynamic Json Formation - java

I am reading one file through which I need to create a specific JSON structure to pass it on UI, but I am unable to write a code for JSON formation. So I created one Java class initialized my class, tried a lot but still now able to find a way, how to form it. Here is my main Java class where I am adding an element like this
public class DynamicListForming {
public static void main(String[] args) {
NodeInfo cab = new NodeInfo("saurabh", "South");
NodeInfo cab1 = new NodeInfo("South", "ZONE1");
NodeInfo cab2 = new NodeInfo("ZONE1", "Street-1");
NodeInfo cab3 = new NodeInfo("ZONE1", "Street-2");
NodeInfo cab4 = new NodeInfo("ZONE1", "Street-3");
NodeInfo cab5 = new NodeInfo("ZONE1", "Street-4");
List<NodeInfo> NodeInfos = new LinkedList<NodeInfo>();
NodeInfos.add(cab);
NodeInfos.add(cab1);
NodeInfos.add(cab2);
NodeInfos.add(cab3);
NodeInfos.add(cab4);
NodeInfos.add(cab5);
}
}
My NodeInfo class looks like this
public class NodeInfo {
private String nodeName;
private String parentName;
private List<NodeInfo> children;
public NodeInfo(String parentName, String nodeName) {
super();
this.parentName = parentName;
this.nodeName = nodeName;
}
public String getNodeName() {
return nodeName;
}
public void setNodeName(String nodeName) {
this.nodeName = nodeName;
}
public String getParentName() {
return parentName;
}
public void setParentName(String parentName) {
this.parentName = parentName;
}
public List<NodeInfo> getChildren() {
return children;
}
public void setChildren(List<NodeInfo> children) {
this.children = children;
}
}
I need to form JSON structure like below
"nodeInfo": {
"name": "saurabh",
"children": [
{
"name": "SOUTH",
"children": [
{
"name": "Zone-1",
"children": [
{
"name": "Street-1"
},
{
"name": "Street-2"
},
{
"name": "Street-3"
},
{
"name": "Street-4"
}
]
}
]
}
]
}
Any suggestion on how to form this type of JSON structure, I struggled a lot and unable to find a way to dynamically create a list and object to form this structure.

Related

Deserialising complex nested Json using Jackson

I am struggling to deserialise complex nested Json data into Java objects I think my class structure is wrong. Here is my Json data:
{
"resultsPerPage": 20,
"startIndex": 0,
"totalResults": 2,
"result": {
"dataType": "CPE",
"feedVersion": "1.0",
"cpeCount": 2,
"feedTimestamp": "2021-03-19T13:06",
"cpes": [
{
"deprecated": false,
"cpe23Uri": "cpe:2.3:o:microsoft:windows_10:1511:*:*:*:*:*:x64:*",
"lastModifiedDate": "2015-12-09T17:28Z",
"titles": [
{
"title": "Microsoft Windows 10 1511 64-bit",
"lang": "en_US"
}
],
"refs": [
{
"ref": "https://www.microsoft.com/en-us/",
"type": "Vendor"
}
],
"deprecatedBy": [],
"vulnerabilities": [
"CVE-2016-0174",
"CVE-2016-0171"
]
}
Here is the class I map the Json data to:
public class RESPONSE {
Result result;
}
class Result {
List<Cpes> cpes;
}
class Cpes {
String cpe23Uri;
List<Titles> titles;
List<String> vulnerabilities;
}
class Titles{
String title;
}
When I debug my code r in the below code is null and I think it's because my RESPONSE class isn't set up right.
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
RESPONSE r = mapper.readValue(response.getContent(), RESPONSE.class);
System.out.println(r);
Your object model should match the structure of the JSON you are trying to read. For example, it'll have to look something like the following:
public class Response {
private int resultsPerPage;
private int startIndex;
private int totalResults;
private Result result;
// Should include getters and setters
}
public class Result {
private String dataType;
private String feedVersion;
private int cpeCount;
private String feedTimestamp;
private CPE[] cpes;
// Should include getters and setters
}
public class CPE {
private boolean deprecated;
private String cpe23Uri;
private String lastModifiedDate;
private Title[] titles;
private Ref[] refs;
private String[] deprecatedBy;
private String[] vulnerabilities;
// Should include getters and setters
}
public class Title {
private String title;
private String lang;
// Should include getters and setters
}
public class Ref {
private String ref;
private String type;
// Should include getters and setters
}
Note that to keep the code sample short, I've omitted the getters and setters.
Edit: As Tugrul pointed out below, since fail on unknown property is disabled, it won't fail if there are missing fields in your model. The only issue is the missing getters and setters.
I also found another way to solve this issue for future reference.
I used a tree data structure to access my Json fields which means I can just declare a flat class:
public class Test {
private String cpe23Uri;
private String title;
private List<String> vulnerabilities;
public String getCpe23Uri() {
return cpe23Uri;
}
public void setCpe23Uri(String cpe23Uri) {
this.cpe23Uri = cpe23Uri;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public List<String> getVulnerabilities() {
return vulnerabilities;
}
public void setVulnerabilities(List<String> vulnerabilities) {
this.vulnerabilities = vulnerabilities;
}
}
I then mapped using a Tree
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JsonNode resultNode = mapper.readTree(response.getContent());
Test t = new Test();
t.setCpe23Uri(resultNode.get("result").get("cpes").get(0).get("cpe23Uri").textValue());

Serialize Java Object attribute to JSON

I have an API built in Java Spring that return (using JacksonJaxbJsonProvider 2.5.5) a JSON object from this class:
public class FieldValues {
private String code;
private Object value;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
In the main object I've
#JsonRootName(value = "WorkRequest")
#XmlRootElement(name = "WorkRequest")
#JsonIgnoreProperties(ignoreUnknown = true)
public class WorkRequestDTOResponse {
private List<FieldValues> fieldValues;
public List<FieldValues> getFieldValues() {
return fieldValues;
}
public void setFieldValues(List<FieldValues> fieldValues) {
this.fieldValues = fieldValues;
}
}
But the output of the fieldValues object is this:
"fieldValues": [
{
"code": "anomaly",
"value": {
"#xsi.type": "ns3:boolean",
"$": "true"
}
},{
"code": "internal_note",
"value": {
"#xsi.type": "ns3:string",
"$": "Test text example"
}
}
]
instead what I need is this:
"fieldValues": [
{
"code": "anomaly",
"value": true
},{
"code": "internal_note",
"value": "Test text example"
}
]
This is my JSON Provider:
public class ErmesJSONProvider extends JacksonJaxbJsonProvider {
public ErmesJSONProvider() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
mapper.configure(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED, false);
_mapperConfig.setMapper(mapper);
_mapperConfig.getConfiguredMapper().setAnnotationIntrospector(new JacksonAnnotationIntrospector());
}
}
Trying to use a String instead an object:
public class FieldValues {
private String code;
private String value;
But if I set this value as String fieldValues.setValue("true"), the JSON output is "value": true instead "value": "true"
Likewise if I set this value as String but with an Integer fieldValues.setValue("1"), the JSON output is "value": 1 instead "value": "1"
If I print the return object using ObjectMapper I've the right JSON:
String payload = new ObjectMapper().writeValueAsString(requestResult)
but if I return a Response like this:
return Response.status(Response.Status.CREATED).entity(new GenericEntity<RequestResult>(requestResult){}).build()
it return the wrong JSON.
I can't understand why 😥
Someone can help me? Thanks.

Aggregation results cannot properly map to Java object

I'm trying to get schedules data from mongoDb.
I created the appropriate aggregation and tried to convert it within Spring Framework.
db.theaters.aggregate([
{ $match: { 'city_id': <someCityId>, 'theatreRooms.schedules.spectacle_id': <someSpecId> } },
{ $unwind: '$theatreRooms' },
{ $unwind: '$theatreRooms.schedules' },
{ $group: { _id: { name: '$name', room: '$theatreRooms.name' }, schedules: { $addToSet: '$theatreRooms.schedules.time' } } },
{ $group: { _id: '$_id.name', schedules: { $addToSet: { room: '$_id.room', schedules: '$schedules' } } } }
])
I've created properly match and unwind operations. But I've got problem with first group operation.
It seems that the operation is well interpreted, but for some reason I am not able to properly map the _id object.
Here is my code example:
public class TheaterProject {
private TheaterId _id;
private List<String> schedules;
public TheaterId get_id() {
return _id;
}
public void set_id(TheaterId _id) {
this._id = _id;
}
public List<String> getSchedules() {
return schedules;
}
public void setSchedules(List<String> schedules) {
this.schedules = schedules;
}
}
public class TheaterId {
#Field("name")
private String name;
#Field("room")
private Integer room;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getRoom() {
return room;
}
public void setRoom(Integer room) {
this.room = room;
}
}
public Document getRawSchedules(String cityId, String spectaclesId){
MatchOperation match = Aggregation.match(Criteria.where("city_id").is(cityId).and("theatreRooms.schedules.spectacle_id").is(spectaclesId));
UnwindOperation theaterUnwind = Aggregation.unwind("theatreRooms");
UnwindOperation schedulesUnwind = Aggregation.unwind("theatreRooms.schedules");
GroupOperation firstGroup = Aggregation.group(Fields.from(
Fields.field("name", "name"),
Fields.field("room", "theatreRooms.name")))
.addToSet("theatreRooms.schedules.time").as("schedules");
Aggregation agg = Aggregation.newAggregation(match,theaterUnwind,schedulesUnwind,firstGroup);
Document theaters = mongoTemplate.aggregate(agg, Theater.class, TheaterProject.class).getRawResults();
return theaters;
}
public List<TheaterProject> getSchedules(String cityId, String spectaclesId){
MatchOperation match = Aggregation.match(Criteria.where("city_id").is(cityId).and("theatreRooms.schedules.spectacle_id").is(spectaclesId));
UnwindOperation theaterUnwind = Aggregation.unwind("theatreRooms");
UnwindOperation schedulesUnwind = Aggregation.unwind("theatreRooms.schedules");
GroupOperation firstGroup = Aggregation.group(Fields.from(
Fields.field("name", "name"),
Fields.field("room", "theatreRooms.name")))
.addToSet("theatreRooms.schedules.time").as("schedules");
Aggregation agg = Aggregation.newAggregation(match,theaterUnwind,schedulesUnwind,firstGroup);
List<TheaterProject> theaters = mongoTemplate.aggregate(agg, Theater.class, TheaterProject.class).getMappedResults();
return theaters;
}
When I've invoked method getSchedules which return mapped objects, _id field is equal to null.
[
{
"_id": null,
"schedules": [
"5:15"
]
},
{
"_id": null,
"schedules": [
"6:55",
"4:35",
"10:15"
]
}
]
But when I've invoked getRawSchedules which used getRawResults it's looking properly.
{
"results": [
{
"_id": {
"name": "Pinokio",
"room": 2
},
"schedules": [
"5:15"
]
},
{
"_id": {
"name": "Roma",
"room": 1
},
"schedules": [
"6:55",
"4:35",
"10:15"
]
}
]
}
I don't have any idea why it's working like that.
I didn't find any information about this problem in the documentation and here. But I have a solution. You may just rename the field from _id to something else. theaterId for example. I don't know all requirements for your issue but you may do it just on mapping level.
Fix the mapping
import org.springframework.data.mongodb.core.mapping.Field;
import java.util.List;
public class TheaterProject {
#Field("theaterId")
private TheaterId _id;
private List<String> schedules;
public TheaterId get_id() {
return _id;
}
public void set_id(TheaterId _id) {
this._id = _id;
}
public List<String> getSchedules() {
return schedules;
}
public void setSchedules(List<String> schedules) {
this.schedules = schedules;
}
}
But it requires additional projection step
public List<TheaterProject> getSchedules(String cityId, String spectaclesId){
...
GroupOperation firstGroup = Aggregation.group(Fields.from(
Fields.field("name", "name"),
Fields.field("room", "theatreRooms.name")))
.addToSet("theatreRooms.schedules.time").as("schedules");
ProjectionOperation projection = Aggregation.project(Fields.from(
Fields.field("theaterId", "_id"),
Fields.field("schedules", "schedules")));
Aggregation agg = Aggregation.newAggregation( ... ,firstGroup, projection);
List<TheaterProject> theaters = mongoTemplate.aggregate(agg, "collectionName", TheaterProject.class).getMappedResults();
return theaters;
}

Build tree structure from Json flat array in Java - Android

I have a json file with Categories of products.
Every entry of the json has :
Id : a unique category id
IdParent : the id of the parent node
...Name & ImageUrl
Sample Date:
[
{
"ImageUrl":"1-home_default/1",
"Id":1,
"IdParent":0,
"Name":"Root"
},
{
"ImageUrl":"2-home_default/2",
"Id":2,
"IdParent":1,
"Name":"Home"
},
{
"ImageUrl":"12-home_default/12",
"Id":12,
"IdParent":2,
"Name":"Fruit"
},
{
"ImageUrl":"336-home_default/336",
"Id":336,
"IdParent":2,
"Name":"Papers"
},
{
"ImageUrl":"33-home_default/33",
"Id":33,
"IdParent":2,
"Name":"Food"
},
{
"ImageUrl":"95-home_default/95",
"Id":95,
"IdParent":2,
"Name":"Meet"
},
{
"ImageUrl":"121-home_default/121",
"Id":121,
"IdParent":2,
"Name":"Bolvery"
},
{
"ImageUrl":"145-home_default/145",
"Id":145,
"IdParent":2,
"Name":"Milk Breakfast"
},
{
"ImageUrl":"189-home_default/189",
"Id":189,
"IdParent":2,
"Name":"Food OUt"
},
{
"ImageUrl":"269-home_default/269",
"Id":269,
"IdParent":2,
"Name":"Cleaning"
},
{
"ImageUrl":"305-home_default/305",
"Id":305,
"IdParent":2,
"Name":"Babies"
},
{
"ImageUrl":"401-home_default/401",
"Id":401,
"IdParent":2,
"Name":"Lifestyle"
},
{
"ImageUrl":"413-home_default/413",
"Id":413,
"IdParent":2,
"Name":"Products"
},
{
"ImageUrl":"426-home_default/426",
"Id":426,
"IdParent":2,
"Name":"Copaigns"
},
{
"ImageUrl":"23-home_default/23",
"Id":23,
"IdParent":12,
"Name":"Seeds"
},
{
"ImageUrl":"344-home_default/344",
"Id":344,
"IdParent":336,
"Name":"Mouth products"
},
{
"ImageUrl":"34-home_default/34",
"Id":34,
"IdParent":33,
"Name":"Macarna"
},
{
"ImageUrl":"103-home_default/103",
"Id":103,
"IdParent":95,
"Name":"Animals"
},
{
"ImageUrl":"127-home_default/127",
"Id":127,
"IdParent":121,
"Name":"Drinks"
},
{
"ImageUrl":"146-home_default/146",
"Id":146,
"IdParent":145,
"Name":"Milk"
},
{
"ImageUrl":"190-home_default/190",
"Id":190,
"IdParent":189,
"Name":"Electronics"
},
{
"ImageUrl":"276-home_default/276",
"Id":276,
"IdParent":269,
"Name":"Cleaning2"
},
{
"ImageUrl":"310-home_default/310",
"Id":310,
"IdParent":305,
"Name":"Kids Cleaning"
},
{
"ImageUrl":"402-home_default/402",
"Id":402,
"IdParent":401,
"Name":"Traveling"
}
]
I am trying to fill this Json file to Tree Structure like the one below:
public class Tree<T> {
private Node<T> root;
public Tree(T rootData) {
root = new Node<T>();
root.data = rootData;
root.children = new ArrayList<Node<T>>();
}
public static class Node<T> {
private T data;
private Node<T> parent;
private List<Node<T>> children;
}
}
So that when user clicks on on of the Nodes, if it has children, it will list the children, otherwise, it will open the products of that category.
I have converted the Json to List<Category>
How to convert List<Category> to Tree?
Based on the answer, which I've found here, I've done it in Java like this:
My mapped Object:
public class MyObject {
public Long objectId;
public String objectName;
public Long parentObjectId;
public MyObject(Long objectId, String objectName, Long parentObjectId) {
this.objectId = objectId;
this.objectName = objectName;
this.parentObjectId = parentObjectId;
}
}
The Node class:
public class Node {
public List<Node> Children = new ArrayList<>();
public Node Parent;
public MyObject Source;
public MyObject getSourceObject() {
return Source;
}
public void setSourceObject(MyObject Source) {
Source = Source;
}
public Node getParent() {
return Parent;
}
public void setParent(Node parent) {
Parent = parent;
}
}
How to build the Tree:
public List<Node> BuildTreeAndGetRoots(List<MyObject> actualObjects) {
Map<Long, Node> lookup = new HashMap<>();
List rootNodes = new ArrayList<Node>();
for (MyObject object : actualObjects) {
// add us to lookup
Node ourNode;
if (lookup.containsKey(object.objectId)) { // was already found as a parent - register the actual object
ourNode = lookup.get(object.objectId);
ourNode.Source = object;
} else {
ourNode = new Node();
ourNode.Source = object;
lookup.put(object.objectId, ourNode);
}
// hook into parent
if (object.parentObjectId == null || object.parentObjectId.equals(object.objectId)) { // is a root node
rootNodes.add(ourNode);
} else { // is a child row - so we have a parent
Node parentNode;
if (!lookup.containsKey(object.parentObjectId)) { // unknown parent, construct preliminary parent
parentNode = new Node();
lookup.put(object.parentObjectId, parentNode);
} else {
parentNode = lookup.get(object.parentObjectId);
}
parentNode.Children.add(ourNode);
ourNode.Parent = parentNode;
}
}
return rootNodes;
}

Gson string with key

I am using Gson to get convert the object to json string, and its working fine but when I am sending that json to a webservice method using post, I have to add the post method's parameter name in the string.
Example:
jsonString I get from Gson new Gson().toJson(requestDataDTO) :
{
"req": {
"AppId": "2",
"ThirdParty": "3",
"UserId": "1",
"UserToken": "4"
},
"req1": {
"AppId": "-33",
"ThirdParty": "3",
"UserId": "1",
"UserToken": "4"
}
}
jsonString I want :
{
"requestDataDTO": {
"req": {
"AppId": "2",
"ThirdParty": "3",
"UserId": "1",
"UserToken": "4"
},
"req1": {
"AppId": "-33",
"ThirdParty": "3",
"UserId": "1",
"UserToken": "4"
}
}
}
for now I am adding this "requestDataDTO" string at the start of json string I got from Gson.
is there a way to achieve this ?
Assuming you have an object which looks somehow like this:
package com.dominikangerer.q25077756;
import com.google.gson.annotations.SerializedName;
public class RequestDataDTO {
// {"AppId":"2","ThirdParty":"3","UserId":"1","UserToken":"4"}
#SerializedName("AppId")
private String appId;
#SerializedName("ThirdParty")
private String thirdParty;
#SerializedName("UserId")
private String userId;
#SerializedName("UserToken")
private String userToken;
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getThirdParty() {
return thirdParty;
}
public void setThirdParty(String thirdParty) {
this.thirdParty = thirdParty;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserToken() {
return userToken;
}
public void setUserToken(String userToken) {
this.userToken = userToken;
}
}
The easiest and also for me most readable solution would be to create an wrapper/container Class which contains a HashMap (key/value) like this:
package com.dominikangerer.q25077756;
import java.util.HashMap;
public class RequestDataDTOContainer {
private HashMap<String, RequestDataDTO> requestDataDTO = new HashMap<String, RequestDataDTO>();
public HashMap<String, RequestDataDTO> getRequestDataDTO() {
return requestDataDTO;
}
public void setRequestDataDTO(HashMap<String, RequestDataDTO> requestDataDTO) {
this.requestDataDTO = requestDataDTO;
}
public void putRequestDataDTO(String key, RequestDataDTO value){
this.requestDataDTO.put(key, value);
}
}
To run it simply test it with a main like this:
// enable pretty printing
Gson gson = new GsonBuilder().setPrettyPrinting().create();
// too lazy to fill the objects by hand
String reqJson = "{\"AppId\":\"2\",\"ThirdParty\":\"3\",\"UserId\":\"1\",\"UserToken\":\"4\"}";
String req1Json = "{\"AppId\":\"-33\",\"ThirdParty\":\"3\",\"UserId\":\"1\",\"UserToken\":\"4\"}";
// deserialize it with gson
RequestDataDTO req = gson.fromJson(reqJson, RequestDataDTO.class);
RequestDataDTO req1 = gson.fromJson(req1Json, RequestDataDTO.class);
// initiliaze the container
RequestDataDTOContainer container = new RequestDataDTOContainer();
// adding the 2 req objects with the certain key
container.putRequestDataDTO("req", req);
container.putRequestDataDTO("req1", req1);
// Print it as pretty json
System.out.println(gson.toJson(container));
You are now more flexibility if you want to add more meta information like a whole meta object or similar without adding a hardcoded String to that json.
You can find the whole Example in this github repository: Java Stackoverflow Answers by DominikAngerer

Categories

Resources