Java preserve generic type in map of wildcard upper bound

392 views Asked by At

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

There are 1 answers

3
syntagma On

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);
    }