How to Convert Tree Structure List to Json - java

I have query result like this :
DEPT_NAME
DEPT_R_IDX
DEPT_IDX
DEPT_LEVEL
root
0
1
0
dept_0
1
2
1
dept_1
1
3
1
dept_1_0
3
4
2
dept_1_1
3
5
2
dept_2
1
6
1
dept_2_0
6
7
2
dept_2_0_1
7
8
3
DEPT_IDX is PRIMARY KEY, DEPT_LEVEL is TREE DEPTH, DEPT_R_IDX is parent's DEPT_IDX
I stored this data in Java's List.
List<HashMap<String, String>> DEPT_LIST;
I want convert this List to Json like this :
[
{
"title": "root",
"key": "1",
"expanded": true,
"folder": true,
"children": [
{
"key": "2",
"title": "dept_0",
"expanded": true,
"folder": true
},
{
"key": "3",
"title": "dept_1",
"expanded": true,
"folder": true,
"children": [
{
"key": "4",
"title": "dept_1_0",
"expanded": true,
"folder": true
},
{
"key": "5",
"title": "dept_1_1",
"expanded": true,
"folder": true
}
]
},
{
"key": "6",
"title": "dept_2",
"expanded": true,
"folder": true,
"children": [
{
"key": "7",
"title": "dept_2_0",
"expanded": true,
"folder": true,
"children": [
{
"key": "8",
"title": "dept_2_1",
"expanded": true,
"folder": true
}
]
}
]
}
]
}
]
result tree using this json data(using fancytree)
i tried this in browser side, but it's too low performance to make json structure

Instead of storing your data in a List<HashMap<String, String>>, store them in a List<Node> where class Node is something like this:
public class Node {
private String title;
private String key;
private boolean expanded;
private boolean folder;
private List<Node> children;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public boolean isExpanded() {
return expanded;
}
public void setExpanded(boolean expanded) {
this.expanded = expanded;
}
public boolean isFolder() {
return folder;
}
public void setFolder(boolean folder) {
this.folder = folder;
}
public List<Node> getChildren() {
return children;
}
public void setChildren(List<Node> children) {
this.children = children;
}
}
Then use Jackson or Gson to generate the corresponding Json.

Related

Group two object attributes in a list

I would like to transform a duplicate object with different values to a list in java, as follows
[
{
"code": "code",
"active": true,
"car": "Sedan"
},
{
"code": "code",
"active": true,
"car": "R4"
},
{
"code": "code2",
"active": false,
"car": "Sedan"
},
{
"code": "code2",
"active": false,
"car": "R4"
}
]
ClassOne
public class Car{
private String code;
private boolean active;
private String car;
}
if "code" and "active" are the same, I would like to group them in a single object
[
{
"code": "code",
"active": true,
"name": {
"cars": [
{
"brand": "Sedan"
},
{
"brand": "R4"
}
]
}
},
{
"code": "code2",
"active": false,
"name": {
"cars": [
{
"brand": "Sedan"
},
{
"brand": "R4"
}
]
}
}
]
Class parse
public class CarParse{
private String code;
private String active;
private Name name;
}
public class Name{
private List<Brand> cars;
}
public class Brand{
private String brand;
}
Then it would be to go from ClassOne to ClassParse,transforming the objects grouped by "code" and "active
I find writing the non java-stream easier first.
For example, group the input objects on code-active will form a unique pair that you can loop over, then build the final list from
public List<CarParse> getParsed(List<Car> cars) {
Map<String, CarParse> codeMap = new HashMap<>();
for (Car c : cars) {
CarParse cp;
List<Brand> brands;
String code = c.getCode();
boolean active = c.isActive();
String group = String.format("%s-%s", code, active);
Brand b = new Brand(c.getCar());
if (codeMap.containsKey(group)) {
cp = codeMap.get(group);
brands = cp.getName().getCars();
brands.add(b);
} else {
brands = new ArrayList<>();
brands.add(b);
Name n = new Name(brands);
cp = new CarParse(code, active, n);
codeMap.put(group, cp);
}
}
return new ArrayList<>(codeMap.values());
}
Stream version
return new ArrayList<>(cars.stream().collect(Collectors.toMap(
c -> String.format("%s-%s", c.getCode(), c.isActive()),
c -> {
ArrayList<Brand> brands = new ArrayList<>();
brands.add(new Brand(c.getCar()));
return new CarParse(c.getCode(), c.isActive(), new Name(brands));
},
(v1, v2) -> {
if (v1.isActive() == v2.isActive() && (v1.getCode().equals(v2.getCode()))) {
for (Brand b : v2.getName().getCars()) {
v1.getName().getCars().add(b);
}
return v1;
}
return v1;
})).values());
Output
[ {
"code" : "code",
"active" : true,
"name" : {
"cars" : [ {
"brand" : "Sedan"
}, {
"brand" : "R4"
} ]
}
}, {
"code" : "code2",
"active" : false,
"name" : {
"cars" : [ {
"brand" : "Sedan"
}, {
"brand" : "R4"
} ]
}
} ]

