有许多内部Java注释,如SuppressWarning
,FunctionalInterface
等,它们可以使用注释限制类的成员,扩展类甚至指定编译器选项,但是如何才能正常的程序员撰写这样的注释?
我搜索了注释主题,我所能找到的就是为注释添加一些元值,如this,以及如何使用注释,但我找不到任何解释如何实现高级注释的内容。任何指示都会有所帮助。
答案 0 :(得分:2)
您要找的是编译时注释。
基本上,注释处理可以基于其RetentionPolicy
来完成。根据{{3}},有3种RetentionPolicy
-
CLASS 编译器将在类文件中记录注释 但在运行时不需要由VM保留。
RUNTIME 注释将由编译器记录在类文件中,并在运行时由VM保留,因此可以反射性地读取它们。
SOURCE 编译器将丢弃注释。
编译时注释处理与RetentionPolicy.SOURCE
相关,因为您希望在编译时处理源文件,类似于@Override
等其他注释。
下面是一个简单的编译时注释处理器的一个例子 -
创建Maven项目 - Annotation_Compile_Time -
(A)在此项目中创建编译时注释MyAnnotation
-
package xxx;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Target(ElementType.TYPE)
@Inherited
@Retention(RetentionPolicy.SOURCE)
public @interface MyAnnotation {
}
(B)创建注释处理器MyAnnotationProcessor -
package xxx;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
@SupportedAnnotationTypes("xxx.MyAnnotation ")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class MyAnnotationProcessor extends AbstractProcessor {
public MyAnnotationProcessor () {
super();
}
@Override
public boolean process(Set<? extends TypeElement> typeElementSet, RoundEnvironment roundEnv) {
for (Element e : roundEnv.getRootElements()) {
String className = e.toString();
String message = "Annotated class - " + className;
System.out.println(message);
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, message);
}
return false;
}
}
(C)在目录 - javax.annotation.processing.Processor
中创建src/main/resources/META-INF/services
个文件,内容低于 -
xxx.MyAnnotationProcessor
(D)使用构建配置更新pom.xml
-
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<verbose>true</verbose>
<fork>true</fork>
<compilerArgument>-proc:none</compilerArgument>
</configuration>
</plugin>
</plugins>
</build>
(E)使用mvn clean install
编译并安装此项目。
创建另一个Maven项目 - Annotation_User - 此项目将使用上述项目中定义的注释。在此项目中使用此批注创建2个源文件
(A)AnnotationUser1 -
package xxx.consumer;
import xxx.MyAnnotation;
@MyAnnotation
public class AnnotationUser1 {
private String message;
public AnnotationUser1(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
(B)AnnotationUser2 -
package xxx.consumer;
import xxx.MyAnnotation;
@MyAnnotation
public class AnnotationUser2 {
private String message;
public AnnotationUser1(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
(C)使用注释项目依赖项更新pom.xml
-
<dependency>
<groupId>xxx</groupId>
<artifactId>Annotation_Compile_Time</artifactId>
<version>1.0</version>
</dependency>
现在,无论何时,您将使用mvn clean compile
编译此项目,您的项目1中定义的注释处理器将被调用。目前,处理器只是打印使用此批注注释的类的名称。
您还可以参考Java docs页面了解详情。
下一步是分析源文件并计算否。方法因为,它是编译时处理,所以你不能使用Reflection API
得到否。方法一种解决方案是使用this来解析源文件并计算否。方法或你可以编写自己的逻辑。
Eclipse AST主要基于编译时注释处理。如果你想做一些有用的事情,最好学习Project lombok
答案 1 :(得分:1)
我认为你需要注释处理:
UPD: 在某些情况下你可以编写javaagent而不是更好,至少因为它至少有一些像bytebuddy这样的工具(这是很棒的恕我直言)
答案 2 :(得分:1)
我正在分享如何制作自定义注释以解决我的应用中的问题。
<强>问题:强>
我正在使用Spring AOP在我的应用中进行日志记录。对于刚接触AOP的人来说,用简单的单词做的不是在每个方法和类中编写logger.log()
,而是可以告诉AOP在之后/之前执行(在我的情况下是日志记录) /每种方法之前和之后。现在的问题是因为每个方法都会被记录,如何防止某个方法(如身份验证)或参数(如密码)被记录。
为此,我创建了一个注释SkipLogging
@Target(value = { ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER })
@Retention(value = RetentionPolicy.RUNTIME)
public @interface SkipLogging {
}
在我的AOP类中,我提出了一个条件,即如果有任何东西都有这个注释,AOP不应该在那里做 logging 。也许跟随(部分)代码会更有意义:
@Around("within(com.test..*)
public Object logAround(final ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
// Log only if class/method is not annotated with SkipLogging
if (!(signature.getDeclaringType().isAnnotationPresent(SkipLogging.class)
|| method.isAnnotationPresent(SkipLogging.class))) {
try {
// Log before method entry
logger.info("");
Object result = joinPoint.proceed();
// Log after method exit
logger.info("");
return result;
} catch (Exception e) {
// Log after exception
logger.error("");
throw e;
}
} else {
return joinPoint.proceed();
}
}
没有详细说明,请查看条件:
if (!(signature.getDeclaringType().isAnnotationPresent(SkipLogging.class)
|| method.isAnnotationPresent(SkipLogging.class
)))
可防止使用SkipLogging
注释的类和方法被记录。同样,我编写了一些代码,用于将这个注释放在参数上并跳过它们。
在接下来的步骤中,我创建了@DebugLogging,@ ErrorLogging等注释,并在我的AOP中进行检查,根据存在的注释编写调试日志或错误日志。