I'm having problems because my select is returning several lines of result due to an Options object that has several different options, and I needed to group this result in java.
I have the parent class which is the QuestionEventDTO:
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class QuestionEventDTO {
public Long id;
public QuestionDTO question;
public List<QuestionDTO> questions;
}
And I have the daughter class:
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class QuestionDTO {
public Long id;
public OptionDTO option;
public List<OptionDTO> options;
}
And I have the granddaughter class:
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class OptionDTO {
public Long id;
public String description;
}
After hitting the procedure, I set the response fields:
public class QuestionEventMapper implements RowMapper<QuestionEventDTO> {
@Override
public QuestionEventDTO mapRow(ResultSet rs, int rowNum) throws SQLException {
QuestionEventDTO dto = new QuestionEventDTO();
dto.setId(rs.getLong(1));
dto.setQuestion(new QuestionDTO(rs.getLong(2), new QuestionOptionDTO(rs.getLong(3), rs.getString(4)), null));
return dto;
}
}
QuestionEventDTO [id=1, question= QuestionDTO [id=1, option= OptionDTO [id=1, description="Are you Dev?"], options = []], questions =[]]
QuestionEventDTO [id=1, question= QuestionDTO [id=1, option= OptionDTO [id=2, description="What's rating?"], options = []], questions =[]]
QuestionEventDTO [id=2, question= QuestionDTO [id=2, option= OptionDTO [id=3, description="What's your dog's name?"], options = []], questions =[]]
QuestionEventDTO [id=2, question= QuestionDTO [id=2, option= OptionDTO [id=4, description="Are you Dev?"], options = []], questions =[]]
But I would like it to stay like this:
QuestionEventDTO [id=1, question= null, questions = QuestionDTO [id=1, option= null, options = [OptionDTO [id=1, description="Are you Dev?"], OptionDTO [id=2, description="What's rating?"]]]]
QuestionEventDTO [id=2, question= null, questions = QuestionDTO [id=2, option= null, options = [OptionDTO [id=3, description="What's your dog's name?"], OptionDTO [id=4, description="Are you Dev?"]]]]
I don't have much experience in lambda, I would like a solution to this problem, could someone help me?
I'll give it a try.
WARNING | Beware that this is only a POC and not good readable code.
What you need is a method, that takes a List<QuestionEventDTO>
and transforms it to another List<QuestionEventDTO>
.
It is possible to do it with streams and nested streams in the map-methods.
Here is the steps this streams will take:
QuestionDTO
by the ID of the QuestionEventDTO
's
List<QuestionEventDTO>
Map<Long, List<QuestionEventDTO>>
Map<Long, List<QuestionDTO>
Map<Long, List<QuestionEventDTO>>
Map<Long, Map<Long, List<QuestionDTO>>>
QuestionDTO
to a Map<Long, OptionDTO>
Map<Long, Map<Long, List<QuestionDTO>>>
Map<Long, Map<Long, Map<Long, OptionDTO>>>
QuestionEventDTO
where the Lists are filled. Here is what the code would look like (heavy usage of Collectors.groupingBy
and Collectors.toMap
):
private static List<QuestionEventDTO> transform(List<QuestionEventDTO> events) {
//Step1
Map<Long, List<QuestionEventDTO>> groupedByQuestionEventId = events.stream()
.collect(Collectors.groupingBy(QuestionEventDTO::getId));
//Step 2
Map<Long, Map<Long, List<QuestionDTO>>> alsoGroupedQuestionID = groupedByQuestionEventId
.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey,
e -> e.getValue().stream()
.map(v -> v.getQuestion())
.collect(Collectors.groupingBy(QuestionDTO::getId)))
);
//Step 3
Map<Long, Map<Long, Map<Long, OptionDTO>>> alsoGroupedByOptionID = alsoGroupedQuestionID
.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey,
e -> e.getValue()
.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey,
v -> v.getValue().stream()
.map(QuestionDTO::getOption)
.collect(Collectors.toMap(OptionDTO::getId, t -> t))))));
//Step 4
List<QuestionEventDTO> transformedBack = alsoGroupedByOptionID.entrySet().stream()
.map(e -> {
QuestionEventDTO eventDTO = new QuestionEventDTO();
eventDTO.setId(e.getKey());
List<QuestionDTO> questions = e.getValue().entrySet().stream()
.map(q -> {
QuestionDTO questionDTO = new QuestionDTO();
questionDTO.setId(q.getKey());
questionDTO.setOptions(new ArrayList<>(q.getValue().values()));
return questionDTO;
}).collect(Collectors.toList());
eventDTO.setQuestions(questions);
return eventDTO;
})
.collect(Collectors.toList());
return transformedBack;
}
Of course you don't need the variables for each step and you also could combine step 2 and 3. Then the code would look like this (not very readable):
private static List<QuestionEventDTO> transformShorter(List<QuestionEventDTO> events) {
return events.stream()
.collect(Collectors.groupingBy(QuestionEventDTO::getId))
.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey,
e -> e.getValue().stream()
.map(QuestionEventDTO::getQuestion)
.collect(Collectors.groupingBy(QuestionDTO::getId))
.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey,
q -> q.getValue().stream()
.map(QuestionDTO::getOption)
.collect(Collectors.toList()))))
)
.entrySet().stream()
.map(e -> {
QuestionEventDTO eventDTO = new QuestionEventDTO();
eventDTO.setId(e.getKey());
List<QuestionDTO> questions = e.getValue().entrySet().stream()
.map(q -> {
QuestionDTO questionDTO = new QuestionDTO();
questionDTO.setId(q.getKey());
questionDTO.setOptions(q.getValue());
return questionDTO;
}).collect(Collectors.toList());
eventDTO.setQuestions(questions);
return eventDTO;
})
.collect(Collectors.toList());
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.