I have the following Event object definition:
@Data
class Event{
private int referenceId;
private int messageId;
private String comment;
public Event(int referenceId, int messageId, String comment) {
this.referenceId = referenceId;
this.messageId = messageId;
this.comment = comment;
}
}
I am given the following input:
EventDTO event = new Event(1, 1, "comment");
EventDTO event1 = new Event(1, 2, "comment");
EventDTO event3 = new Event(1, 3, "comment");
EventDTO event4 = new Event(1, 4, "comment");
List<EventDTO> events = List.of(event, event1, event3, event4);
All the input I have will have the same data except the messageId property. Since I need to transform this data into another object called EventMessages:
@Data
class ChangeReason{
private int id;
private String description;
public ChangeReason(int id, String description) {
this.id = id;
this.description = description;
}
}
@Data
class EventMessages{
private int referenceId;
private String comment;
private List<ChangeReason> reasons;
public EventMessages(int referenceId, String comment, List<ChangeReason> reasons) {
this.referenceId = referenceId;
this.comment = comment;
this.reasons = reasons;
}
}
The ChangeReason id is the messageId of Event class
The problem is that N objects of Event need to be mapped into just 1 object of EventMessages. I am sure that all properties among incoming Events are going to be the same expect for the messageId.
I do not really like the solution of getting the first object like this:
List<ChangeReason> reasons = events.stream().map(event -> new ChangeReason(event.getMessageId(), "")).collect(Collectors.toList());
EventMessages eventMessages = new EventMessages(events.get(0).getReferenceId(), events.get(0).getComment(), reasons);
I dont really like this implementation and i was wondering if there is a better way of achiveing this.
I am trying to get the following scenario of data structure: Map<Event,List< Integer> > eventsWithMessages
So the key Event will be the object from I will retreive the comment and referenceId information which is common among all objects and the value would be the Collected different List of messageIds of events List I am trying to get this using lambdas and streams
Doing this wouldn't work:
Map<Event, List<Integer>> eventMessages = events.stream().collect
(Collectors.groupingBy(e -> e, Collectors.mapping(e -> e.getMessageId(), Collectors.toList())));
Since the groupingBy key comparison is done by the object and the property of messageId is different...
Found a solution. I started working with mergeOperators and I thought this could be the solution for this problem I had in the past. I leave the code:
First I needed to implement an EqualHashCode for the Event class:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Event)) return false;
Event event = (Event) o;
return getReferenceId() == event.getReferenceId() && getComment().equals(event.getComment());
}
@Override
public int hashCode() {
return Objects.hash(getReferenceId(), getComment());
}
Then i used this code on MergeFunction toMap()
Map<Event, List<Integer>> eventsWithMessages = events.stream()
.collect(Collectors.toMap(
event -> event,
event -> Collections.singletonList(event.getMessageId()),
(list1, list2) -> { // Here is the magic
List<Integer> mergedList = new ArrayList<>(list1);
mergedList.addAll(list2);
return mergedList;
}
));