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.

5 Answers 5

1

Declare you map as:

Map<Class<T extends IEntity>, IEntityHandler> handlers.
Sign up to request clarification or add additional context in comments.

1 Comment

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.
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.

1 Comment

You are absolutely right! Thanks for your detailed explanation.
0
private Map<? extends IEntity, ? extends IEntityHandler> handlers;

2 Comments

He needs to map Class objects to handlers, not instances of IEntity to handlers.
Here I get this build error: The method handle(capture#1-of ? extends IEntity) in the type IEntityHandler<capture#1-of ? extends IEntity> is not applicable for the arguments (IEntity)
0
private Map<Class<? extends IEntity>, ? extends IEntityHandler> handlers;

2 Comments

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.
Same here the build error: The method handle(capture#1-of ? extends IEntity) in the type IEntityHandler<capture#1-of ? extends IEntity> is not applicable for the arguments (IEntity)
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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.