Why does this work:
private List<Optional<Event>> createEventsStartingWith(List<Long> forwardIds, int startAt, final AnnouncementUpdatedEventPayload beforeChanges) {
List<Optional<Event>> announcementDeletedAppEvents = new ArrayList<>();
for (Long forwardId : forwardIds.subList(startAt, forwardIds.size())) {
announcementDeletedAppEvents.add(Optional.of(new AnnouncementDeletedAppEvent(forwardId, eventMapper.mapToNotificationPayload(beforeChanges))));
}
return announcementDeletedAppEvents;
}
but this doesn't work:
compilation error:
Required type: List<Optional<Event>>
Provided: List<Optional<AnnouncementDeletedAppEvent>>
private List<Optional<Event>> createEventsStartingWith(List<Long> forwardIds, int startAt, final AnnouncementUpdatedEventPayload beforeChanges) {
return IntStream.range(forwardIds.indexOf(startAt), forwardIds.size())
.mapToObj(forwardId -> Optional.of(new AnnouncementDeletedAppEvent(forwardId, eventMapper.mapToNotificationPayload(beforeChanges))))
.toList();
}
where:
public class AnnouncementDeletedAppEvent extends Event{
long Id;
AnnouncementPayload payload;
}
This is because Generics are invariant in Java.
Let's look at the expression you are returning:
IntStream.range(forwardIds.indexOf(startAt), forwardIds.size())
.mapToObj(forwardId -> Optional.of(new AnnouncementDeletedAppEvent(forwardId, eventMapper.mapToNotificationPayload(beforeChanges))))
.toList();
Specifically, the mapToObj
method will give you a Stream<AnnouncementDeletedAppEvent>
and not a Stream<Event>
because javac
sees that it will always be an Optional<AnnouncementDeletedAppEvent>
(instead of an Optional<Event>
) and it tries to find the most general type and it does not propagate type information backwards through methods.
Then, toList()
converts the result to a List<Optional<AnnouncementDeletedAppEvent>>
. Since generics are invariant, a List<Optional<AnnouncementDeletedAppEvent>>
is not a List<Optional<Event>>
.
You can fix this issue by telling Java you just want events using an additional type paramer (you can explicitely the type used in Optional.of
) by adding <Event>
before the of
(Optional.<Event>of(...)
):
return IntStream.range(forwardIds.indexOf(startAt), forwardIds.size())
.mapToObj(forwardId -> Optional.<Event>of(new AnnouncementDeletedAppEvent(forwardId, eventMapper.mapToNotificationPayload(beforeChanges))))
.toList();
Alternatively, you can cast the AnnouncementDeletedAppEvent
to an Event
before calling Optional.of
:
return IntStream.range(forwardIds.indexOf(startAt), forwardIds.size())
.mapToObj(forwardId -> Optional.of((Event) new AnnouncementDeletedAppEvent(forwardId, eventMapper.mapToNotificationPayload(beforeChanges))))
.toList();