2

Instead of using if/else I'd like to use a map to get a concrete implementation.

I'd like to use generics to declare a specific entity handler witch handles a specific entity but I have the problem that the handler just accepts extensions of my entity interface. The code looks like this:

private Map<Class<IEntity>, IEntityHandler> handlers;

public void callingMethod(IModel model) {
  for (IEntity entity : model.getObjects()) {
    // handle accepts just IDevice and not IEntity !
    handlers.get(entity).handle(entity);
  }
}

public interface IEntityHandler<T extends IEntity> {
  handle(T entity);
}

public class DeviceHandler implements IEntityHandler<IDevice> {
  @Override
  public void handle(IDevice deviceEntity) {
    // do something
  }
}

How can I get my handle method that it takes IEntity's? IDevice extends from IEntity.

myborobudur
  • 4,385
  • 8
  • 40
  • 61

5 Answers5

1

Declare you map as:

Map<Class<T extends IEntity>, IEntityHandler> handlers.
Tarcísio Júnior
  • 1,239
  • 7
  • 15
  • 1
    I don't think he has a type parameter `T` in the class that has the map as field. This wouldn't be possible since the map should be capable of containing handlers for a variety of different classes. That's the whole purpose. – G_H Oct 26 '11 at 12:44
1

First of all, you'll need to change this line...

handlers.get(entity).handle(entity);

to this...

handlers.get(entity.getClass()).handle(entity);

Then, like the others said, it'd be best to change the Class<IEntity> type parameter of your map to Class<? extends IEntity>, since you want to map concrete classes to handlers.

If you do it like that, you won't get an error. Only a warning because the IEntityHandler type parameter in your map is a raw type. But if you try to change it to ? extends IEntityHandler or IEntityHandler<? extends IEntity>, you will get a compilation error on assigning or populating the Map.

So I suggest you just make the above to changes (getClass() and Class<? extends IEntity>), then simply suppress the warning with an annotation. As long as your Map is properly populated with the right handler for the right class, you won't run into trouble.

G_H
  • 11,739
  • 3
  • 38
  • 82
0
private Map<? extends IEntity, ? extends IEntityHandler> handlers;
kgautron
  • 7,915
  • 9
  • 39
  • 60
  • He needs to map `Class` objects to handlers, not instances of `IEntity` to handlers. – G_H Oct 26 '11 at 12:46
  • Here I get this build error: The method handle(capture#1-of ? extends IEntity) in the type IEntityHandler is not applicable for the arguments (IEntity) – myborobudur Oct 26 '11 at 15:43
0
private Map<Class<? extends IEntity>, ? extends IEntityHandler> handlers;
Mikel
  • 450
  • 2
  • 8
  • 1
    This will lead to issues when trying to actually place handlers in the map. Using `? extends ...` for a type param in a collection declaration usually doesn't work well when you intend to directly add entries to the collection for the reasons [explained here](http://download.oracle.com/javase/tutorial/java/generics/wildcards.html). – G_H Oct 26 '11 at 12:50
  • Same here the build error: The method handle(capture#1-of ? extends IEntity) in the type IEntityHandler is not applicable for the arguments (IEntity) – myborobudur Oct 26 '11 at 15:44
0

I think what you're heading towards is a (deep breath) typesafe hetereogeneous container. However, because the objects you want to store are themselves generic, you need to use super type tokens.

I think you then need to introduce and then tame a wildcard by rewriting the top loop like this:

for (IEntity entity: model.getObjects()) {
    handle(entity);
}

private <T extends IEntity> handle(T entity) {
    IEntityHandler<T> handler = ... get appropriate handler from THC ...
    handler.handle(entity);
}

I'm not sure about this, though. This is a pretty rough sketch.

Community
  • 1
  • 1
Tom Anderson
  • 46,189
  • 17
  • 92
  • 133