问题
I have my AbstractBinder
and I bind several classes with the same interface. Let's say I bind Fish
and Cat
which both implement Animal
interface.
What is the easiest/proper way of injecting them into a bean which takes Collection<Animal>
?
PS: Spring has equivalent in simply @Autowire List<Animal>
and the collection is created and populated by Spring.
回答1:
HK2 has IterableProvider<T>, as mentioned here in the documentation. You can get the service by name, by qualifier annotation, or just iterate over them, as it's an Iterable
. Just for fun, here is a test.
public class IterableProviderTest {
public static interface Service {}
public static class ServiceOne implements Service {}
@QualAnno
public static class ServiceTwo implements Service {}
@Qualifier
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public static @interface QualAnno {
public static class Instance
extends AnnotationLiteral<QualAnno> implements QualAnno {
public static QualAnno get() {
return new Instance();
}
}
}
public class Binder extends AbstractBinder {
@Override
protected void configure() {
bind(ServiceOne.class).to(Service.class).named("one");
bind(ServiceTwo.class).to(Service.class).qualifiedBy(QualAnno.Instance.get());
}
}
@Inject
private IterableProvider<Service> services;
@Test
public void test_IterableProvider() {
ServiceLocator locator = ServiceLocatorUtilities.bind(new Binder());
locator.inject(IterableProviderTest.this);
assertEquals(2, services.getSize());
Service serviceOne = services.named("one").get();
assertTrue(serviceOne instanceof ServiceOne);
Service serviceTwo = services.qualifiedWith(QualAnno.Instance.get()).get();
assertTrue(serviceTwo instanceof ServiceTwo);
}
}
UPDATE
For a List<Service>
(to avoid HK2 InterablProvider), the only think I can think of is to use a Factory
and inject the IterableProvider
into it, and from there return the list. For example
public class Binder extends AbstractBinder {
@Override
protected void configure() {
...
bindFactory(ListServiceFactory.class).to(new TypeLiteral<List<Service>>(){});
}
}
public static class ListServiceFactory implements Factory<List<Service>> {
@Inject
private IterableProvider<Service> services;
@Override
public List<Service> provide() {
return Lists.newArrayList(services);
}
@Override
public void dispose(List<Service> t) {}
}
Yeah it's a little bit of extra work.
回答2:
In the latest release of hk2 (2.4.0) you can
@Inject Iterable<Foo> foos;
That allows you to keep your pojo's without any hk2 API in them.
For more information see: Iterable Injection
来源:https://stackoverflow.com/questions/34021935/how-to-collect-several-interfaces-into-a-collection-in-hk2