1

Starting with these classes

public class Event {

   private EventType eventType;

   public EventType getEventType() {
       return eventType;
   }

   public void setEventType(EventType eventType) {
       this.eventType = eventType;
   }
}

public class OneEvent extends Event {

   public OneEvent() {
       setEventType(EventType.ONE);
   }
}


public interface EventProcessor<T extends Event> {

   Stream<? extends Event> process(T element);

   EventType getType();

}

public enum EventType {
    ONE, TWO
}

I have created OneEventProcessor and TwoEventProcessor that implement it.

public class OneEventProcessor implements EventProcessor<OneEvent> {

@Override
public Stream<? extends Event> process(OneEvent element) {
    return null;
}

@Override
public EventType getType() {
    return EventType.ONE;
}

}

In another class I want to add them to a map type->processor and then retrieve and use.

Map<EventType, EventProcessor<? extends Event>> map = new HashMap<>();
OneEventProcessor oep = new OneEventProcessor();
map.put(oep.getType(), oep);

public Stream<? extends Event> process(Event event) {
    return map.get(event.getEventType()).process(event);
}

This is not working because the map will retrieve a EventProcessor< ? extends Event > that expects a capture of < ? extends Event > in process method.

Any way I can work around this?

1 Answers1

0

This can be achieved with few changes in your code.

  1. Use OneEvent that you parametrize OneEventProcessor with:

    class OneEventProcessor implements EventProcessor<OneEvent> {
    
         @Override
         public Stream<OneEvent> process(OneEvent element) {
             return null;
         }
    
         @Override
         public EventType getType() {
             return EventType.ONE;
         }
     }
    
  2. Use properly T that you parametrize EventProcessor with:

    interface EventProcessor<T extends Event> {
    
        Stream<T> process(T element);
    
        EventType getType();
    }
    
  3. Add proper type bounds to your process() method (I included map initialisation in the body of that method for brevity):

    public <T extends Event> Stream<T> process(T event) {
        Map<EventType, EventProcessor<T>> map = new HashMap<>();
        EventProcessor oep = new OneEventProcessor();
        map.put(oep.getType(), oep);
        return map.get(event.getEventType()).process(event);
    }
    
syntagma
  • 23,346
  • 16
  • 78
  • 134
  • Thank you for your answer. OneEvent processor will process a OneEvent and return a Stream of Event (not a Stream of OneEvent). I am trying to implement some sort of upcasting layer in an application using an event store. – Georgian Benetatos Oct 15 '18 at 21:35
  • @GeorgianBenetatos in that case change signature of `process()` in `EventProcessor` to `Stream process(T element);`, then change to `public Stream process(OneEvent element)` in `OneEventProcessor` and `public Stream process(T event)` in the last method. I think that will get you the desired effect. – syntagma Oct 15 '18 at 21:39
  • 1
    Tried it but did not work. The map has to be initialised outside the process method. The map has to be already there when it starts processing, so you cannot bind it to T in process (last method) – Georgian Benetatos Oct 15 '18 at 21:46