I have the below Json that I'm reading into nested POJOs with the same structure.
{
"employees": [
{
"name": "John",
"age": "30",
"proData": [
{
"year": "1",
"idList": [
"234342",
"532542",
"325424",
"234234"
]
},
{
"year": "2",
"idList": [
"234342",
"532542",
"325424",
"234234"
]
},
{
"year": "3",
"idList": [
"234342",
"532542",
"325424",
"234234"
]
}
]
},
{
"name": "Scott",
"age": "32",
"proData": [
{
"year": "1",
"idList": [
"234342",
"532542",
"325424",
"234234"
]
},
{
"year": "2",
"idList": [
"234342",
"532542",
"325424",
"234234"
]
},
{
"year": "3",
"idList": [
"234342",
"532542",
"325424",
"234234"
]
}
]
}
]
}
Now I wanted to map this to a structure like below, the ProData can be initialized using each of the string in the idList.
Map<String,Map<String,List<ProData>>> finalMap
I have written something like the below and it works.
Map<String,Map<String,List<ProData>>> finalMap = new HashMap<>();
for(Employee employee:root.getEmployees()){
Map<String,List<ProData>> proDataMap = new HashMap<>();
for(ProData proData: employee.getProData()){
List<ProData> finalObjs = new ArrayList<>();
for(String id:proData.getIdList()){
finalObjs.add(new ProData(id));
}
proDataMap.put(proData.getYear(),finalObjs);
}
finalMap.put(employee.getName(),proDataMap);
}
I wanted to make a better version using the stream API.
The end result is a map, so use the toMap collector. The maps' keys are the employee names (assuming no duplicates), and the map values require a little bit more work.
root.getEmployees().stream().collect(
Collectors.toMap(
Employee::getName,
Employee::getProDataMap
)
}
Now let's try writing getProDataMap in Employee. Again we use the toMap collector. The keys are the years (assuming no duplicates), and the values are the id lists mapped to ProData using the constructor.
public Map<String, List<ProData>> getProDataMap() {
return this.getProData().stream().collect(
Collectors.toMap(
ProData::getYear,
proData -> proData.getIdList().stream()
.map(ProData::new)
.collect(Collectors.toList())
)
)
}
should be something similar to,
root.stream().forEach(employee -> {
Map<String,List<ProData>> proDataMap = new HashMap<>();
employee.getProdData().stream().forEach(data -> {
List<ProData> finalObjs = new ArrayList<>();
data.getIdList().stream().forEach(data -> {
finalObjs.add(new ProData(id));
});
});
});
but regardless you can also use Gson to parse it
https://mkyong.com/java/how-to-parse-json-with-gson/
Related
I am trying to get the id of the OutterObject where the InnerObject id is a specific value and the date is the most recent of all InnerObject of all OutterObject.
I'm trying to achieve that with streams.
Searching for id "ab", it should return "def"
here is a json example of the structre.
{
"OutterObject": [
{
"id": "abc",
"InnerObject": [
{
"id": "ab",
"date": "1"
},
{
"id": "de",
"date": "2"
},
{
"id": "ab",
"date": "3"
}
]
},
{
"id": "def",
"InnerObject": [
{
"id": "ab",
"date": "9"
},
{
"id": "de",
"date": "3"
},
{
"id": "ab",
"date": "1"
}
]
}
]
}
Use flatMap to gather all objects in the same array :
OutterObject.stream().flatMap(outer -> outer.getInnerObject().stream());
Use max() and Comparator to get the higher value
Combine both to get something like :
Optional<Date> maxDate = OutterObject.stream().flatMap(outer -> outer.getInnerObject().stream()).max(Comparator.comparing(InnerObject::getDate));
This is solved with :
Optional<SimpleImmutableEntry<String, InnerObject>> mostRecentOutterObjectId= MasterObject.getOutter().stream()
.flatMap(outter-> outter.getInner().stream()
.map(inner-> new SimpleImmutableEntry<String, InnerObject>(outter.getId(), inner)))
.filter(outterMap-> StringUtils.equals(outterMap.getValue().getId(), "ab")))
.max((innerA,innerB) -> innerA.getValue().getDate().compareTo(innerB.getValue().getDate()));
I am open to improvement if you see some.
i have request :
"questionType": "questionType",
"question": [
{
"questionId": "questionIdFirst",
"answer": [
{
"input": "input1",
"answerOption": [
{
"answerId": "AnswerId1",
"score": 7
}
]
},
{
"input": "input2",
"answerOption": [
{
"answerId": "AnswerId2",
"score": 8
}
]
}
]
},
{
"questionId": "questionIdSecond",
"answer": [
{
"input": "input3",
"answerOption": [
{
"answerId": "answerId",
"score": 9
}
]
},
{
"input": "input4",
"answerOption": [
{
"answerId": "answerId",
"score": 10
}
]
}
]
}
]
}
and i want to get maxValues score in object answerOption with stream filter or foreach, how can i do this?
i try to this and cannot resolve :
input.getQuestionnaire().getQuestion().stream()
.forEach(quest -> quest.getAnswer().stream()
.forEach(answer -> answer.getAnswerOption()
.stream().max(Comparator.comparing(AnswerOption::getScore))));
and then, in i want to get maxValues, i select to DB and then i want to replace answerOption for request sample to database
For retrieving the max score AnswerOption in your Questionnaire try the following (you need flatMap to flatten the inner lists and get the max comparator result as output)
final Optional<AnswerOption> max = input.getQuestionnaire().getQuestion().stream().map(Question::getAnswer)
.flatMap(Collection::stream)
.map(Answer::getAnswerOption).flatMap(Collection::stream)
.max(Comparator.comparing(AnswerOption::getScore));
This is my json structure and I want to get the values of hierarchy_name from each json object in an Array , can someone help me with that using Java..
{
"hits": {
"total": {
"value": 218
},
"max_score": null,
"hits": [
{
"_index": "planlytx",
"_source": {
"hierarchy_name": "PRODUCT"
},
"fields": {
"attribute_name.keyword": [
"PRODUCT"
]
}
},
{
"_index": "planlytx",
"_source": {
"hierarchy_name": "PRODUCT"
},
"fields": {
"attribute_name.keyword": [
"PRODUCT-ALL"
]
}
}
]
}
}
Using org.json, you can do:
JSONArray hitsArray = new JSONObject(jsonStr).getJSONObject("hits").getJSONArray("hits");
List<String> keywords = IntStream.range(0, hitsArray.length())
.mapToObj(hitsArray::getJSONObject)
.map(json -> json.getJSONObject("fields")
.getJSONArray("attribute_name.keyword")
.toList())
.flatMap(objects -> objects.stream().map(Object::toString))
.collect(Collectors.toList());
For "hierarchy_name":
JSONArray hitsArray = new JSONObject(jsonStr).getJSONObject("hits").getJSONArray("hits");
List<String> keywords = IntStream.range(0, hitsArray.length())
.mapToObj(hitsArray::getJSONObject)
.map(json -> json.getJSONObject("_source").getString("hierarchy_name"))
.collect(Collectors.toList());
Output:
[PRODUCT, PRODUCT-ALL]
I currently have a set of data I pull back from an API in my java app. The data returned is along the lines of the following:
{
"id": 1,
"receiptId": "123456",
"selections": [
{
"name": "Apple",
"price": "£1"
}
]
},
{
"id": 2,
"receiptId": "678910",
"selections": [
{
"name": "Pear",
"price": "£0.5"
}
]
},
{
"id": 3,
"receiptId": "123456",
"selections": [
{
"name": "Banana",
"price:": "£2.00"
}
]
}
As you can see, two of the receiptId's are the same, I would like to merge any duplicate receiptId's data together to become one block. I.e:
{
"id": 1,
"receiptId": "123456",
"selections": [
{
"name": "Apple",
"price": "£1"
},
{
"name": "Banana",
"price": "£2.00"
}
]
},
{
"id": 2,
"receiptId": "678910",
"selections": [
{
"name": "Pear",
"price": "£0.5"
}
]
},
Currently I am just streaming the data into a map by doing the following:
List<String> data = data.getData()
.stream()
.map(this::dataToReadable)
.collect(Collectors.toList());
dataToReadable does the following:
private String dataToReadable(List data) {
return new DataBuilder().fromData(data)
.buildData();
}
fromData does the following:
public DataBuilder fromData(List data) {
this.withId(data.getId())
this.withSelections(data.getSelections())
this.withReceiptId(data.getReceiptId())
return this;
}
See if this works.
data.getData()
.stream()
.collect(Collectors.groupingBy(Data::getRecieptId))
.entrySet()
.stream()
.map(item -> dataToReadable(item.getValue()))
.collect(Collectors.toList());
I have to create POJO class of following JSON, Problem is that key p_d has variables with dynamic name like s_t, n_t, n_p and etc. the real JSON is big and i am facing problem with that part only, i shared partial JSON.
i am using jackson for parsing.
{
"flag": true,
"flag2": false,
"r_no": [
{
"room_type": 250067,
"no_of_rooms": 1,
"no_of_children": 1,
"no_of_adults": 2,
"description": "Executive Room, 1 King Bed, Non Smoking",
"children_ages": [
8
]
},
{
"room_type": 250067,
"no_of_rooms": 1,
"no_of_children": 0,
"no_of_adults": 2,
"description": "Executive Room, 1 King Bed, Non Smoking"
}
],
"r_code": "abc",
"r_key": "123",
"p_d": {
"s_t": [
{
"name": "xyz",
"cur": "INR"
},
{
"name": "xyz1",
"cur": "INR"
}
],
"n_t": [
{
"name": "xyz2",
"cur": "INR"
}
],
"n_p": [
{
"name": "xyz5",
"cur": "INR"
}
]
},
"cur": "INR"
}
For dynamic keys, use a Map<String, Object>:
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> parsed = mapper.readValue(json,
new TypeReference<Map<String, Object>>() {});