Java 扫描枚举类并获取属性
文章目录
- Java 扫描枚举类并获取属性
- 第一步:在 pom.xml 下导入 hutool 和 commons-lang3
- 第二步:写一个接口以规范枚举的属性
- 第三步:写一个枚举属性包装类
- 第四步:写两个实体测试类
- 第五步:写一个枚举扫描工具类
- 第六步:代码测试
- 第七步:运行结果
- 第八步:实际使用说明
第一步:在 pom.xml 下导入 hutool 和 commons-lang3
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.0.M2</version>
</dependency>
<!--commons-lang3-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
第二步:写一个接口以规范枚举的属性
package com.zibo.api.myinterfaces;
// 枚举实现该接口,用于约束枚举必须有 key 和 value 两个字段,及其 getter 方法,以符合反射获取和调用方法
public interface MyEnum {
int getKey();
String getValue();
}
第三步:写一个枚举属性包装类
package com.zibo.api.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
// 封装枚举数据
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EnumDto {
private Integer key;
private String value;
}
第四步:写两个实体测试类
Dog
package com.zibo.api.enums;
import com.zibo.api.myinterfaces.MyEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
@AllArgsConstructor
public enum Dog implements MyEnum {
A(1, "刘备"),
B(2, "关羽"),
C(3, "张飞");
private int key;
private String value;
}
Cat
package com.zibo.api.enums;
import com.zibo.api.myinterfaces.MyEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
@AllArgsConstructor
public enum Cat implements MyEnum {
A(1, "大哥"),
B(2, "二哥"),
C(3, "三哥");
private int key;
private String value;
}
第五步:写一个枚举扫描工具类
注意使用时需要根据实际需求进行调整!
package com.zibo.api.utils;
import cn.hutool.core.util.ClassUtil;
import com.zibo.api.entity.EnumDto;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
// 获取枚举类的所有属性
public class EnumUtils {
// 扫描的包路径
private static final String basePackage = "com.zibo.api";
public static Map<String, List<EnumDto>> enums = null;
static {
try {
enums = getEnums();
} catch (InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
}
private EnumUtils() {}
private static Map<String, List<EnumDto>> getEnums() throws InvocationTargetException, IllegalAccessException {
// map 的规则是覆盖,如果存在多个相同的 key 不会报错,因此写一个 set 以验证之
Set<String> set = new HashSet<>();
// 扫描该包路径下所有class文件
Set<Class<?>> classes = ClassUtil.scanPackage(basePackage);
// 用来存放扫描到的符合要求的【所有枚举】信息,要求参考“ClassUtil.getDeclaredMethod”
Map<String, List<EnumDto>> enums = new HashMap<>();
// 用来存放【当前枚举】的所有属性
List<EnumDto> list;
for (Class<?> aClass : classes) {
// 判断类是否为枚举类型
if (ClassUtil.isEnum(aClass)) {
// 枚举必须有这两个字段,当然也可以根据需求定义更多,将 EnumDto 做相应调整即可!
Method keyMethod = ClassUtil.getDeclaredMethod(aClass, "getKey");
Method valueMethod = ClassUtil.getDeclaredMethod(aClass, "getValue");
if (keyMethod == null || valueMethod == null) continue;
// 得到 enum 的所有实例:一个数组,该数组包含组成此 Class 对象表示的枚举类的值,按它们声明的顺序
Object[] objs = aClass.getEnumConstants();
// 装载当前枚举所有值
list = new ArrayList<>();
for (Object obj : objs) list.add(new EnumDto((Integer) keyMethod.invoke(obj), (String) valueMethod.invoke(obj)));
// 装载当前枚举 list 到所有枚举 map
String enumName = aClass.getName().substring(aClass.getName().lastIndexOf(".") + 1);
String prefix = "com.zibo";
String moduleName = aClass.getName().substring(aClass.getName().indexOf(".", prefix.length()) + 1, aClass.getName().indexOf(".", prefix.length() + 1));
String key = StringUtils.join(moduleName, ".", enumName);
if (!set.add(key)) throw new RuntimeException("同一模块下存在重复枚举名!格式:模块名.枚举名,内容:" + key);
enums.put(key, list);
}
}
return enums;
}
}
第六步:代码测试
package com.zibo.api;
import com.zibo.api.utils.EnumUtils;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class MyEnumTest {
@Test
public void test() {
EnumUtils.enums.forEach((k, v) -> {
System.out.println(k + ":");
v.forEach(System.out::println);
});
}
}
第七步:运行结果
api.Dog:
EnumDto(code=1, text=刘备)
EnumDto(code=2, text=关羽)
EnumDto(code=3, text=张飞)
api.Cat:
EnumDto(code=1, text=大哥)
EnumDto(code=2, text=二哥)
EnumDto(code=3, text=三哥)
第八步:实际使用说明
1、(必须)要返回的枚举必须遵守 MyEnum 接口规范,不一定要实现该接口,但必须有 getKey 和 getValue 两个方法;
2、(建议)建议在登录完成后等场景调用一次该接口(写成的api接口),并缓存到客户端;
3、(提示)本接口全部相关类(用来测试的测试实体类除外):EnumDto、MyEnum、EnumUtils。