简体   繁体   English

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

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

There are many internal Java annotations like SuppressWarning , FunctionalInterface , etc. which can limit the members of the class with the annotation, expand classes or even specify compiler options, but how can a normal programmer compose such annotations? 有许多内部Java注释,例如SuppressWarningFunctionalInterface等,它们可以使用该注释限制类的成员,扩展类甚至指定编译器选项,但是普通程序员如何才能构成此类注释?

I searched on the annotation topics and all I could find is adding some meta values to the annotation like this , and how to use annotations, but nothing I can find that explains how to implement advanced annotations. 我搜索的注释主题和所有我能找到的是增加了一些元值注释像这样 ,以及如何使用注释,但没有什么我能找到解释如何实现先进的注解。 Any directions would be helpful. 任何方向都会有所帮助。

What you are looking for is compile-time annotation . 您正在寻找的是编译时注释

Basically, annotation processing can be done based on its RetentionPolicy . 基本上,注释处理可以基于其RetentionPolicy As per the Java docs , there are 3 type of RetentionPolicy - 根据Java文档RetentionPolicy有3种类型-

CLASS Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time. CLASS批注由编译器记录在类文件中,但在运行时无需由VM保留。

RUNTIME Annotations are to be recorded in the class file by the compiler and retained by the VM at run time, so they may be read reflectively. RUNTIME批注将由编译器记录在类文件中,并在运行时由VM保留,因此可以通过反射方式读取它们。

SOURCE Annotations are to be discarded by the compiler. 注释将由编译器丢弃。

Compile-time annotation processing is related to RetentionPolicy.SOURCE because you want to process on source file at the time of compilation similar to other annotation like @Override . 编译时注释处理与RetentionPolicy.SOURCE有关,因为您希望在编译时对源文件进行处理,类似于@Override等其他注释。

Below is one example of a simple compile-time annotation processor - 以下是一个简单的编译时注释处理器的示例-

  1. Create Maven Project - Annotation_Compile_Time - 创建Maven项目-Annotation_Compile_Time-

    (A) Create a compile-time Annotation MyAnnotation in this project - (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) Create a annotation Processor MyAnnotationProcessor - (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) Create javax.annotation.processing.Processor file in directory - src/main/resources/META-INF/services with below content - (C)在目录src/main/resources/META-INF/services具有以下内容的javax.annotation.processing.Processor文件 -

     xxx.MyAnnotationProcessor 

    (D) Update pom.xml with build configuration - (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) Compile and install this project using mvn clean install . (E)使用mvn clean install编译并安装该项目。

  2. Create Another Maven Project - Annotation_User - This project will use annotation defined in above project. 创建另一个Maven项目-Annotation_User-该项目将使用上述项目中定义的注释。 Create 2 source files in this project annotated with this annotation 在该项目中创建2个带有此批注的源文件

    (A) AnnotationUser1 - (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 - (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) Update pom.xml with Annotation project dependency - (C)使用注释项目依赖项更新pom.xml

     <dependency> <groupId>xxx</groupId> <artifactId>Annotation_Compile_Time</artifactId> <version>1.0</version> </dependency> 

Now, whenever, you will compile this project using mvn clean compile , your annotation processor defined in project 1 will get called. 现在,无论何时,只要使用mvn clean compile编译该项目,项目1中定义的注释处理器都将被调用。 Currently, processor is just printing the name of the classes annotated with this annotation. 当前,处理器只是打印带有该注释的类的名称。

You can also refer to this page for details. 您也可以参考页面了解详细信息。

Next step comes is to analyse the source file and calculate no. 下一步是分析源文件并计算否。 of methods. 方法。 Since, it is compile time processing, so you can not use Reflection API for getting no. 由于这是编译时处理,因此您不能使用Reflection API来获取否。 of methods. 方法。 One solution is to use Eclipse AST for parsing source file and calculating no. 一种解决方案是使用Eclipse AST解析源文件并计算no。 of methods or you can write your own logic. 方法,或者您可以编写自己的逻辑。

Project lombok is mainly based on Compile-time annotation processing. 龙目岛项目主要基于编译时注释处理。 If you want to do something useful, it would be better to study Project lombok source code 如果您想做一些有用的事情,最好研究Project Lombok源代码

I think you need annotation processing: 我认为您需要注释处理:

UPD: For some cases you can write javaagent instead which is much better at least because it is at least has some tools like bytebuddy (which is great IMHO) UPD:在某些情况下,您可以编写javaagent来代替,这至少要好得多,因为至少它具有诸如bytebuddy之类的工具(这是很棒的恕我直言)

I am sharing how I made a custom annotation to resolve an issue in my app. 我将分享我如何制作自定义注释来解决应用程序中的问题。

Problem: 问题:

I was using Spring AOP to do the logging in my app. 我正在使用Spring AOP在我的应用程序中进行日志记录。 To people new to AOP, what it did in simple words is instead of writing logger.log() in every method and class, you can tell AOP to do something (in my case logging) after/before/after-and-before each method. 对于logger.log() AOP的人来说,它用简单的语言代替了在每个方法和类中编写logger.log() ,您可以告诉AOP在每个之后/之前/之后和之前做一些事情(在我的情况下是日志记录)方法。 Now the problem is since every method is going to get logged, how do I prevent a certain method(like authentication ) or parameter(like password ) from getting logged. 现在的问题是,由于每个方法都将被记录下来,因此如何防止某个方法(例如authentication )或参数(例如password )被记录下来。

So to do this, I created an annotation SkipLogging 为此,我创建了一个注释SkipLogging

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

}

