jdk开发

[JAVA基础篇25]—反射读取枚举值上的注解信息

2021-10-25  本文已影响0人  小胖学编程

JAVASE 的API并没有提供获取枚举值注解信息的方法,只能获取到enum类上的注解,但是有一种场景:通过注解为枚举值增加额外的功能。

enum作为数据字典,当为enum的各个枚举值增加一个新的属性值时,有两种方式:

  1. 增加一个属性值,通过多种参数的构造方法,来实现;
  2. 增加一个注解,并且放置在枚举值上;

本文来实现第二种方式,遇见的难题:JAVASE 的API并没有提供获取枚举值注解信息的方法,只能获取到enum类上的注解。

解决办法:通过获取枚举值Field对象,来实现:

实现

两个注解:需要去增强枚举值的功能

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface Log {

    //是否开启
    boolean open() default false;

}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface Cost {

    double min();

    double max();
}

解析方法:

/**
 * 随意一个枚举
 */
@Getter
public enum StudyEnum {

    @Log(open = true)
    @Cost(min = 10.0, max = 99.0)
    JAVA("java", "java基础"),

    @Cost(min = 20.0, max = 79.0)
    PHP("php", "php基础");

    private String actualName;

    private String desc;
    
    private static final Map<String, Cost> costCache = new HashedMap<>();
    private static final Map<String, Log> logCache = new HashedMap<>();

    private static final Map<String, StudyEnum> cache = new HashedMap<>();

    StudyEnum(String actualName, String desc) {
        this.actualName = actualName;
        this.desc = desc;
    }
    
    //对象初始化时,执行下面的方法,将注解上的枚举值解析到cache中
    static {
        //将枚举属性值的name和Field映射为Map
        Map<String, Field> fieldCache = Arrays.stream(StudyEnum.class.getDeclaredFields()).
                filter(Field::isEnumConstant).
                collect(Collectors.toMap(Field::getName, Function.identity()));
        //遍历所有的枚举值
        for (StudyEnum studyEnum : StudyEnum.class.getEnumConstants()) {
            String keyName = studyEnum.name();
            //原始的cache
            cache.put(keyName, studyEnum);
            Field field = fieldCache.get(keyName);
            //不包含原始,则停止解析
            if (!field.isAnnotationPresent(Log.class) || !field.isAnnotationPresent(Cost.class)) {
                continue;
            }
            //获取日志注解
            parsingLogAnno(keyName, field);
            //获取价格注解
            parsingCostAnno(keyName, field);
        }
    }


    /**
     * 获取注解的属性
     */
    public static StudyEnumInfo resolve(String name) {
        StudyEnum studyEnum = cache.get(name);
        if (studyEnum == null) {
            return null;
        }
        Log log = logCache.get(name);
        Cost cost = costCache.get(name);
        StudyEnumInfo studyEnumInfo = new StudyEnumInfo();
        studyEnumInfo.setName(studyEnumInfo.name);
        studyEnumInfo.setDesc(studyEnum.desc);
        studyEnumInfo.setLogAnno(log);
        studyEnumInfo.setCostAnno(cost);
        return studyEnumInfo;
    }

    /**
     * 获取注解的属性
     */
    public StudyEnumInfo resolve() {
        return resolve(this.name());
    }


    //解析日志注解
    private static void parsingLogAnno(String keyName, Field field) {
        Log logAnno = field.getDeclaredAnnotation(Log.class);
        if (logAnno != null) {
            logCache.put(keyName, logAnno);
        }
    }

    //解析花费注解
    private static void parsingCostAnno(String keyName, Field field) {
        Cost costAnno = field.getDeclaredAnnotation(Cost.class);
        if (costAnno != null) {
            costCache.put(keyName, costAnno);
        }
    }


    @Data
    public static class StudyEnumInfo {
        private String name;

        private String desc;

        private Log logAnno;

        private Cost costAnno;
    }
}

测试方法:

public class TestStudy {

    //完成对象的解析
    public static void main(String[] args) {
        //info对象
        StudyEnum.StudyEnumInfo info = StudyEnum.JAVA.resolve();
        System.out.println(info.getCostAnno().max());
        System.out.println(info.getLogAnno().open());
    }
}
上一篇 下一篇

猜你喜欢

热点阅读