В моем проекте я использую 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);
}
}