在 JDK8 中增加了 Repeatable 注解,通过示例了解一下这个注解的功能。

Repeatable 源代码

package java.lang.annotation;

/**
 * The annotation type {@code java.lang.annotation.Repeatable} is
 * used to indicate that the annotation type whose declaration it
 * (meta-)annotates is <em>repeatable</em>. The value of
 * {@code @Repeatable} indicates the <em>containing annotation
 * type</em> for the repeatable annotation type.
 *
 * @since 1.8
 * @jls 9.6 Annotation Types
 * @jls 9.7 Annotations
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
    /**
     * Indicates the <em>containing annotation type</em> for the
     * repeatable annotation type.
     * @return the containing annotation type
     */
    Class<? extends Annotation> value();
}

The annotation type java.lang.annotation.Repeatable is used to indicate that the annotation type whose declaration it (meta-)annotates is repeatable. The value of @Repeatable indicates the containing annotation type for the repeatable annotation type.

@Repeatable 注解用于指示它注解声明的注解类型是可重复的。@Repeatable 的值用于指示一个注解类型,这个注解类型用来存放可重复的注解类型。

初次看这段文字时,觉得比较难以理解,经过思考,我认为 用户-角色场景可以通俗的解释 @Repeatable 注解。

功能描述

一个系统中可以设定多个角色,每个角色我们称之为 Role,系统定义的角色如下:

  • 系统管理员:system_admin
  • 业务管理员:biz_admin
  • 客户:custom

一个用户(User)可以拥有其中的一个或者多个角色,用户拥有的角色列表我们称之为 Roles,假设有两个用户 User1、User2 ,他们的权限分别如下:

  • User1:system_admin
  • User2 :biz_admin、custom

通过 @Repeatable 注解来实现以上功能

定义角色注解 Role

package org.learn.annotation;


import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Roles.class)
public @interface Role {
    String value() default "";
}

这里需要说明 @Repeatable(Roles.class),它指示在同一个类中 @Role 注解是可以重复使用的,重复的注解被存放至 @Roles 注解中。

定义角色列表注解 Roles

package org.learn.annotation;


import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Roles {
    Role[] value();
}

@Roles 注解是如何存放 @Role 注解的呢?它定义了 Role[] value(); 用来存放可重复的注解。

这里提出一个问题,如果在同一个类中只有一个可重复的 @Role 注解,那这个值会被存入 @Roles 注解中吗?

定义 User1

package org.learn.annotation;

/**
 * @author zhibo
 * @date 2019/5/31 15:03
 */

@Role("system_admin")
public class User1 {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

定义 User2

package org.learn.annotation;

/**
 * @author zhibo
 * @date 2019/5/31 15:03
 */

@Role("biz_admin")
@Role("custom")
public class User2 {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

进行测试

package org.learn.annotation;

/**
 * @author zhibo
 * @date 2019/5/31 15:00
 */
public class RepeatableDemo {

    public static void main(String[] args) {
        if(User1.class.isAnnotationPresent(Roles.class)){
            Roles roles = User1.class.getAnnotation(Roles.class);
            System.out.println("User1的角色如下:");
            for (Role role : roles.value()){
                System.out.println(role.value());
            }
        }

        if(User2.class.isAnnotationPresent(Roles.class)){
            Roles roles = User2.class.getAnnotation(Roles.class);
            System.out.println("User2的角色如下:");
            for (Role role : roles.value()){
                System.out.println(role.value());
            }
        }
    }
}

执行 main 方法,输出如下:

java aar热更 java repeatable_Repeatable


从执行结果中可以看到 User2 的角色列表,通过注解的值我们可以进行用户角色判定。

同时可以看到 User1 的角色是@Role("system_admin"),但是 User1 的角色没有被输出,在加上一个 Role 的话,就可以输出角色了。由此可见,如果只声明了一个注解 Role(被 @Repeatable 声明的注解),那么注解值是不会被存放至 Roles 注解中的,测试类中不会存在 Roles 注解。

解惑

修改 User1 的代码,为其增加 @Role("custom") 角色:

package org.learn.annotation;

/**
 * @author zhibo
 * @date 2019/5/31 15:03
 */

@Role("system_admin")
@Role("custom")
public class User1 {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

再次执行 main 方法,结果如下:

java aar热更 java repeatable_java aar热更_02


与我们的预期一致,由此可见,在写代码时,不能用惯性思维去理解问题,面对不确定的问题,一定要通过代码进行验证。

文章内容仅代表个人观点,如有不正之处,欢迎批评指正,谢谢大家。