358 lines
14 KiB
Java
358 lines
14 KiB
Java
package com.engine.salary.util;
|
||
|
||
|
||
import lombok.extern.slf4j.Slf4j;
|
||
import sun.reflect.ConstructorAccessor;
|
||
import sun.reflect.FieldAccessor;
|
||
import sun.reflect.MethodAccessor;
|
||
import sun.reflect.ReflectionFactory;
|
||
|
||
import java.lang.reflect.Constructor;
|
||
import java.lang.reflect.Field;
|
||
import java.lang.reflect.Method;
|
||
import java.lang.reflect.Modifier;
|
||
import java.util.ArrayList;
|
||
import java.util.Arrays;
|
||
import java.util.List;
|
||
|
||
@Slf4j
|
||
public class EnumUtil {
|
||
|
||
/**
|
||
* 扩展枚举(把新枚举的值加入旧枚举里,从旧枚举里删除不要的枚举值)
|
||
* @param oldEnumClass 旧枚举类
|
||
* @param newEnumClass 需要扩展的枚举类
|
||
* @param removeOldEnums 需要删除的旧枚举值
|
||
* @param <O>
|
||
* @param <N>
|
||
* @throws Exception
|
||
*/
|
||
public static <O extends Enum,N extends Enum> void extendEnum(Class<O> oldEnumClass,Class<N> newEnumClass,O... removeOldEnums) throws Exception {
|
||
boolean needToRemoveOldEnum = removeOldEnums!=null&&removeOldEnums.length>0;
|
||
if(needToRemoveOldEnum){
|
||
removeEnum(oldEnumClass,removeOldEnums);
|
||
}
|
||
List newEnums = values(newEnumClass);
|
||
Field[] fields = getFields(newEnumClass);
|
||
for (Object newEnumObject : newEnums) {
|
||
Enum newEnum = Enum.class.cast(newEnumObject);
|
||
|
||
List<Class> fieldTypeList = new ArrayList<>();
|
||
//枚举名称的类型:String.class
|
||
fieldTypeList.add(String.class);
|
||
for (Field field : fields) {
|
||
fieldTypeList.add(field.getType());
|
||
}
|
||
List<Object> fieldValueList = new ArrayList<>();
|
||
//枚举名称
|
||
fieldValueList.add(newEnum.name());
|
||
for (Field field : fields) {
|
||
Object value = field.get(newEnum);
|
||
fieldValueList.add(value);
|
||
}
|
||
|
||
Class[] fieldTypes = fieldTypeList.toArray(new Class[]{});
|
||
String[] fieldValues = fieldValueList.toArray(new String[]{});
|
||
addEnum(oldEnumClass,fieldTypes,fieldValues);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 新增枚举值
|
||
* @param enumClass 枚举类型
|
||
* @param fieldTypes 字段的类型,第一个是枚举名类型String
|
||
* @param fieldValues 字段的值,第一个是枚举名称
|
||
* @throws Exception
|
||
*/
|
||
public static <T extends Enum<T>> T addEnum(Class<T> enumClass, Class[] fieldTypes, Object[] fieldValues) throws Exception {
|
||
if(fieldTypes==null||fieldTypes.length==0){
|
||
throw new RuntimeException("参数fieldTypes为空");
|
||
}
|
||
if(fieldValues==null||fieldValues.length==0){
|
||
throw new RuntimeException("参数fieldValues为空");
|
||
}
|
||
if(fieldTypes[0]!=String.class){
|
||
throw new RuntimeException("参数fieldTypes[0]不是String.class");
|
||
}
|
||
if(!(fieldValues[0] instanceof String)){
|
||
throw new RuntimeException("参数fieldValues[0]不是字符串");
|
||
}
|
||
if(fieldTypes.length!=fieldValues.length){
|
||
throw new RuntimeException("参数fieldTypes和参数fieldValues的长度不一致");
|
||
}
|
||
ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
|
||
String enumName = fieldValues[0].toString();
|
||
synchronized (enumClass){
|
||
//判断name是否已经添加过了
|
||
if(hasEnumName(enumClass,enumName)){
|
||
log.info("枚举类{}中已存在该枚举名:{}",enumClass.getSimpleName(),enumName);
|
||
return getEnum(enumClass,enumName);
|
||
}
|
||
//name,ordinal,其他自定义字段
|
||
List<Class> allFieldClass = new ArrayList<>(fieldTypes.length + 1);
|
||
allFieldClass.add(String.class);
|
||
allFieldClass.add(int.class);
|
||
for (int i = 1; i < fieldTypes.length; i++) {
|
||
allFieldClass.add(fieldTypes[i]);
|
||
}
|
||
Class[] classes = allFieldClass.toArray(new Class[]{});
|
||
Constructor<T> constructor = enumClass.getDeclaredConstructor(classes);
|
||
ConstructorAccessor constructorAccessor = reflectionFactory.newConstructorAccessor(constructor);
|
||
List<Object> allFields = new ArrayList<>(fieldValues.length + 1);
|
||
allFields.add(enumName);
|
||
int maxOrdinal = getMaxOrdinal(enumClass);
|
||
allFields.add(maxOrdinal+1);
|
||
for (int i = 1; i < fieldValues.length; i++) {
|
||
allFields.add(fieldValues[i]);
|
||
}
|
||
//调用枚举的构造方法,创建新的枚举值
|
||
T newEnum = (T) constructorAccessor.newInstance(allFields.toArray());
|
||
log.info("新增枚举:{}" , newEnum);
|
||
Field valuesField = enumClass.getDeclaredField("$VALUES");
|
||
valuesField.setAccessible(true);
|
||
|
||
//解除values属性的final限制
|
||
Field modifiersField = Field.class.getDeclaredField("modifiers");
|
||
modifiersField.setAccessible(true);
|
||
int modifiers = modifiersField.getInt(valuesField);
|
||
modifiers &= ~Modifier.FINAL;
|
||
modifiersField.setInt(valuesField, modifiers);
|
||
|
||
//将新增的枚举值加入values属性里
|
||
FieldAccessor fieldAccessor = reflectionFactory.newFieldAccessor(valuesField, false);
|
||
T[] ts = (T[]) fieldAccessor.get(enumClass);
|
||
List<T> list = new ArrayList<>(Arrays.asList(ts));
|
||
list.add(newEnum);
|
||
fieldAccessor.set(enumClass, list.toArray(ts));
|
||
|
||
//将Class对象的enumConstants和enumConstantDirectory清空(Enum.valueOf()方法会给它们赋值)
|
||
/**
|
||
* Enum.valueOf()逻辑:
|
||
* 1.取enumConstantDirectory
|
||
* 1.1如果有值则直接返回
|
||
* 1.2如果没值,则取enumConstants,并拷贝到enumConstantDirectory,下次可直接返回
|
||
* 1.2.1如果enumConstants有值,则返回
|
||
* 1.2.2如果enumConstants没值,则取枚举的values属性,并拷贝到enumConstants,下次可直接返回
|
||
* 2.enumConstantDirectory.get(name)返回
|
||
*/
|
||
Field enumConstantDirectoryField = enumClass.getClass().getDeclaredField("enumConstantDirectory");
|
||
enumConstantDirectoryField.setAccessible(true);
|
||
FieldAccessor enumConstantDirectoryFieldAccessor = reflectionFactory.newFieldAccessor(enumConstantDirectoryField, false);
|
||
enumConstantDirectoryFieldAccessor.set(enumClass,null);
|
||
Field enumConstantsField = enumClass.getClass().getDeclaredField("enumConstants");
|
||
enumConstantsField.setAccessible(true);
|
||
FieldAccessor enumConstantsFieldAccessor = reflectionFactory.newFieldAccessor(enumConstantsField, false);
|
||
enumConstantsFieldAccessor.set(enumClass,null);
|
||
return newEnum;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取枚举类当前最大序号
|
||
* @param enumClass 枚举类型
|
||
* @param <T>
|
||
* @return
|
||
* @throws Exception
|
||
*/
|
||
public static <T extends Enum<T>> int getMaxOrdinal(Class<T> enumClass) throws Exception {
|
||
List<T> values = values(enumClass);
|
||
if(values==null||values.size()==0){
|
||
return 0;
|
||
}
|
||
int maxOrdinal = 0;
|
||
for (T value : values) {
|
||
if(maxOrdinal<value.ordinal()){
|
||
maxOrdinal = value.ordinal();
|
||
}
|
||
}
|
||
return maxOrdinal;
|
||
}
|
||
|
||
/**
|
||
* 删除枚举值
|
||
* @param enumClass 枚举类型
|
||
* @param removeOldEnums 需要删除的枚举值
|
||
* @param <T>
|
||
*/
|
||
public static <T extends Enum<T>> void removeEnum(Class<T> enumClass, Enum<T>... removeOldEnums) throws Exception {
|
||
if(removeOldEnums==null||removeOldEnums.length==0){
|
||
log.warn("removeOldEnums为空");
|
||
return;
|
||
}
|
||
ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
|
||
synchronized (enumClass){
|
||
Field valuesField = enumClass.getDeclaredField("$VALUES");
|
||
valuesField.setAccessible(true);
|
||
|
||
//解除values属性的final限制
|
||
Field modifiersField = Field.class.getDeclaredField("modifiers");
|
||
modifiersField.setAccessible(true);
|
||
int modifiers = modifiersField.getInt(valuesField);
|
||
modifiers &= ~Modifier.FINAL;
|
||
modifiersField.setInt(valuesField, modifiers);
|
||
|
||
FieldAccessor fieldAccessor = reflectionFactory.newFieldAccessor(valuesField, false);
|
||
T[] oldEnumArray = (T[]) fieldAccessor.get(enumClass);
|
||
List<T> enumList = new ArrayList<>(Arrays.asList(oldEnumArray));
|
||
for (Enum removeOldEnum : removeOldEnums) {
|
||
//将指定的枚举值从values属性里删除
|
||
enumList.remove(removeOldEnum);
|
||
log.info("删除枚举值:{}",removeOldEnum);
|
||
}
|
||
//把List转成数组
|
||
T[] newEnumArray = (T[]) Arrays.copyOf(enumList.toArray(), enumList.size(), oldEnumArray.getClass());
|
||
fieldAccessor.set(enumClass, newEnumArray);
|
||
}
|
||
}
|
||
/**
|
||
* 修改枚举属性
|
||
* @param enumClass 枚举类型
|
||
* @param enumName 枚举名称
|
||
* @param attributeName 属性名
|
||
* @param attributeValue 属性值
|
||
* @param <T>
|
||
* @throws Exception
|
||
*/
|
||
public static <T extends Enum<T>> void setAttribute(Class<T> enumClass,String enumName,String attributeName,Object attributeValue) throws Exception {
|
||
List<T> values = values(enumClass);
|
||
T target = null;
|
||
for (T t:values){
|
||
if(t.name().equals(enumName)){
|
||
target = t;
|
||
break;
|
||
}
|
||
}
|
||
if(target==null){
|
||
throw new RuntimeException("该枚举类没有枚举名:"+enumName);
|
||
}
|
||
Field declaredField = target.getClass().getDeclaredField(attributeName);
|
||
declaredField.setAccessible(true);
|
||
declaredField.set(target,attributeValue);
|
||
}
|
||
|
||
/**
|
||
* 修改枚举属性
|
||
* @param targetEnum 枚举值
|
||
* @param attributeName 属性名
|
||
* @param attributeValue 属性值
|
||
* @param <T>
|
||
* @throws Exception
|
||
*/
|
||
public static <T extends Enum<T>> void setAttribute(T targetEnum,String attributeName,Object attributeValue) throws Exception {
|
||
Field declaredField = targetEnum.getClass().getDeclaredField(attributeName);
|
||
declaredField.setAccessible(true);
|
||
declaredField.set(targetEnum,attributeValue);
|
||
}
|
||
|
||
/**
|
||
* 判断枚举类是否包含了指定枚举名
|
||
* @param clazz
|
||
* @param enumName
|
||
* @param <T>
|
||
* @return
|
||
*/
|
||
public static <T extends Enum<T>> boolean hasEnumName(Class<T> clazz, String enumName) throws Exception {
|
||
// 不要用valueOf方法,因为它会初始化enumConstantDirectory使得后续调用valueOf方法后拿不到后面加入的枚举值
|
||
// try{
|
||
// T t = Enum.valueOf(clazz, enumName);
|
||
// if(t!=null){
|
||
// return true;
|
||
// }
|
||
// }catch (Exception e){
|
||
// e.printStackTrace();
|
||
// System.err.println(e.getMessage());
|
||
// }
|
||
List<T> values = values(clazz);
|
||
for (T t:values){
|
||
if(t.name().equals(enumName)){
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 根据枚举类型和枚举名获取枚举值
|
||
* @param clazz 枚举类型
|
||
* @param enumName 枚举名称
|
||
* @param <T>
|
||
* @return
|
||
* @throws Exception
|
||
*/
|
||
public static <T extends Enum<T>> T getEnum(Class<T> clazz, String enumName) throws Exception {
|
||
List<T> values = values(clazz);
|
||
for (T t:values){
|
||
if(t.name().equals(enumName)){
|
||
return t;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* 获取枚举类的所有枚举值
|
||
* @param clazz 枚举类型
|
||
* @param <T>
|
||
* @return
|
||
* @throws Exception
|
||
*/
|
||
public static <T extends Enum<T>> List<T> values(Class<T> clazz) throws Exception {
|
||
ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
|
||
Field valuesField = clazz.getDeclaredField("$VALUES");
|
||
valuesField.setAccessible(true);
|
||
FieldAccessor fieldAccessor = reflectionFactory.newFieldAccessor(valuesField, false);
|
||
T[] ts = (T[]) fieldAccessor.get(clazz);
|
||
List<T> list = new ArrayList<>(Arrays.asList(ts));
|
||
return list;
|
||
}
|
||
|
||
/**
|
||
* 获取枚举类的所有枚举值
|
||
* @param clazz 枚举类型
|
||
* @param <T>
|
||
* @return
|
||
* @throws Exception
|
||
*/
|
||
public static <T extends Enum<T>> List<T> values2(Class<T> clazz) throws Exception {
|
||
ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
|
||
Method valuesMethod = clazz.getDeclaredMethod("values");
|
||
valuesMethod.setAccessible(true);
|
||
MethodAccessor methodAccessor = reflectionFactory.newMethodAccessor(valuesMethod);
|
||
T[] ts = (T[]) methodAccessor.invoke(clazz, null);
|
||
List<T> list = new ArrayList<>(Arrays.asList(ts));
|
||
return list;
|
||
}
|
||
|
||
/**
|
||
* 获取枚举的字段(排除数组类型、枚举类型)
|
||
* @param enumClass
|
||
* @return
|
||
*/
|
||
public static Field[] getFields(Class<? extends Enum> enumClass){
|
||
List<Field> result = new ArrayList<>();
|
||
Field[] declaredFields = enumClass.getDeclaredFields();
|
||
for (Field field : declaredFields) {
|
||
Class<?> type = field.getType();
|
||
//排除数组类型(values)、枚举类型(枚举值)
|
||
if(type!=enumClass && !type.isArray()){
|
||
field.setAccessible(true);
|
||
result.add(field);
|
||
}
|
||
}
|
||
return result.toArray(new Field[]{});
|
||
}
|
||
|
||
/**
|
||
* 打印枚举值
|
||
* @param enumClass 枚举类型
|
||
* @throws Exception
|
||
*/
|
||
public static void printEnum(Class<? extends Enum> enumClass) throws Exception {
|
||
System.out.println("+++++++++++++++++++++++");
|
||
List values = values(enumClass);
|
||
values.stream().forEach(System.out::println);
|
||
System.out.println("+++++++++++++++++++++++");
|
||
}
|
||
|
||
}
|