java 实现注解的用例
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3341930/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Use cases for implementing annotations
提问by Timo Westk?mper
What are valid use cases for implementing annotations?
什么是实现注释的有效用例?
When designing primarily annotation based configuration systems I occasionally need to create classes which implement annotations for code generation or programmatic configuration.
在主要设计基于注解的配置系统时,我偶尔需要创建实现代码生成或编程配置注解的类。
The alternative involves mirroring the data contained in annotations into DTOs, which seems like an overhead.
另一种方法是将注释中包含的数据镜像到 DTO,这似乎是一种开销。
Here is an example:
下面是一个例子:
public enum IDType {
LOCAL,
URI,
RESOURCE;
}
@Documented
@Target( { METHOD, FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Id {
/**
* @return
*/
IDType value() default IDType.LOCAL;
}
with the implementation
随着实施
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;
}
}
I get compiler warnings for this, but it seems to be a valid tool for many use cases.
我为此收到编译器警告,但它似乎是许多用例的有效工具。
The warning for the example above is
上面例子的警告是
The annotation type Id should not be used as a superinterface for IdImpl
注释类型 Id 不应用作 IdImpl 的超接口
Edited :
编辑:
I just found this example from Guice:
我刚刚从Guice找到了这个例子:
bind(CreditCardProcessor.class)
.annotatedWith(Names.named("Checkout"))
.to(CheckoutCreditCardProcessor.class);
See this Javadoc from Names.
Has anyone some information why this restriction exists or has some other use cases in mind?
有没有人知道为什么存在这种限制或有其他一些用例?
采纳答案by Arne Deutsch
I've never used it in practice but what you get is, that you can use classes as replacement for your annotations.
我从来没有在实践中使用过它,但你得到的是,你可以使用类来代替你的注释。
Let's create an artificial example. Say we have an documentation generator. It reads a @Docuannotation from given classes and prints the descriptionattribute. Like this:
让我们创建一个人工示例。假设我们有一个文档生成器。它@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 {
}
Prints:
印刷:
This is a static class!
This is another static class!
What we now want to accomplish is, that a class can not only be staticly annotated, but can add runtime information to the documentation. We are quite happy to use the @Docuannotation most of the time, but there are special cases we want special documenation. We might want to add performance documenation for some methodes. We can do this by letting a class implement the annotation. The generator checks first for the annotation and, if not present, it checks if the class implements the annotation. If it does, it adds the class to the list of annotations.
我们现在想要完成的是,一个类不仅可以静态注释,还可以将运行时信息添加到文档中。@Docu大多数时候我们很乐意使用注释,但有一些特殊情况我们需要特殊的文档。我们可能希望为某些方法添加性能文档。我们可以通过让一个类实现注释来做到这一点。生成器首先检查注解,如果不存在,则检查该类是否实现了注解。如果是,它会将类添加到注释列表中。
Like this (only two additional lines of code in the generator):
像这样(生成器中只有两行额外的代码):
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;
}
}
Output is:
输出是:
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.
You havn't to change the code generator that much because you can use the class as replacement of the annotation.
您不必对代码生成器进行太多更改,因为您可以使用该类来替换注释。
Other example whould be a framework that uses annotations or XML as configuration. You might have one processor that works on annotations. If you use XML as configuration you can generate instances of classes that implement the annotations and your processor works on them without a single change! (of course there are other ways to accomplish the same effect, but this is ONE way to do it)
其他示例可能是使用注释或 XML 作为配置的框架。您可能有一个处理注释的处理器。如果您使用 XML 作为配置,您可以生成实现注释的类的实例,并且您的处理器无需任何更改即可处理它们!(当然还有其他方法可以实现相同的效果,但这是一种方法)
回答by sfussenegger
JAXBIntroductionsis a good example: it allows configuring JAXB annotations using XML files. Two main use cases come to mind: configuring classes you don't have source access or different configurations for one class.
JAXBIntroductions就是一个很好的例子:它允许使用 XML 文件配置 JAXB 注释。我想到了两个主要用例:配置您没有源访问权限的类或一个类的不同配置。
In general, I think instantiating annotations dynamically to pass them to frameworks is generally a good use case. However, if you are the designer of this framework, I certainly would think twice though.
总的来说,我认为动态实例化注释以将它们传递给框架通常是一个很好的用例。然而,如果你是这个框架的设计者,我当然会三思而后行。
回答by Foumpie
I use it when I created an annotation and want to make its use optional, by providing a default when the annotation is omitted. This could occur when your library introduces a new annotation and you want your library to remain backwards compatible.
我在创建注释时使用它,并希望通过在省略注释时提供默认值来使其使用可选。当您的库引入新注释并且您希望您的库保持向后兼容时,可能会发生这种情况。
In this example, BeanB is written in source code against an older version of your library, so you want to use a default when you identify such a class.
在此示例中,BeanB 是针对旧版本库编写的源代码,因此在识别此类类时您希望使用默认值。
@Id
class BeanA {}
// No annotation
class BeanB {}
The default implementation;
默认实现;
private static final Id DEFAULT_ID = new Id() {
@Override
public IDType value() {
return IDType.LOCAL;
}
@Override
public Class<? extends Annotation> annotationType() {
return Id.class;
}
};
Processing;
加工;
Id beanId = (bean.getClass().isAnnotationPresent(Id.class))
? bean.getClass().getAnnotation(Id.class)
: DEFAULT_ID;
回答by ZXX
There are no valid user cases for that - compiler just tollerates it since it would be quite messy to forbid it and people who are writing compilers may need the facility on a very rare occasion. If you need to classify annotations check out this article to see how to do it: Why is not possible to extend annotations in Java?
没有有效的用户案例 - 编译器只是容忍它,因为禁止它会非常混乱,并且正在编写编译器的人可能在非常罕见的情况下需要该工具。如果您需要对注解进行分类,请查看这篇文章以了解如何进行:Why is not possible to extend annotations in Java?
Inagine a poor soul coming after you to maintain and debug that code or another one who needs to write a codegen tool and assumes that annotatuion types are straight or another who just used such annotation not even dreaming what can happend and what to do about it. By the time he discovers that hack and finds a way to eliminate it he's going to die from hernia - or equivalent ailment :-) Annotations are expected to be purely declarative statements, interpreted solely by a codegen tool which runs separately from the annotated code and treats it as data.
想象一个可怜的人跟着你来维护和调试该代码,或者另一个需要编写代码生成工具并假设注释类型是直接的或另一个只是使用这种注释的人,甚至没有梦想会发生什么以及如何处理它。当他发现这个黑客并找到消除它的方法时,他将死于疝气 - 或等效的疾病:-) 注释应该是纯粹的声明性语句,仅由代码生成工具解释,该工具与注释代码分开运行,并且将其视为数据。
Take a fresh look at that code and try to honestly say what's a rational rason for something like:
重新审视该代码并尝试诚实地说出以下内容的合理理由:
public Class<? extends Annotation> annotationType() {
return Id.class;
}
and that's stil a small thing compared to that people can put in code.
与人们可以放入代码相比,这仍然是一件小事。
Annotations are not the place to practice hacking - that's what compiler is trying to convey. Do you know exactly when and how the code in "implementation" of annotation may run? Including CTOR? What is available and what not at that point? What is safe to call? Compiler doesn't - it would take pretty heavy static analysis for a compiler to check actual safety of such hack. So instead it just issues a warning so that when something goes wrong people can't blame compile, VM and everything else.
注释不是练习黑客的地方 - 这就是编译器试图传达的。您是否确切知道注释的“实现”中的代码何时以及如何运行?包括CTOR?什么是可用的,什么是不可用的?什么叫安全?编译器没有 - 编译器需要进行大量静态分析来检查此类黑客的实际安全性。因此,它只是发出警告,以便在出现问题时人们不能责怪编译、VM 和其他一切。

