繁体   English   中英

如何实现注释以限制成员函数,函数类型等数目,例如FunctionalInterface?

[英]How to implement annotations to limit number of member functions, function types, etc. like FunctionalInterface?

有许多内部Java注释,例如SuppressWarningFunctionalInterface等,它们可以使用该注释限制类的成员,扩展类甚至指定编译器选项,但是普通程序员如何才能构成此类注释?

我搜索的注释主题和所有我能找到的是增加了一些元值注释像这样 ,以及如何使用注释,但没有什么我能找到解释如何实现先进的注解。 任何方向都会有所帮助。

您正在寻找的是编译时注释

基本上,注释处理可以基于其RetentionPolicy 根据Java文档RetentionPolicy有3种类型-

CLASS批注由编译器记录在类文件中,但在运行时无需由VM保留。

RUNTIME批注将由编译器记录在类文件中,并在运行时由VM保留,因此可以通过反射方式读取它们。

注释将由编译器丢弃。

编译时注释处理与RetentionPolicy.SOURCE有关,因为您希望在编译时对源文件进行处理,类似于@Override等其他注释。

以下是一个简单的编译时注释处理器的示例-

  1. 创建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)在目录src/main/resources/META-INF/services具有以下内容的javax.annotation.processing.Processor文件 -

     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编译并安装该项目。

  2. 创建另一个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中定义的注释处理器都将被调用。 当前,处理器只是打印带有该注释的类的名称。

您也可以参考页面了解详细信息。

下一步是分析源文件并计算否。 方法。 由于这是编译时处理,因此您不能使用Reflection API来获取否。 方法。 一种解决方案是使用Eclipse AST解析源文件并计算no。 方法,或者您可以编写自己的逻辑。

龙目岛项目主要基于编译时注释处理。 如果您想做一些有用的事情,最好研究Project Lombok源代码

我认为您需要注释处理:

UPD:在某些情况下,您可以编写javaagent来代替,这至少要好得多,因为至少它具有诸如bytebuddy之类的工具(这是很棒的恕我直言)

我将分享我如何制作自定义注释来解决应用程序中的问题。

问题:

我正在使用Spring AOP在我的应用程序中进行日志记录。 对于logger.log() AOP的人来说,它用简单的语言代替了在每个方法和类中编写logger.log() ,您可以告诉AOP在每个之后/之前/之后和之前做一些事情(在我的情况下是日志记录)方法。 现在的问题是,由于每个方法都将被记录下来,因此如何防止某个方法(例如authentication )或参数(例如password )被记录下来。

为此,我创建了一个注释SkipLogging

@Target(value = { ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER })
@Retention(value = RetentionPolicy.RUNTIME)
public @interface SkipLogging {

}

并且在我的AOP类中,我设定了一个条件:如果有任何东西带有此批注,则AOP不应对此进行记录 也许遵循(部分)代码会更有意义:

@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中进行了检查,以便根据当前批注编写调试日志或错误日志。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM