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 * @param * @throws Exception */ public static void extendEnum(Class oldEnumClass,Class 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 fieldTypeList = new ArrayList<>(); //枚举名称的类型:String.class fieldTypeList.add(String.class); for (Field field : fields) { fieldTypeList.add(field.getType()); } List 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 addEnum(Class 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 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 constructor = enumClass.getDeclaredConstructor(classes); ConstructorAccessor constructorAccessor = reflectionFactory.newConstructorAccessor(constructor); List 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 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 * @return * @throws Exception */ public static > int getMaxOrdinal(Class enumClass) throws Exception { List values = values(enumClass); if(values==null||values.size()==0){ return 0; } int maxOrdinal = 0; for (T value : values) { if(maxOrdinal */ public static > void removeEnum(Class enumClass, Enum... 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 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 * @throws Exception */ public static > void setAttribute(Class enumClass,String enumName,String attributeName,Object attributeValue) throws Exception { List 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 * @throws Exception */ public static > 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 * @return */ public static > boolean hasEnumName(Class 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 values = values(clazz); for (T t:values){ if(t.name().equals(enumName)){ return true; } } return false; } /** * 根据枚举类型和枚举名获取枚举值 * @param clazz 枚举类型 * @param enumName 枚举名称 * @param * @return * @throws Exception */ public static > T getEnum(Class clazz, String enumName) throws Exception { List values = values(clazz); for (T t:values){ if(t.name().equals(enumName)){ return t; } } return null; } /** * 获取枚举类的所有枚举值 * @param clazz 枚举类型 * @param * @return * @throws Exception */ public static > List values(Class 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 list = new ArrayList<>(Arrays.asList(ts)); return list; } /** * 获取枚举类的所有枚举值 * @param clazz 枚举类型 * @param * @return * @throws Exception */ public static > List values2(Class 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 list = new ArrayList<>(Arrays.asList(ts)); return list; } /** * 获取枚举的字段(排除数组类型、枚举类型) * @param enumClass * @return */ public static Field[] getFields(Class enumClass){ List 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 enumClass) throws Exception { System.out.println("+++++++++++++++++++++++"); List values = values(enumClass); values.stream().forEach(System.out::println); System.out.println("+++++++++++++++++++++++"); } }