Java Stream to aggregate list of JSONs into groups

I have list of objects in java, like this.
[
{
"applicationNumber": "100400",
"users": "A",
"category": "student"
},
{
"applicationNumber": "100400",
"users":"B",
"category": "student"
},
{
"applicationNumber": "100400",
"users":"C",
"category": "neighbour"
},
{
"applicationNumber": "100400",
"users": "D",
"category": "neighbour"
},
{
"applicationNumber": "200543",
"users": "C",
"category": "student"
},
{
"applicationNumber": "200543",
"users": "A",
"category": "student"
},
{
"applicationNumber": "200543",
"users":"D",
"category": "friend"
}
]
I want to group users as list (order does not matter) for each category for every applicationNumber. Can refer below json to get the idea.
[
{
"applicationNumber": "100400",
"users": [
"A",
"B"
],
"category": "student"
},
{
"applicationNumber": "100400",
"users": [
"C",
"D"
],
"category": "neighbour"
},
{
"applicationNumber": "200543",
"users": [
"C",
"A"
],
"category": "student"
},
{
"applicationNumber": "200543",
"users": [
"D"
],
"category": "friend"
}
]
I am able to this using a for loop, HashMap and if else conditions. I want to use Java 8 stream to achieve the same . Can anyone help me , I am new to java.
PS: Thank you in advance
I think using streams here is a little bit overengineering but you can to that in two steps. First you need to use Collectors.groupingBy() to group yours pojos into map of lists. Next you need to reduce each list to a single value by using stream().reduce().
ObjectMapper mapper = new ObjectMapper()
.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
List<Application> applications = Arrays.asList(mapper.readValue(json, Application[].class));
List<Application> groupedApplications = applications.stream()
.collect(Collectors.groupingBy(ApplicationKey::of, Collectors.toList()))
.values().stream()
.map(apps -> apps.stream().reduce(Application::merge))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
Application.java:
public class Application {
private String applicationNumber;
private String category;
private List<String> users = new ArrayList<>();
public static Application merge(Application first, Application second) {
assert ApplicationKey.of(first).equals(ApplicationKey.of(second));
Application merged = new Application(first.applicationNumber, first.category, first.getUsers());
merged.users.addAll(second.getUsers());
return merged;
}
//constructor, getters, setters
}
ApplicationKey.java
public class ApplicationKey {
private String applicationNumber;
private String category;
public static ApplicationKey of(Application application) {
return new ApplicationKey(application.getApplicationNumber(), application.getCategory());
}
public ApplicationKey(String applicationNumber, String category) {
this.applicationNumber = applicationNumber;
this.category = category;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ApplicationKey that = (ApplicationKey) o;
return Objects.equals(applicationNumber, that.applicationNumber) &&
Objects.equals(category, that.category);
}
#Override
public int hashCode() {
return Objects.hash(applicationNumber, category);
}
//getters, setters
}

How to iterate a list recursively on condition comparison using java8 stream

