Google Guice - как автоматически добавить привязку - PullRequest
0 голосов
/ 21 октября 2018

В моем проекте я использую Google Guice для внедрения зависимостей.В моем классе Module, который расширяет AbstactModule Google Guice, у меня есть MapBinder, где ключ - это имя элемента, а значение - реализация моего интерфейса Item (например, FirstItem).

MapBinder<String, Item> itemMapBinder = MapBinder.newMapBinder(binder(), String.class, Item.class);
itemMapBinder.addBinding("FirstItem").to(FirstItem.class);

В настоящее время каждый разЯ добавляю новую реализацию Item (например, SecondItem). Мне также нужно добавить новую строку в Module, например,

itemMapBinder.addBinding("SecondItem").to(SecondItem.class);

Я использую эту карту элементов в моей ItemFactory.

public class ItemFactoryImpl implements ItemFactory {

    private final Map<String, Item> items;

    @Inject
    public ItemFactoryImpl(Map<String, Item> items) {
        this.items = items;
    }

    @Override
    public Item getItem(String name) {
        if (name == null) throw new IllegalArgumentException("Name cannot be null");
        return items.get(name);
    }
}

Я пытался найти способ автоматического добавления привязки для новой реализации интерфейса Item.Моя идея заключалась в том, чтобы использовать пользовательскую аннотацию, которая будет добавлена ​​в новую реализацию интерфейса Item, и каким-то образом изменить Module # configure, чтобы добавить привязку для всех классов с этой пользовательской аннотацией.Я закончил что-то вроде этого:

// cz.milanhlinak.guiceautobinding.item.AutoBindableItem.java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoBindableItem {
}

// cz.milanhlinak.guiceautobinding.item.Item.java
public interface Item {
}

// cz.milanhlinak.guiceautobinding.item.SecondItem.java
@AutoBindableItem
public class SecondItem implements Item {
}

// cz.milanhlinak.guiceautobinding.Module.java
public class Module extends AbstractModule {

    @Override
    protected void configure() {

        MapBinder<String, Item> itemMapBinder = MapBinder.newMapBinder(binder(), String.class, Item.class);
        new Reflections("cz.milanhlinak.guiceautobinding.item")
            .getTypesAnnotatedWith(AutoBindableItem.class)
            .stream()
            .filter(Item.class::isAssignableFrom)
            .forEach(typeAnnotatedWith -> itemMapBinder
                    .addBinding(typeAnnotatedWith.getSimpleName())
                    .to((Class<? extends Item>) typeAnnotatedWith)
            );

        bind(ItemFactory.class).to(ItemFactoryImpl.class).in(Singleton.class);
    }
}

Полный код доступен в моем GitHub репозитории .

Я хотел бы знать, есть ли лучшийспособ, как добиться автоматического связывания с Google Guice, потому что, как вы можете видеть, я в настоящее время использую дополнительную библиотеку - Reflections .

UPDATE

Другим вариантом может быть использование Google Guava вместо Reflections

public class Module extends AbstractModule {

    @Override
    protected void configure() {

        MapBinder<String, Item> itemMapBinder = MapBinder.newMapBinder(binder(), String.class, Item.class);

        ClassPath classPath;
        try {
            classPath = ClassPath.from(Thread.currentThread().getContextClassLoader());
        } catch (IOException e) {
            throw new RuntimeException("Unable to read class path resources", e);
        }

        ImmutableSet<ClassPath.ClassInfo> topLevelClasses = classPath.getTopLevelClassesRecursive("cz.milanhlinak.guiceautobinding.item");
        topLevelClasses.stream()
                .map(ClassPath.ClassInfo::load)
                .filter(clazz -> clazz.isAnnotationPresent(AutoBindableItem.class) && Item.class.isAssignableFrom(clazz))
                .forEach(clazz -> itemMapBinder
                        .addBinding(clazz.getSimpleName())
                        .to((Class<? extends Item>) clazz));

        bind(ItemFactory.class).to(ItemFactoryImpl.class).in(Singleton.class);
    }
}

1 Ответ

0 голосов
/ 22 октября 2018

Вы не делаете ничего плохого.

В использовании Reflections нет ничего плохого.Этот инструмент превосходен и выполняет ту работу, которую вы хотите.

У Guice нет инструмента обнаружения, поэтому не существует способа "по умолчанию" делать то, что вы хотите, только в Guice.

Если вы хотитечтобы использовать что-то еще, кроме Reflections, вы можете использовать java.util.ServiceLoader, но ServiceLoader не является действительно дружественным к Guice, потому что оно автоматически создает экземпляры, но вы обычно используете Guice, потому что хотите, чтобы оно создавало экземпляры для вас вместо того, чтобы позволять другомуФреймворк сделает это за вас.

Альтернатива использования Classpath в Guava также имеет смысл, но Reflections намного мощнее, потому что вы также можете загружать классы не в вашем пути к классам.

Нижняя строка, вы уже сделали лучший выбор.

...