vendredi 12 mai 2017

How to determine the type parameter of Bean implementing generic FunctionalInterface with a lambda?

I have a generic functional interface:

@FunctionalInterface
public interface Feeder<T extends Animal> {
  void feed(T t);
}

And a couple of beans implementing that interface for different Animal subclasses.

@Configuration
public class Config {
  @Bean
  public Feeder<Dog> dogFeeder() {
    return dog -> dogService.feedDog(dog);
  }
  @Bean
  public Feeder<Cat> catFeeder() {
    return cat -> catService.feedCat(cat);
  }
}

Now a service class has been injected with these beans and is given an instance of Animal. How can it determine the correct Feeder bean to use?

@Service
public class PetStore {
  @Autowired
  private List<Feeder<? extends Animal> feeders;

  private void feed(Animal animal) {
    //TODO: How to determine the correct feeder from feeders?
    Feeder<? extends Animal> correctFeeder = ....
    correctFeeder.feed(animal);
  }
}

I initially thought I'd be alright using How to get a class instance of generics type T but am running into issues that the bean is implemented using a lambda function and the type returned when I call GenericTypeResolver.resolveTypeArgument(feeder.getClass(), Feeder.class) is Animal(!)

I then tried to use an anonymous subclass for the beans. Then GenericTypeResolver can determine the specific type of Animal each Feeder will feed. But IntelliJ is screaming at me I should create a lambda for it and so will other people using the PetStore.

I added a getAnimalClass() method to the Feeder interface. IntelliJ stops screaming. It does feel very clumsy though.

The first time I get an Animal instance of a class I've not yet fed, I try/catch to use each candidate feeder, until I find one that works. Then I remember the result for future use. Also feels very clumsy.

So my question: What is the proper way to do this?





Aucun commentaire:

Enregistrer un commentaire