I want to convert a list of DTOs into a deep nested map.
Source format:
[
Dto(validationType=BASIC, source=BASE, address=A4, error=Client is a required field.),
Dto(validationType=BASIC, source=BASE, address=A4, error=Client must be one of 'I', 'G' or 'W'.),
Dto(validationType=BASIC, source=BASE, address=B5, error=Individuals require First and Last Names.),
Dto(validationType=BASIC, source=BASE, address=D6, error=Individuals require First and Last Names.),
Dto(validationType=BASIC, source=BASE, address=J7, error=First is a required field.),
Dto(validationType=BASIC, source=BASE, address=L8, error=Last is a required field.),
Dto(validationType=BASIC, source=BASE, address=M9, error=Name is a required field.),
Dto(validationType=BASIC, source=BASE, address=N10, error=Status is a required field.),
Dto(validationType=BASIC, source=BASE, address=N10, error=Status must be one of 'A' or 'P'.),
Dto(validationType=BASIC, source=BASE, address=F16, error=Groups require a Group Name.)
]
Target format:
{
BASIC = {
BASE = {
A4 = [ "Client is a required field.", "Client must be one of 'I', 'G' or 'W'." ],
B5 = [ "Individuals require First and Last Names." ],
D6 = [ "Individuals require First and Last Names." ],
J7 = [ "First is a required field." ],
L8 = [ "Last is a required field." ],
M9 = [ "Name is a required field." ],
N10 = [ "Status is a required field." ],
N10 = [ "Status must be one of 'A' or 'P'." ],
F16 = [ "Groups require a Group Name." ]
}
}
}
This code snippet:
final Map<String, Map<String, Map<String, ArrayList<String>>>> collect =
dtoList.stream()
.collect(
Collectors.groupingBy(
Dto::getValidationType,
Collectors.groupingBy(
Dto::getSource,
Collectors.groupingBy(
Dto::getAddress,
Collectors.mapping(
Dto::getError,
Collectors.collectingAndThen(
Collectors.toSet(),
ArrayList::new))))));
produces this map:
{
BASIC = {
BASE = {
key -> D6 = [ "Individuals require First and Last Names."],
order -> B5 = [ "Individuals require First and Last Names.],
not -> A4 = [ "Client must be one of 'I', 'G' or 'W'.", "Client is a required field."], <- values' original order lost
preserved -> F16 = [ "Groups require a Group Name." ],
-> N10 = [ "Status must be one of 'A' or 'P'.", "Status is a required field." ],
-> M9 = [ "Name is a required field." ],
-> L8 = [ "Last is a required field." ],
-> J7 = [ "First is a required field." ]
}
}
}
The problems are:
You need to pass in the Supplier
mapFactory
to specify the type of Map
you wish to collect in (()->new TreeMap<>()
). Same in case of TreeSet
final TreeMap<String, TreeMap<String, TreeMap<String, TreeSet<String>>>> collect =
list.stream()
.collect(
groupingBy(
Dto::getValidationType,
TreeMap::new,
groupingBy(
Dto::getSource,
TreeMap::new,
groupingBy(
Dto::getAddress,
TreeMap::new,
Collectors.mapping(
Dto::getError,
Collectors.collectingAndThen(
Collectors.toSet(),
TreeSet::new)
)
)
)
)
);