簡體   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