[英]Guice multiple annotations
I have an interface called StatsStore
. 我有一个名为
StatsStore
的接口。 I have 2 implementations of this store. 我有2个这个商店的实现。 An in-memory and an SQL implementation called
InMemoryStatsStore
and SqlStatsStore
. 内存和SQL实现,称为
InMemoryStatsStore
和SqlStatsStore
。 In order to inject them I've create 2 annotations @InMemoryStore
and @SqlStore
. 为了注入它们,我创建了2个注释
@InMemoryStore
和@SqlStore
。 the injections are: 注射剂是:
bind(StatsStore.class)
.annotatedWith(InMemoryStore.class)
.to(InMemoryStatsStore.class);
bind(StatsStore.class)
.annotatedWith(SqlStore.class)
.to(SqlStatsStore.class);
Now I want to add a new layer of annotation to separate between InMemoryStringStore
and InMemoryNumberStore
but I can't add more than one annotation to the binding lines eg the following does not compile: 现在我想添加一个新的注释层来分隔
InMemoryStringStore
和InMemoryNumberStore
但是我不能在绑定行中添加多个注释,例如以下内容不能编译:
bind(StatsStore.class)
.annotatedWith(InMemoryStore.class)
.annotatedWith(NumberStoreAnnotation.class) // using named doesn't work as well
.to(InMemoryNumberStore.class);
How can I add more than one annotation without using a single named one which would be quite complicated the more layers I add to it? 如何在不使用单个命名的注释的情况下添加多个注释,如果我添加的层越多,这将更复杂?
The other solution I had in mind is Injecting twice: 我想到的另一个解决方案是注入两次:
bind(StatsStore.class)
.annotatedWith(InMemoryStore.class)
.to(InMemoryStatsStore.class);
bind(InMemoryStatsStore.class)
.annotatedWith(NumberStoreAnnotation.class)
.to(InMemoryNumberStore.class);
Thanks all. 谢谢大家。
As Amit said, you can't have more than one @BindingAnnotation apply to any given injection. 正如Amit所说,你不能有多个@BindingAnnotation适用于任何给定的注入。 Internally, Guice works like a
Map<Key, Provider>
where a Key is a possibly-parameterized class with an optional single annotation instance. 在内部,Guice的工作方式类似于
Map<Key, Provider>
,其中Key是可能参数化的类,带有可选的单个注释实例。 However, because these are instances , you're welcome to create your own instantiable annotation that works the way Named
works. 但是,因为这些是实例 ,所以欢迎您创建自己的可实例化注释 ,其工作方式与
Named
。
@Inject @InMemoryStore(NUMBER) StatsStore inMemoryNumberStore;
@Inject @SqlStore(STRING) StatsStore sqlStringStore;
// or
@Inject @Store(dataType=NUMBER, backend=SQL) sqlNumberStore;
The annotation must have the fields defined like so. 注释必须具有如此定义的字段。 (If you have one element named
value
, you can omit the property name per JLS 9.7.3 .) Equal annotations are defined as in the Annotation.equals
docs . (如果您有一个名为
value
元素,则可以省略每个JLS 9.7.3的属性名称。)等号注释在Annotation.equals
文档中定义。
public enum DataType { NUMBER, STRING; }
public enum Backend { SQL, IN_MEMORY; }
@BindingAnnotation @Retention(SOURCE) @Target({ FIELD, PARAMETER, METHOD })
public @interface Store {
DataType dataType();
Backend backend();
}
That works nicely for @Provides
, when you can invoke the annotation the same way you inject it, but how can you create a factory method for instances like Names.named
? 这对于
@Provides
,当你可以像注入它一样调用注释时,但是如何为Names.named
这样的实例创建工厂方法? For that, you'll need to do one of the following: 为此,您需要执行以下操作之一:
equals
and hashCode
. equals
和hashCode
正确实现。 Note that the hashCode
contract is much stricter than for Object
, but you can get compatible implementations from Apache annotation utils or similar libraries. hashCode
契约比Object
更严格 ,但您可以从Apache注释工具或类似库获得兼容的实现。 equals
and hashCode
implementations for arbitrary subclasses. equals
和hashCode
实现。 @Qualifier
annotations work the same way in other JSR-330 compatible dependency injection frameworks, though, including Dagger.) @Qualifier
注释在其他JSR-330兼容依赖注入框架中的工作方式相同,但包括Dagger。) If the above seems a little complicated, or if you want more complex logic than Guice's map-based implementation can accomplish, one alternative is to add a layer of indirection that you control: 如果上面看起来有点复杂,或者如果你想要比Guice基于地图的实现更复杂的逻辑,一种方法是添加一个你控制的间接层:
public class StoreStore {
@Inject Provider<InMemoryNumberStore> inMemoryNumberStoreProvider;
// ...
// You can also inject the Injector to call getInstance with a class literal.
public StatsStore getStore(DataType dataType, Backend backend) {
// This can also be a switch or any other sort of lookup, of course.
if (dataType == NUMBER && backend == IN_MEMORY) {
return inMemoryNumberStoreProvider.get();
} // ...
}
}
You can't do that : 你不能这样做 :
@BindingAnnotation
tells Guice that this is a binding annotation.@BindingAnnotation
告诉Guice这是一个绑定注释。 Guice will produce an error if ever multiple binding annotations apply to the same member .如果多个绑定注释适用于同一成员,Guice将产生错误 。
You could use named bindings instead, or you should consider redesigning your solution. 您可以改为使用命名绑定,或者应该考虑重新设计解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.