I have two sets of json , which consist of recursive children.
I want to find last child in that list which will contain "code", I want to find all "code" values from that jsons.
Sample1:
{
"totalSize": 1,
"data": [
{
"level": "sites",
"children": [
{
"level": "sites",
"children": [
{
"level": "segments",
"children": [
{
"level": "assets",
"code": "1"
},
{
"level": "assets",
"code": "2"
},
{
"level": "assets",
"code": "3"
},
{
"level": "assets",
"code": "4"
},
{
"level": "assets",
"code": "5"
},
{
"level": "assets",
"code": "6"
}
]
}
]
}
]
}
]
}
Sample2:
{
"totalSize": 1,
"data": [
{
"level": "sites",
"children": [
{
"level": "segments",
"children": [
{
"level": "assets",
"code": "1"
},
{
"level": "assets",
"code": "2"
},
{
"level": "assets",
"code": "3"
},
{
"level": "assets",
"code": "4"
},
{
"level": "assets",
"code": "5"
},
{
"level": "assets",
"code": "6"
}
]
}
]
}
]
}
The entities are as follows:
public class HierarchyResponse {
private Integer totalSize;
private List<Data> data;
}
public class Data {
private List<Children> children;
private String level;
}
public class Children {
private String level;
private List<Children> children;
}
I have tried but didnot succeed:
List<Children> children = response
.getData()
.get(0)
.getChildren()
.stream().filter(t -> t.getLevel().equalsIgnoreCase("assets"))
.collect(Collectors.toList());
you can create a method which recursively flatmaps the children
private static Stream<Children> toStream(Children children) {
if (children != null) {
return Stream.concat(Stream.of(children), children.getChildren().stream().flatMap(c -> toStream(c)));
} else {
return Stream.empty();
}
}
and use it as
List<Children> children = response.getData().stream()
.flatMap(d -> d.getChildren().stream())
.flatMap(c -> toStream(c))
.filter(t -> t.getLevel().equalsIgnoreCase("assets"))
.collect(Collectors.toList());
for example
Children b1as2 = new Children("assets", "2");
Children b1as1 = new Children("assets", "1");
Children b1seg1 = new Children("segments", "0", List.of(b1as1, b1as2));
Children b1s1 = new Children("sites", "0", List.of(b1seg1));
Children b1 = new Children("sites", "0", List.of(b1s1));
Data data = new Data(List.of(b1));
HierarchyResponse response = new HierarchyResponse(List.of(data));
will print [Children{level='assets', code='1'}, Children{level='assets', code='2'}]
Another solution is not using Stream API
private static List<Children> findAssetsChildren(List<Children> children) {
List<Children> result = new LinkedList<>();
for(Children ch: children) {
if(ch.getLevel().equals("assets")) {
result.add(ch);
}
result.addAll(findAssetsChildren(ch.getChildren()));
}
return result;
}
//...
List<Children> children = findAssetsChildren(response.getData()
.get(0).getChildren());

How do I parse an input JSON, and based on the existing JSON, which represents a product inventory, generate the bill

I am trying to parse JSON using GSON library.
I have a product inventory in the form of a JSON like this:
[
{
"id": 2000,
"name": "Child Shoes",
"variants": [
{
"size": "size 7",
"price": 19.99,
"tax_code": 0
}
]
},
{
"id": 3000,
"name": "Eggs",
"variants": [
{
"size": "6",
"price": 1.50,
"tax_code": 7
},
{
"size": "12",
"price": 2.25,
"tax_code": 1
}
]
},
{
"id": 3100,
"name": "Apples",
"variants": [
{
"size": "1",
"price": 0.30,
"tax_code": 7
},
{
"size": "10",
"price": 2.50,
"tax_code": 7
}
]
},
{
"id": 5423,
"name": "Book",
"variants": [
{
"size": "Assorted",
"price": 11.00,
"tax_code": 1
}
]
}
]
And Tax codes as follows :
[
{
"code": 0,
"name": "HST",
"rate": 0.13
},
{
"code": 1,
"name": "HST - Books",
"rate": 0.05
},
{
"code": 7,
"name": "EXEMPT - Food",
"rate": 0
}
]
Now, how do I generate the total bill, if I get an input like this:
[
{
"product": 3000,
"variant": 1,
"quantity": 1
},
{
"product": 3100,
"variant": 1,
"quantity": 1
}
]
I am new to JSON and having a tough time trying to identify the correct strategy to solve this problem.
I hope below solution give you some idea -
Map your json to pojo like below -
public class ProductInventory {
private Integer id;
private String name;
private List<Variant> variants = null;
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 List<Variant> getVariants() {
return variants;
}
public void setVariants(List<Variant> variants) {
this.variants = variants;
}
}
//class Variant
public class Variant {
private String size;
private Double price;
private Integer taxCode;
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public Integer getTaxCode() {
return taxCode;
}
public void setTaxCode(Integer taxCode) {
this.taxCode = taxCode;
}
}
Use Gson library to parse json into java object and vice-versa:
Gson gson = new Gson();
Type jsonType = new TypeToken<List<ProductInventory>>(){}.getType();
List<ProductInventory> piList = gson.fromJson(json, jsonType);
Now Iterate over the piList and populate your other pojos and parse it into json using toJson() method.
Note:- You have to create pojo classes for the target json, that you can create here - http://www.jsonschema2pojo.org/

