【问题标题】:What is @AutoAnnotation for? How could it be used?@AutoAnnotation 有什么用?怎么可能使用?
【发布时间】:2019-10-07 01:55:12
【问题描述】:

https://dagger.dev/multibindings.html,我读到了@AutoAnnotation。它引用了https://github.com/google/auto/blob/master/value/src/main/java/com/google/auto/value/AutoAnnotation.java

也有提到 https://github.com/google/auto/blob/57dfad360306619a820e6aae4a14a1aa67c29299/value/userguide/howto.md#annotation

我读过它,无法理解它。

我设法从我的 Android 代码中使用

implementation 'com.google.auto.value:auto-value:1.5.2'
kapt 'com.google.auto.value:auto-value:1.5.2'

还有

android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true

但我不明白如何使用它。有什么好的使用教程吗?

【问题讨论】:

标签: java android annotations dagger-2


【解决方案1】:

AutoAnnotation 自动生成一个类,该类实现注解接口的方式与 JDK 相同。

匕首映射键

当通过 Dagger 使用自定义注解作为其键的 Multibindings 映射时,Dagger 将使用注解实例本身作为键将实例 T 或 Provider Provider<T> 安装到返回的映射中。为了更清楚地说明这一点:

@MapKey
@interface YourAnnotation {
  String foo();
}

@Provides @YourAnnotation(foo="bar") YourClass getYourClassForBar() { /* ... */ }

// Dagger will create a multibinding that would allow you to inject this:
@Inject Map<YourAnnotation, YourClass> map;

如果这里唯一重要的是foo,您还可以使用unwrapKeys 使映射由String 而不是YourAnnotation 键控,但假设您希望这样做,因为您希望YourAnnotation 将来有多个值.但是YourAnnotation 的实现是从哪里来的,你应该如何在地图上调用get

运行时注解

当您注释 Java 元素(通常是类、方法或字段)时,Java 将返回该类注释的特定实现。来自Java tutorial

@interface ClassPreamble {
   String author();
   String date();
   int currentRevision() default 1;
   String lastModified() default "N/A";
   String lastModifiedBy() default "N/A";
   // Note use of array
   String[] reviewers();
}

// [...]

@ClassPreamble (
   author = "John Doe",
   date = "3/17/2002",
   currentRevision = 6,
   lastModified = "4/12/2004",
   lastModifiedBy = "Jane Doe",
   // Note array notation
   reviewers = {"Alice", "Bob", "Cindy"}
)
public class Generation3List extends Generation2List {/* ... */}

在这种用法中,Generation3List 有一个 ClassPreamble 类型的 Annotation。如果注解在运行时保留(即 ClassPreamble 本身是annotated with @Retention(RUNTIME)),您可以通过Generation3List.class.getAnnotations()Generation3List.class.getAnnotation(ClassPreamble.class) 获取它。 (也有声明的对应物以不同的方式处理超类注解。)

一旦获得 ClassPreamble 的实例,就可以使用 author()date() 等方法从类中检索数据。但是,ClassPreamble 充当接口,并且该注释的实现在 VM 内部。这使得在运行时创建您自己的任意 ClassPreamble 实例变得更加困难。

符合注释的实现

因为 YourAnnotation 和 ClassPreamble 是接口,您可以只创建一个实现。但是,与 VM 的实现相比,该实现不太可能具有匹配的 equalshashCode 实现,因为 JRE 之间的实现可能会有所不同,并且在 Android 中也可能会有所不同。不过equalshashCode的实现其实和in the docs for Annotation的规定非常紧密:

注解的哈希码是其成员(包括具有默认值的)哈希码的总和,定义如下:注解成员的哈希码是(成员名称哈希码的127倍)由 String.hashCode()) 计算的成员值的哈希码 XOR,定义如下 [...]

如果指定的对象表示一个逻辑上等同于该对象的注释,则返回 true。换句话说,如果指定对象是与此实例相同的注解类型的实例,则返回true,其所有成员都等于此注解的相应成员,如下定义[...]

可以手动实现这些规则,但是很难做到,而且如果YourAnnotation或ClassPreamble的结构发生变化也会带来负担。尽管there are reflective solutions to this problem,AutoAnnotation 会自动为符合要求的实现生成代码:

public class YourAnnotations {
  @AutoAnnotation public static YourAnnotation yourAnnotation(String foo) {
    return new AutoAnnotation_YourAnnotations_yourAnnotation(foo);
  }
}

public class ClassPreambles {
  @AutoAnnotation public static ClassPreamble classPreamble(
      String author,
      String date,
      int currentRevision,
      String lastModified,
      String lastModifiedBy,
      String[] reviewers) {
    return new AutoAnnotation_ClassPreambles_classPreamble(
        author,
        date,
        currentRevision,
        lastModified,
        lastModifiedBy,
        reviewers);
  }
}

使用 AutoAnnotation 生成的实现,您可以在 Dagger Multibindings 生成的地图上调用get(或提供您控制的测试实现),而无需处理特定于注解的hashCode XOR 或equals 规则。这在 Dagger 和测试之外很有用,但是因为 Dagger 在其地图中使用注释实例,所以您可能需要使用 AutoAnnotation 来创建类似的实例是有道理的。

【讨论】:

  • 谢谢@jeff-bowman。为了更好地理解这一点,我探索了 AutoValue。然而卡住了。在那里发布了我的问题。希望您能提供一些见解。 stackoverflow.com/questions/58286591/… 谢谢!
  • 很好的答案。简而言之,生成 Annotation 键的是 AutoValue。一旦我设法让 AutoValue 工作,让 AutoAnnotation 工作变得很自然。谢谢!!
猜你喜欢
  • 1970-01-01
  • 2013-10-15
  • 2018-10-31
  • 1970-01-01
  • 2020-08-21
  • 2018-05-28
  • 1970-01-01
  • 1970-01-01
  • 2015-01-03
相关资源
最近更新 更多