Hello, annotations!

Главное что нужно знать об аннотациях — они ничего не делают! Аннотации представляют собой простые метки в коде и больше ничего. Когда кто-то говорит «Аннотация @DoSomething делает блаблабла» это фактически означает, что кто-то где-то вызывает код, который находит типы с этой аннотацией и делает блаблабла.

Зачем нужны аннотации? Они позволяют разработчику декларировать дополнительные свойства кода, который он пишет. Говоря простыми словами — когда разработчик пишет над определением метода  @Test это означает две вещи:

  1. Разработчик говорит себе и всему миру: «Этот метод не предназначен для использования в коде, этот метод реализует какую-то проверку и должен вызываться только во время исполнения тестов»
  2. Тестовый фреймворк осматривает все доступные ему методы в тестовых классах и запускает все методы, которые имеют аннотацию @Test

Другой хороший пример пользы от аннотаций был в статье, рассказывающей о разрешении конфликтов при внедрении зависимостей: некоторой аннотацией (можно считать, что именем) помечался как внедряемый класс, так и переменные, в которые он внедрялся.

Подготовка

Нам понадобится пустой maven проект с JUnit и Hamcrest:

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <junit.version>4.12</junit.version>
        <hamcrest.version>1.3</hamcrest.version>
    </properties>




    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>


        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-library</artifactId>
            <version>${hamcrest.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

И класс приветствия:

public class Greeter {
    public String greet(String target) {
        return "Hello, " + target;
    }
}
public class GreeterTest {


    @Test
    public void testGreet() throws Exception {
        Greeter testedObject = new Greeter();


        assertThat(testedObject.greet("TEST"), is("Hello, TEST"));
    }
}

Собственная аннотация

Сделать аннотацию самому не сложно — аннотация состоит из имени, свойств и конфигурации:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface GreeterTarget {
    String value() default "world";
}

@Target(ElementType.FIELD)  говорит, что эта аннотация может быть применена только к полям классов. Аннотации можно применять к пакетам, классам и их конструкторам, методам и их аргументам, переменным и так далее. @Retention(RetentionPolicy.RUNTIME) делает аннотацию доступной во время исполнения, а не удаляет её во время компиляции.

@interface говорит, что это аннотация, а не обычный интерфейс. Внутри аннотации могут быть определены её свойства, но их определение несколько необычно: во первых они выглядят как методы, во вторых у них может быть значение по умолчанию.

Использование аннотации очевидно:

  @GreeterTarget
    private static Greeter world = new Greeter();


    @GreeterTarget(value = "annotations")
    private static Greeter annotations = new Greeter();


    @GreeterTarget("Java")
    private static Greeter java = new Greeter();

В первом случае значением свойства value будет значение по умолчанию: «world», во втором «annotations», а в третьем … таки да, «Java». У свойства по имено value() если удобное соглашение, именно в него попадает значение аннотации по умолчанию.

Использовать аннотацию гораздо сложнее. Так как аннотации относятся к коду, а не к данным программы, то для доступа к ним приходиться использовать reflection:

 

Вначале надо получить аннотируемый объект, потом получить из него аннотацию и, наконец, взять у аннотации её значения. Другой пример показывает, что никакой другой связи между кодом и аннотациями нет:

        Field javaField = Main.class.getDeclaredField("java");
        GreeterTarget javaTarget = javaField.getAnnotation(GreeterTarget.class);
        System.out.println(world.greet(javaTarget.value()));

Скачать код примера

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *