Please I'm doing a practice with MongoDB and Spring but I have the following dilemma; in the DB I have the following information:
[
{
"menu":"querys",
"optionsList":[
{
"options":[
"0001",
"0022",
"0014",
"0041",
"0042",
"0043"
]
}
]
},{..},{...}
]
The structure of the object in Java is as follows:
#Document(collection = "menu")
public class GetAllRules implements Serializable {
private static final long serialVersionUID = 7375796948388333325L;
#JsonProperty(value = "menu")
private String name;
#JsonProperty(value = "optionsList")
private List<Map<String, ?>> optionsList;
//Getters and Setters.
With the following method I get the JSON (I'm using the MongoRepository), with the first FOR I get all the information and with the second I get the inner map, but I don't know how to iterate the information found inside options, I would appreciate it if someone can you help me with the issue:
#GetMapping("/final")
public String obtener() {
List<GetAllRules> allRules = iGetMenuService.getAll(); // Mongo List
String key= "options";
for (GetAllRules rules : allRules) {
for (Map<String, ?> internal : rules.getOptionsList()) {
System.out.println(internal.get(key));
}
}
return "finalizado";
}
With line System.out.println(internal.get(key)); I get the key values that I need but now I don't know how to go through it one by one to do something specific with each data.
[0001, 0022, 0014, 0041, 0042, 0043]
[0238]
[1001, 1003]
[0108, 0109, 0102]
[0601, 0602, 0604, 0604]
[0603, 0901, 0901]
[0238]
[0001]
Thanks.
how to iterate the information found inside options
Your options field is just another array/list of strings, so you can specify that in your pojo:
#JsonProperty(value = "optionsList")
private List<Map<String, List<String>>> optionsList;
with that, you can add one more iteration
for (GetAllRules rules : allRules) {
for (Map<String, List<String>> internal : rules.getOptionsList()) {
for (String value : internal.get(key)) {
System.out.println(value);
// will print "0001", ...
}
}
}
Nicer way to handle this would be to use Java streams - you don't want to use too many nested loops,
it may look like this:
allRules.stream()
.map(GetAllRules::getOptionsList)
.flatMap(Collection::stream)
.flatMap(option -> option.get(key).stream())
.forEach(System.out::println);
Related
I want to construct a chapter directory. My data structure is as follow.
private Map<String, ChapterPage> chapterPageRel;
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
public static class ChapterPage {
#ApiModelProperty(value = "page list")
private List<Integer> page;
#ApiModelProperty(value = "page image list")
private List<String> chapterImageId;
}
My database data is as follow.
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
#TableName(value = "tb_electronic_material_resource_rel")
public class ElectronicMaterialResourceRelEntity {
#TableId(value = "id", type = IdType.AUTO)
private Long id;
#TableField(value = "material_id")
private Long materialId;
#TableField(value = "chapter_image_id")
private String chapterImageId;
#TableField(value = "chapter_name")
private String chapterName;
#TableField(value = "page")
private Integer page;
}
I want to get each chapterName of the corresponding page Numbers and pictures, in fact, I get a strange map, as shown below.
List<ElectronicMaterialResourceRelEntity> materialResourceRelEntities = xxxx;
Map<String, Map<Integer, String>> collect =
materialResourceRelEntities
.stream()
.collect(Collectors.groupingBy(ElectronicMaterialResourceRelEntity::getChapterName, Collectors.toMap(ElectronicMaterialResourceRelEntity::getSort, ElectronicMaterialResourceRelEntity::chapterImageId)));
But I want to ask, how to collect for a class like Map<String,ChapterPage>.
A loop is probably better here, unless you need to collect to such ChapterPage objects in multiple places in your code or your input is already a stream and you want to avoid materializing it into a list first. Just to demonstrate how this could still be done, this is an example using a custom downstream Collector:
Map<String, ChapterPage> res = input.stream()
.collect(Collectors.groupingBy(ElectronicMaterialResourceRelEntity::chapterName,
Collector.of(
ChapterPage::new,
(c, e) -> {
c.getPage().add(e.page());
c.getChapterImage().add(e.chapterImageId());
},
(c1, c2) -> {
c1.getPage().addAll(c2.getPage());
c2.getChapterImage().addAll(c2.getChapterImage());
return c1;
}
)));
Getters and constructors differ from your code, I used a record for ElectronicMaterialResourceRelEntity and a POJO without annotation magic for ChapterPage in my test.
By "loop", I don't necessarily mean a traditional loop, but a somewhat less functional approach directly using a mutable HashMap:
Map<String, ChapterPage> res = new HashMap<>();
input.forEach(e -> {
ChapterPage c = res.computeIfAbsent(e.chapterName(), k -> new ChapterPage());
c.getPage().add(e.page());
c.getChapterImage().add(e.chapterImageId());
});
produces the same result in a less verbose way.
You can convert List to Json, and then convert Json to Map
so I have seen some similar questions to this but have been unable to apply their answers to my code and am wondering how to do this. So basically I have the following code (simplified):
public Map<String, List<String>> myFunction(String myApp) {
List<String> myIds = myService.getIds(myApp);
return myIds.stream()
.map(id -> {
final List<String> myObjects = myService.getListForId(id);
return new MyWrapper(id, myObjects);
}).collect(Collectors.toMap(a -> a.ID, a -> a.OBJECTS);
}
class MyWrapper {
public final String ID;
public final List<String> OBJECTS;
public MyWrapper(String id, List<String> objects) {
ID = id;
OBJECTS = objects;
}
}
I can't figure out how to access id in the Collectors function since the list has no gettable relation to the id so I created a wrapper class to store both values. Any ideas on a way to do this without the wrapper? Thanks
streams the ids via myService.getIds
then simply maps those ids to the list returned by the service (using a method reference).
Map<String, List<String>> map = myService.getIds(myApp).
stream().collect(Collectors.toMap(id->id, myService::getListForId));
class Item {
String oneTo
}
class Header {
String twoTo;
List <Item> items;
}
class HeaderFrom {
String oneFrom;
String twoFrom;
}
In the above example, I need to map the following scenarios using MapStruct. What is the best way to get this done?
oneFrom -> all the oneTo fields in the list
twoFrom -> twoTo
Thank you.
Can you try
#Mapping(source = "oneFrom", target = "items", qualifiedByName = "oneFromToList")
Header headerFromToHeader(HeaderFrom headerFrom);
In the same mapper class add a method
#Named("oneFromToList")
public static String oneFromToList(List<> input) {
// logic to map Item.oneTo = HeaderFrom.oneFrom
}
JSON
{
"type": {
"type1": {
"sub1": [
"sub1A": {
}
]
}
}
"type2": {
"type1": {
"sub1": [
"sub1A": {
}
]
}
}
}
I have Json like this , I am not getting how to create map for this, like
Map<String, Object> requestMap = new HashMap<>();
requestMap.get("type");
Inside type again create map containing sub data.
I didn't understand your question completely. But, from your statement, if you are trying to fetch json data into your class and that JSON data has recursive mapping, i.e., one object contains itself under its body. Then, I don't think you need HashMap to map this json into your class. You can use single Entity with a field of type of itself like employee-manager relationship. e.g.,
class Type {
private Type type;
private String otherField;
// constructors, setters, getters
}
Now, you can read values from type using the recursive functions.
According to what you have shared you can use:
Map <String, Map<String, Map<String, Set<Map<String, String>>>>>
Or to get more details concerning working with json objects you can look at: Query a JSONObject in java
{
"TC_01": {
"step": "TS01",
"keyword": "navigate",
"object": “search_fare"
}
"TC_02": {
"step": "TS02",
"keyword": "Verify text",
"object": “text_header_Traveler"
}
}
How will I achieve the following data structure using Multidimensional Arraylist or HashMap in Java? Please provide your suggesstion
make a class/type for
{ "step": "TS01", "keyword": "navigate", "object": “search_fare" }
Say YourClass
class YourClass{
String step,keyword,object; //type string is just example
...
}
then you need a map Map<String, YourClass>
If you look at your code you´ll finde something called "code smell" (repeated code). You have your own structure of three parameters that continue to repeat themselves: step, keyword and object. Just seeing that I suggest putting that in a class so as to have:
public class YourClass{
private String keyword;
private String step;
private String object;
//It´s your choice whether to have setters or have everything in through constructor
public String getKeyword(){
return this.keyword;
}
.... //continue with getters for step and object
}
Now you can have your regular structure of hashMap so as to have Map which means that they key for looking into your map will be a string "TC_01", "TC_02" and when you get YourClass returned, all you have to do is invoke .getKeyword() ... to get the rest of your information.
Example:
YourClass yourClassVariable = new YourClass();
yourClassVariable.setStep("TS01");
yourClassVariable.setKeyword("navigate");
yourClassVariable.setObject("search_fare");
Map<String,YourClass> mp=new HashMap<String, YourClass>();
// adding or setting elements in Map by put method key and value pair
mp.put("TC_01", yourClassVariable);
:)
Map<String, TCObject> = new HashMap<String, TCObject>;
Where, TCObject is a class that contains fields:
private String step;
private String keyword;
... etc ...
Hope this will help...
public class TC{
private String keyword;
private String step;
private String object;
//setters
//getters
}
TC tc=new TC()
tc.setStep("TS01")
tc.setKeyword("navigate");
tc.setObject("search_fare");
Map map=new HashMap();
map.put("TC_01",tc);