0

I am probably wrong with terminology which doesn't help me to google the answer, but the question boils down to this:

I have a set of objects declared like this:

public interface ActivationService<T extends Activator> {
    T getActivator(Item item);
}

, so the set is declared like this:

Set<ActivationService>_activationServices = new HashSet<>();

I want to transform it into a map in order to lookup the appropriate "activation service" easier.

Map<Class<? extends Activator>, Set<ActivationService>> _actsCache = new HashMap<>();

Once I know how to get this T parameter from an object of a class, I will be able to do it. How do I get this from an object? The TypeVariable interface confuses me.

fedd
  • 880
  • 12
  • 39
  • 2
    I'm afraid you can't – Ward Dec 11 '19 at 10:32
  • 5
    `Set` You are using the raw type here btw. It should be `Set>` – Michael Dec 11 '19 at 10:32
  • 1
    I never used reflection myself but I think it is possible to achieve what you want with it. Check this quesiton: https://stackoverflow.com/questions/1901164/get-type-of-a-generic-parameter-in-java-with-reflection. However, I'd rather rethink the idea than use the reflection which might come really painful later on. Of course there is no point if you use raw types as Michael mentioned. – Amongalen Dec 11 '19 at 10:36

1 Answers1

1

Since your interface is ActivationService<T extends Activator> you'll probably want to use Set<ActivationService<? extends Activator>> as well.

That being said, you should already see that there's a problem getting the actual generic type of a service stored in the map/set because it could be any number of unrelated activators.

To fill the map you could do one of 2 things:

  1. Provide a Class<T> getActivatorClass() method in the interface and provide an appropriate implementation.
  2. Use reflection to get the actual generic type from any concrete implementation, i.e. this would work for MyActivatorService implements ActivatorService<MyActivator> but not MyActivatorService<T extends MyActivator> implements ActivatorService<T>. (Have a look here on one way how to do that which I've used for years now [there might be a more modern way now]: https://www.artima.com/weblogs/viewpost.jsp?thread=208860)

Note that when working with such a service you'd need to use some casts eventually because all you've got is a ActivatorService<? extends Activator>, i.e. there's no way to get the actual generic type at compiletime.

Thomas
  • 87,414
  • 12
  • 119
  • 157
  • I understand that there are unrelated activators, that's why I decided to group their services. I think my question is about how to use reflection. The `getActivatorClass` seems to return information already present in an implementation, like implying some extra work for the implementor... – fedd Dec 11 '19 at 10:48
  • @fedd yes it's some extra work but since reflection has its caveats using a method like that seems the safest way to go. You could mitigate the effort to some extent by providing a base class that uses reflection to provide an implementation of that method or maybe even a default implementation in the interface itself (although I've never tested this). – Thomas Dec 11 '19 at 11:07
  • 2
    @fedd information about type parameters may not be present in an implementation. For example, it's absent in `class GenericActivationService implements ActivationService`. – IlyaMuravjov Dec 11 '19 at 11:34