简体   繁体   English

Guice多个注释

[英]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实现,称为InMemoryStatsStoreSqlStatsStore 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: 现在我想添加一个新的注释层来分隔InMemoryStringStoreInMemoryNumberStore但是我不能在绑定行中添加多个注释,例如以下内容不能编译:

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: 为此,您需要执行以下操作之一:

  1. Create an anonymous implementation , with accessors for each attribute as well as correct implementations of equals and hashCode . 创建一个匿名实现 ,包含每个属性的访问器以及equalshashCode正确实现。 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注释工具或类似库获得兼容的实现。
  2. Use AnnotationLiteral , which provides equals and hashCode implementations for arbitrary subclasses. 使用AnnotationLiteral ,它为任意子类提供equalshashCode实现。
  3. Use Google Auto or a similar code generator to generate code for a compatible implementation for you. 使用Google Auto或类似的代码生成器为您生成兼容实现的代码。 Familiarity with this type of solution is particularly useful for Android and other memory-constrained environments for which reflection is slow, though such environments usually preclude you from using Guice. 熟悉这种类型的解决方案对于Android和其他内存受限的环境特别有用,但反射速度很慢,但这种环境通常会阻止您使用Guice。 ( @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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM