Для чего нужен @AutoAnnotation? Как это можно использовать? - PullRequest
0 голосов
/ 07 октября 2019

В 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

Но я не понимаю, как его можно использовать. Есть ли хороший учебник по его использованию?

1 Ответ

2 голосов
/ 07 октября 2019

AutoAnnotation автоматически генерирует класс, который реализует интерфейс аннотации так же, как это делает JDK.

Ключи карты кинжала

При использовании карты Multibindings через Dagger, котораяв качестве ключа использует пользовательскую аннотацию, Dagger установит экземпляр T или поставщика 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-учебника :

@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. Если аннотация сохраняется во время выполнения (т.е. сам ClassPreamble помечен @Retention(RUNTIME)), вы можете получить к нему через Generation3List.class.getAnnotations() или Generation3List.class.getAnnotation(ClassPreamble.class),(Существуют также объявленные аналоги, которые по-разному обрабатывают аннотации суперкласса.)

Как только вы получите экземпляр ClassPreamble, вы можете использовать такие методы, как author() и date(), чтобы получитьданные вне класса. Однако ClassPreamble ведет себя как интерфейс, и реализация этой аннотации является внутренней по отношению к ВМ. Это затрудняет создание собственного произвольного экземпляра ClassPreamble во время выполнения.

Соответствующие реализации аннотаций

Поскольку YourAnnotation и ClassPreamble являются интерфейсами, вы можете просто создать реализацию. Однако эта реализация вряд ли будет иметь совпадающие реализации equals и hashCode по сравнению с реализацией виртуальной машины, поскольку реализация может различаться в зависимости от JRE, а также в Android. Однако реализация equals и hashCode на самом деле очень точно прописана в документах для аннотации :

Хеш-код аннотации представляет собой сумму хеш-кодакоды его членов (в том числе со значениями по умолчанию), как определено ниже: хеш-код элемента аннотации (в 127 раз больше хеш-кода имени члена, вычисленного String.hashCode ()) XOR хеш-кодзначение элемента, как определено ниже [...]

Возвращает true, если указанный объект представляет аннотацию, которая логически эквивалентна этой. Другими словами, возвращает true, если указанный объект является экземпляром того же типа аннотации, что и этот экземпляр, все члены которого равны соответствующему члену этой аннотации, как определено ниже [...]

Возможно реализовать эти правила вручную, но это будет трудно сделать, и это также наложит бремя, если структура YourAnnotation или ClassPreamble должна была измениться. Хотя есть рефлексивные решения этой проблемы , 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 вы можете вызвать get на карте, к которой относится DaggerMultibindings генерирует (или предоставляет тестовые реализации, которые вы контролируете) без необходимости иметь дело с правилами hashCode XOR или equals, специфичными для аннотаций. Это полезно помимо Dagger и тестов, но поскольку Dagger использует экземпляры аннотаций в своих картах, имеет смысл использовать AutoAnnotation для создания похожих экземпляров.

...