Java 8 前若需在同一位置多次使用同一註解,必須定義「容器註解」包裝陣列:@Authorities({@Authority("Admin"), @Authority("Manager")})。Java 8 引入 @Repeatable 元註解,配合容器註解,實現語法層面的原生重複:@Authority("Admin") @Authority("Manager")。編譯器自動合成容器註解,反射 API 提供 getAnnotationsByType() 直接獲取重複註解陣列。
@Retention(RUNTIME) @Target({TYPE, METHOD, FIELD})
public @interface Authorities { Authority[] value(); }
@Retention(RUNTIME) @Target({TYPE, METHOD, FIELD})
public @interface Authority { String role(); }
// 使用
@Authorities({@Authority("Admin"), @Authority("Manager")})
public void doSomething() {}
@Retention(RUNTIME) @Target({TYPE, METHOD, FIELD})
@Repeatable(Authorities.class) // 指向容器註解
public @interface Authority { String role(); }
// 容器註解必須存在,value() 為重複註解陣列
@Retention(RUNTIME) @Target({TYPE, METHOD, FIELD})
public @interface Authorities { Authority[] value(); }
// 使用:直接重複標註
@Authority("Admin")
@Authority("Manager")
public void doSomething() {}
// 反射獲取(Java 8 新增)
Authority[] authorities = method.getAnnotationsByType(Authority.class);
// 或獲取容器
Authorities container = method.getAnnotation(Authorities.class);
@Repeatable 的值必須是容器註解類型(Authorities.class)。value() 方法,型別為重複註解的陣列(Authority[])。@Retention、@Target 必須兼容(通常相同)。| 方法 | Java 7 行為 | Java 8+ 行為 |
|---|---|---|
getAnnotation(Authority.class) | 返回單個(若用容器則返回容器) | 返回第一個重複註解(為兼容性) |
getAnnotationsByType(Authority.class) | 不存在 | 返回所有重複註解陣列(含容器展開) |
getDeclaredAnnotationsByType() | 不存在 | 同理,不繼承父類註解 |
getAnnotation(Authorities.class) | 返回容器 | 返回合成的容器註解 |
@Scheduled、@Cacheable、@EventListener 均已支援重複。RoundEnvironment.getElementsAnnotatedWith() 可正確識別重複註解。Duplicate annotation。@Inherited 僅作用於容器註解,重複註解本身不繼承。