2010-07-27 3 views
34

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

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

Альтернатива включает зеркальное отображение данных, содержащихся в аннотациях, в DTO, что кажется накладными расходами.

Вот пример:

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<? extends Annotation> annotationType() { 
     return Id.class; 
    } 

} 

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

Предупреждение о приведенном выше примере

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

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

Я только что нашел этот пример из Guice :

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

См. Это Javadoc from Names.

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

+2

Какие предупреждения вы получаете? – djna

+2

@djina: Да, один пенни за каждый раз, когда вы должны это сказать, и вы были бы богаты. Меня никогда не перестает удивлять. – musiKk

+0

Может быть, это только я, но, похоже, он тесно связан с этим вопросом: http: // stackoverflow.com/questions/1624084/why-is-not-possible-to-extend-annotations-in-java –

ответ

19

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

Давайте создадим искусственный пример. Скажем, у нас есть генератор документации. Он читает аннотацию @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. 

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

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

+0

спасибо за подробный ответ. Классы в качестве заметок для экземпляров аннотаций, вызванных отражением, действительно являются допустимым случаем. Аннотации весьма удобны, поскольку данные конфигурации и динамические случаи, создающие их экземпляры, необходимы. –

+0

"// игнорировать исключение, чтобы сделать отладку немного сложнее" +1 – Izmaki

-1

Для этого нет действительных случаев для пользователей - компилятор просто обменивает его, так как было бы довольно беспорядочно запрещать его, и люди, которые пишут компиляторы, могут нуждаться в этом объекте в очень редком случае. Если вам нужно классифицировать аннотации, ознакомьтесь с этой статьей, чтобы узнать, как это сделать: Why is not possible to extend annotations in Java?

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

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

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

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

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

+0

Меня не интересует классификация аннотаций, и мои варианты использования не связаны с компиляторами. И я не рассматриваю свои варианты использования «взлома». –

+0

@ZZX, на вашем примере отсутствовал javadoc, который, надеюсь, содержит ответ на _why? _. –

+0

Ваша чрезмерная реакция действительно не оправдана. Вот один очень правильный пример использования аннотаций: вы хотите запускать обработчики аннотаций, которые поставляют метаданные, используя неизученно api, например javax.lang.model, который освобождается при попытке загрузить значения классов. Лучше написать обработчик аннотации, который сканирует аннотации и генерирует построитель аннотаций, который фактически может работать с значениями класса. (javax.lang.model заставляет вас поймать необъявленную исключение во время выполнения и извлечь тип класса из зеркала типа, сгенерированный построитель заботится об этом уродливом беспорядке в других обработчиках аннотаций). – Ajax

4

JAXBIntroductions - хороший пример: он позволяет настраивать аннотации JAXB с использованием файлов XML. Приходят в голову два основных варианта использования: настройка классов у вас нет доступа к источнику или разных конфигураций для одного класса.

В целом, я думаю, что динамическое преобразование аннотаций, чтобы передать их в рамки, обычно является хорошим вариантом использования. Однако, если вы являетесь разработчиком этой структуры, я, конечно, подумаю дважды.

0

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

Использовать ваш пример; Когда я обрабатываю/просматриваю следующие компоненты, я хочу использовать значение по умолчанию для BeanB.

@Id 
class BeanA {} 

// No annotation 
class BeanB {} 

Реализация по умолчанию;

private static final Id DEFAULT_ID = new Id() { 

    @Override 
    public IDType value() { 
     return IDType.LOCAL; 
    } 

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

обработка;

Id beanId = (bean.getClass().isAnnotationPresent(Id.class)) 
    ? bean.getClass().getAnnotation(Id.class) 
    : DEFAULT_ID; 
Смежные вопросы