and in my AOP class, I put in a condition that if any thing has this annotation, AOP should not do logging on that. 并且在我的AOP类中,我设定了一个条件:如果有任何东西带有此批注,则AOP不应对此进行记录 Maybe following (partial) code will make more sense: 也许遵循(部分)代码会更有意义:

@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();
        }
    }

Without going into much detail, look at the condition: 无需赘述,请看一下条件:

    if (!(signature.getDeclaringType().isAnnotationPresent(SkipLogging.class)
                        || method.isAnnotationPresent(SkipLogging.class

)))

which prevents classes and methods annotated with SkipLogging from getting logged. 这样可以防止使用SkipLogging注释的类和方法被记录。 Similarly, I had written some code for putting this annotation on parameters and skipping them. 同样,我编写了一些代码,用于将此批注放在参数上并跳过它们。

In the next steps, I had created annotations like @DebugLogging, @ErrorLogging etc. and put in a check in my AOP, to write debug log or error log based on the annotation present. 在接下来的步骤中,我创建了@ DebugLogging,@ ErrorLogging等批注,并在AOP中进行了检查,以便根据当前批注编写调试日志或错误日志。

暂无
暂无

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

相关问题 如何使用AutoBean实现不同基类型的列表,如String,Integer等? - How to implement with AutoBean a list of different base types like String, Integer, etc.? 如何反映像java.Math这样的类(我想提取参数的函数类型,如:Math.abs()等) - How to reflect classes like java.Math(I would like to extract parameters' types of functions like: Math.abs(), etc.) 如何将弹出菜单的可见性限制为所有类型的文件,包括Java文件等可编译文件? - How to limit visibility of a popup menu to all type of files including compilable file like Java file, etc.? 如何在simpleadapter中实现OnItemClickListener? 代码删除,更新等, - how to implement OnItemClickListener in simpleadapter? code delete, update etc., 如何将带有tinestamp等的CSV文件输入到mahout中以实现相似功能等? - How to input CSV file with tinestamp etc. into mahout to achieve similarity function etc.? 如何不使用随机库等构建随机数? - How ı build random number not using random library or etc.? AspectJ / AOP:如何通过类型“get-field”等限制编织? - AspectJ / AOP : how to limit the weaving by type "get-field", etc.? Java是否有平台无关的代码来调用默认应用程序以查看诸如PDF,DOCX,JPEG等文档类型? - Is there platform-agnostic code in Java to invoke the default app to view document types like PDF, DOCX, JPEG etc.? 如何在Java中计算@,#,+等符号的数量 - How to count number of symbols like @,#,+ etc in Java 字段上的Java注释数量是否有限制? - Is there a limit on the number of Java annotations on a field?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM