Как собрать несколько интерфейсов в Коллекцию в HK2?

У меня есть AbstractBinder, и я связываю несколько классов с одним и тем же интерфейсом. Допустим, я связываю Fish и Cat, которые реализуют интерфейс Animal.

Каков самый простой/правильный способ ввести их в bean-компонент, который принимает Collection<Animal> ?

PS: Spring имеет эквивалент просто @Autowire List<Animal>, а коллекция создается и заполняется Spring.


person Jan Zyka    schedule 01.12.2015    source источник


Ответы (2)


HK2 имеет IterableProvider<T>, как уже упоминалось здесь, в документации. Вы можете получить услугу по имени, по аннотацию квалификатора или просто перебирать их, так как это Iterable. Просто для удовольствия, вот тест.

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);  
    }
}

ОБНОВИТЬ

Для List<Service> (чтобы избежать HK2 InterablProvider) единственное, что я могу придумать, это использовать Factory и внедрить в него IterableProvider, а оттуда вернуть список. Например

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) {}
}

Да, это небольшая дополнительная работа.

person Paul Samsotha    schedule 01.12.2015
comment
Я вижу, большое спасибо. Не странно ли, что ваш pojo будет содержать IterableProvider<...>, специфичный для HK2? Например, если я пишу модульный тест, мне нужно было бы как-то издеваться над этим... - person Jan Zyka; 01.12.2015
comment
Ах, это расширяет Iterable ... тогда хорошо. Тем не менее, мне все еще не нравится конкретная ссылка на HK2. - person Jan Zyka; 01.12.2015
comment
Хотя дополнительная функциональность, такая как сужение выбора, это круто :D - person Jan Zyka; 01.12.2015
comment
Возможно, есть другой способ, но единственное, что я могу придумать, это если вы действительно не хотите использовать IterableProvider, это использовать Factory и внедрить туда IterableProvider и, в свою очередь, вернуть коллекцию. Но там вы теряете функциональность IterableProvider :-) - person Paul Samsotha; 01.12.2015
comment
Мы обсуждали, что можно разрешить людям просто использовать @Inject Iterable. Проблема в том, что в него может вмешиваться Factory, производящая Iterable. Тем не менее, я согласен, что было бы неплохо, чтобы pojo был полностью без ссылок на hk2. - person jwells131313; 01.12.2015
comment
Я только что встретил это. У меня есть параметр конструктора bean-компонента с IterableProvide, а в модульных тестах мне нужно предоставить mock. Это лишняя работа :) - person Jan Zyka; 02.12.2015
comment
Может быть, хелпер был бы хорош static <T> IterarableProvider<T>.of(T... elements) для тестов? - person Jan Zyka; 02.12.2015

В последней версии hk2 (2.4.0) вы можете

@Inject Iterable<Foo> foos;

Это позволяет вам хранить ваши pojo без каких-либо hk2 API.

Для получения дополнительной информации см.: Итерируемое внедрение

person jwells131313    schedule 05.01.2016
comment
Предполагается ли, что этот синтаксис Iterable<Foo> также работает для внедрения конструктора? - person Technetium; 02.03.2016
comment
Да. Если это не так, введите ошибку! - person jwells131313; 03.03.2016