Варианты использования для реализации аннотаций

Что такое допустимые варианты использования для реализации аннотаций?

При разработке, прежде всего, основанных на аннотации систем конфигурации я иногда должен создавать классы, которые реализуют аннотации для генерации кода или программную конфигурацию.

Альтернатива включает зеркальное отражение данных, содержавшихся в аннотациях в DTOs, который походит на издержки.

Вот пример:

public enum IDType {
    LOCAL,
    URI,
    RESOURCE;
}

@Documented
@Target( { METHOD, FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Id {
    /**
     * @return
     */
    IDType value() default IDType.LOCAL;
}

с реализацией

public class IdImpl implements Id{

    private final IDType idType;

    public IdImpl(IDType idType){
        this.idType = idType;
    }

    @Override
    public IDType value() {
        return idType;
    }

    @Override
    public Class annotationType() {
        return Id.class;
    }

}

Я получаю предупреждения компилятора для этого, но это, кажется, допустимый инструмент для многих вариантов использования.

Предупреждение для примера выше

Идентификатор типа аннотации не должен использоваться в качестве суперинтерфейса для IdImpl

Отредактированный:

Я просто нашел этот пример от Guice:

bind(CreditCardProcessor.class)
    .annotatedWith(Names.named("Checkout"))
    .to(CheckoutCreditCardProcessor.class);

Посмотрите этот Javadoc с Имен.

У кого-либо есть некоторая информация, почему это ограничение существует или имеет некоторые другие варианты использования в виду?

37
задан Timo Westkämper 28 July 2010 в 12:47
поделиться

2 ответа

Я никогда не использовал его на практике, но вы получаете то, что вы можете использовать классы в качестве замены ваших аннотаций.

Создадим искусственный пример. Допустим, у нас есть генератор документации. Он считывает аннотацию @Docu из заданных классов и печатает атрибут description . Примерно так:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.List;

public class DokuGenerator {

    public static void main(String[] args) throws Exception {
        new DokuGenerator(StaticClass.class, StaticClass2.class);
    }

    public DokuGenerator(Class<?>... classesToDokument) throws Exception {
        List<Docu> documentAnnotations = getDocumentAnnotations(classesToDokument);
        printDocumentation(documentAnnotations);
    }

    private List<Docu> getDocumentAnnotations(Class<?>... classesToDokument)
            throws Exception {
        List<Docu> result = new ArrayList<Docu>();
        for (Class<?> c : classesToDokument)
            if (c.isAnnotationPresent(Docu.class))
                result.add(c.getAnnotation(Docu.class));
        return result;
    }

    private void printDocumentation(List<Docu> toDocument) {
        for (Docu m : toDocument)
            System.out.println(m.description());
    }

}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Docu {
    String description();
}

@Docu(description = "This is a static class!")
class StaticClass {
}

@Docu(description = "This is another static class!")
class StaticClass2 {
}

Печать:

This is a static class!  
This is another static class!

Теперь мы хотим добиться того, чтобы класс можно было не только аннотировать статически, но и добавлять в документацию информацию о времени выполнения. Мы очень рады использовать аннотацию @Docu большую часть времени, но есть особые случаи, когда нам нужна специальная документация. Возможно, мы захотим добавить документацию по производительности для некоторых методов. Мы можем сделать это, позволив классу реализовать аннотацию. Генератор сначала проверяет аннотацию, а если ее нет, то проверяет, реализует ли класс аннотацию. Если это так, он добавляет класс в список аннотаций.

Примерно так (только две дополнительные строки кода в генераторе):

import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class DokuGenerator {

    public static void main(String[] args) throws Exception {
        new DokuGenerator(StaticClass.class, StaticClass2.class,
                DynamicClass.class);
    }

    public DokuGenerator(Class<?>... classesToDokument) throws Exception {
        List<Docu> documentAnnotations = getDocumentAnnotations(classesToDokument);
        printDocumentation(documentAnnotations);
    }

    private List<Docu> getDocumentAnnotations(Class<?>... classesToDokument)
            throws Exception {
        List<Docu> result = new ArrayList<Docu>();
        for (Class<?> c : classesToDokument)
            if (c.isAnnotationPresent(Docu.class))
                result.add(c.getAnnotation(Docu.class));
            else if (Arrays.asList(c.getInterfaces()).contains(Docu.class))
                result.add((Docu) c.newInstance());
        return result;
    }

    private void printDocumentation(List<Docu> toDocument) {
        for (Docu m : toDocument)
            System.out.println(m.description());
    }

}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Docu {
    String description();
}

@Docu(description = "This is a static class!")
class StaticClass {
}

@Docu(description = "This is another static class!")
class StaticClass2 {
}

class DynamicClass implements Docu {

    public DynamicClass() {
        try {
            Thread.sleep((long) (Math.random() * 100));
        } catch (InterruptedException e) {
            // ignore exception to make debugging a little harder
        }
    }

    @Override
    public String description() {
        long millis = System.currentTimeMillis();
        new DynamicClass();
        millis = System.currentTimeMillis() - millis;
        return "This is a dynamic class. I run on "
                + System.getProperty("os.name")
                + ". The construction of an instance of this class run for "
                + millis + " milliseconds.";
    }

    @Override
    public Class<? extends Annotation> annotationType() {
        return Docu.class;
    }

}

Результат:

This is a static class!  
This is another static class!  
This is a dynamic class. I run on Windows XP. The construction of an instance of this class run for 47 milliseconds.

Вам не нужно так сильно менять генератор кода, потому что вы можете использовать класс как замену аннотации.

Другим примером может быть структура, использующая аннотации или XML в качестве конфигурации. У вас может быть один процессор, который работает с аннотациями.Если вы используете XML в качестве конфигурации, вы можете создавать экземпляры классов, реализующих аннотации, и ваш процессор работает с ними без единого изменения! (конечно, есть и другие способы добиться того же эффекта, но это ОДИН способ сделать это)

21
ответ дан 27 November 2019 в 05:03
поделиться

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

Представьте себе беднягу, идущую за вами, чтобы поддерживать и отлаживать этот код, или другого человека, который необходимо написать инструмент кодогенерации и предполагает, что типы аннотаций являются прямыми или кем-то еще, кто только что использовал такую ​​аннотацию, даже не подозревая, что может случиться и что с этим делать. К тому времени, когда он обнаружит этот взлом и найдет способ устранить его, он умрет от грыжи - или аналогичного недуга :-) Ожидается, что аннотации будут чисто декларативными заявлениями, интерпретируемыми исключительно с помощью инструмента кодогенерации, который запускается отдельно от аннотированного кода и рассматривает это как данные.

Взгляните свежим взглядом на этот код и попытайтесь честно сказать, что является рациональным rason для чего-то вроде:

 public Class<? extends Annotation> annotationType() { 
     return Id.class; 
 } 

и это все еще мелочь по сравнению с тем, что люди могут вставлять в код.

Аннотации - не место для практики взлома - это то, что пытается передать компилятор. Вы точно знаете, когда и как может работать код в «реализации» аннотации? Включая CTOR? Что доступно, а что нет в данный момент? Что безопасно называть? Компилятор этого не делает - компилятору потребуется довольно тяжелый статический анализ, чтобы проверить фактическую безопасность такого взлома. Вместо этого он просто выдает предупреждение, чтобы, когда что-то пойдет не так, люди не могли винить компиляцию, виртуальную машину и все остальное.

-2
ответ дан 27 November 2019 в 05:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: