![](/img/trans.png)
[英]How to implement with AutoBean a list of different base types like String, Integer, etc.?
[英]How to implement annotations to limit number of member functions, function types, etc. like FunctionalInterface?
有許多內部Java注釋,例如SuppressWarning
, FunctionalInterface
等,它們可以使用該注釋限制類的成員,擴展類甚至指定編譯器選項,但是普通程序員如何才能構成此類注釋?
我搜索的注釋主題和所有我能找到的是增加了一些元值注釋像這樣 ,以及如何使用注釋,但沒有什么我能找到解釋如何實現先進的注解。 任何方向都會有所幫助。
您正在尋找的是編譯時注釋 。
基本上,注釋處理可以基於其RetentionPolicy
。 根據Java文檔 , RetentionPolicy
有3種類型-
CLASS批注由編譯器記錄在類文件中,但在運行時無需由VM保留。
RUNTIME批注將由編譯器記錄在類文件中,並在運行時由VM保留,因此可以通過反射方式讀取它們。
源注釋將由編譯器丟棄。
編譯時注釋處理與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)在目錄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
編譯並安裝該項目。
創建另一個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.