JSON for constructing multilevel tree

I wanted to form JSON like this:
{
"Schedule": [
{
"id": "A",
"name": "Summary",
"ischild": "1",
"level1": [
{
"id": "A.1",
"name": "A.1",
"ischild": "1",
"level2": [
{
"id": "A.1.a",
"name": "Income Statement",
"ischild": "0"
},
{
"id": "A.1.b",
"name": "Balance Sheet",
"ischild": "0"
},
{
"id": "A.1.c",
"name": "A.1.c",
"ischild": "1",
"level3": [
{
"id": "A.1.c.1",
"name": "General RWA",
"ischild": "0"
},
{
"id": "A.1.c.2",
"name": "Standardized RWA",
"ischild": "0"
},
{
"id": "A.1.c.3",
"name": "Advanced RWA",
"ischild": "0"
}
]
}
]
}
]
}
]
}
But my code is giving below output:
{
"Schedule": [
{
"name": "Summary",
"ischild": "1",
"id": "A",
"N_LEVEL": "1"
},
{
"name": "A.1",
"ischild": "1",
"id": "A.1",
"N_LEVEL": "2"
},
{
"name": "Income Statement",
"ischild": "0",
"id": "A.1.a",
"N_LEVEL": "3"
},
{
"name": "Balance Sheet",
"ischild": "0",
"id": "A.1.b",
"N_LEVEL": "3"
},
{
"name": "A.1.c",
"ischild": "1",
"id": "A.1.c",
"N_LEVEL": "3"
},
{
"name": "General RWA",
"ischild": "0",
"id": "A.1.c.1",
"N_LEVEL": "4"
},
{
"name": "Standardized RWA",
"ischild": "0",
"id": "A.1.c.2",
"N_LEVEL": "4"
},
{
"name": "Advanced RWA",
"ischild": "0",
"id": "A.1.c.3",
"N_LEVEL": "4"
}
]
}
Here is my code:
public static String getJSONFromResultSet(ResultSet rs,String keyName)
{
System.out.println(" in getJSONFromResultSet method");
Map json = new HashMap();
List list = new ArrayList();
if(rs!=null)
{
try
{
ResultSetMetaData metaData = rs.getMetaData();
while(rs.next())
{
Map<String,Object> columnMap = new HashMap<String, Object>();
for(int columnIndex=1;columnIndex<=metaData.getColumnCount();columnIndex++)
{
if(rs.getString(metaData.getColumnName(columnIndex))!=null)
columnMap.put(metaData.getColumnLabel(columnIndex),rs.getString(metaData.getColumnName(columnIndex)));
else
columnMap.put(metaData.getColumnLabel(columnIndex), "");
}
list.add(columnMap);
}
}
catch (SQLException e)
{
e.printStackTrace();
}
json.put(keyName, list);
}
return JSONValue.toJSONString(json);
I think your target structure could be better if it's names didn't change on every level. The level number is a value not a key. ischild makes no sense either, I think this is isNotALeaf, well that can be worked out, so leave that off too, so we have:
{
"id": "A",
"name": "Summary",
"level": "1",
"children": [
{
"id": "A.1",
"name": "A.1",
"level": "2",
"children": [
{
"id": "A.1.a",
"name": "Income Statement",
"level": "3"
},
{
"id": "A.1.b",
"name": "Balance Sheet",
"level": "3"
}
]
}
}
Then generate a self-referencing class with based on that for use in GSon:
package com.example;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Generated;
import com.google.gson.annotations.Expose;
#Generated("org.jsonschema2pojo")
public class Child {
#Expose
private String id;
#Expose
private String name;
#Expose
private String level;
#Expose
private List<Child> children = new ArrayList<Child>();
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLevel() {
return level;
}
public void setLevel(String level) {
this.level = level;
}
public List<Child_> getChildren() {
return children;
}
public void setChildren(List<Child> children) {
this.children = children;
}
}

Categories