JAVA动态添加枚举值

  1 import java.lang.reflect.AccessibleObject;
  2 import java.lang.reflect.Array;
  3 import java.lang.reflect.Field;
  4 import java.lang.reflect.Modifier;
  5 import java.util.ArrayList;
  6 import java.util.Arrays;
  7 import java.util.List;
  8 
  9 import sun.reflect.ConstructorAccessor;
 10 import sun.reflect.FieldAccessor;
 11 import sun.reflect.ReflectionFactory;
 12 
 13 /**
 14  * @Description: 动态枚举操作工具
 15  * @author wly
 16  * @date 2019年11月29日
 17  */
 18 @SuppressWarnings("restriction")
 19 public class DynamicEnumUtils {
 20     private static ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
 21 
 22     private static void setFailsafeFieldValue(Field field, Object target, Object value)
 23         throws NoSuchFieldException, IllegalAccessException {
 24 
 25         field.setAccessible(true);
 26 
 27         Field modifiersField = Field.class.getDeclaredField("modifiers");
 28         modifiersField.setAccessible(true);
 29         int modifiers = modifiersField.getInt(field);
 30 
 31         modifiers &= ~Modifier.FINAL;
 32         modifiersField.setInt(field, modifiers);
 33 
 34         FieldAccessor fa = reflectionFactory.newFieldAccessor(field, false);
 35         fa.set(target, value);
 36     }
 37 
 38     private static void blankField(Class<?> enumClass, String fieldName)
 39         throws NoSuchFieldException, IllegalAccessException {
 40         for (Field field : Class.class.getDeclaredFields()) {
 41             if (field.getName().contains(fieldName)) {
 42                 AccessibleObject.setAccessible(new Field[] {field}, true);
 43                 setFailsafeFieldValue(field, enumClass, null);
 44                 break;
 45             }
 46         }
 47     }
 48 
 49     private static void cleanEnumCache(Class<?> enumClass) throws NoSuchFieldException, IllegalAccessException {
 50         blankField(enumClass, "enumConstantDirectory"); // Sun (Oracle?!?) JDK 1.5/6
 51         blankField(enumClass, "enumConstants"); // IBM JDK
 52     }
 53 
 54     private static ConstructorAccessor getConstructorAccessor(Class<?> enumClass, Class<?>[] additionalParameterTypes)
 55         throws NoSuchMethodException {
 56         Class<?>[] parameterTypes = new Class[additionalParameterTypes.length + 2];
 57         parameterTypes[0] = String.class;
 58         parameterTypes[1] = int.class;
 59         System.arraycopy(additionalParameterTypes, 0, parameterTypes, 2, additionalParameterTypes.length);
 60         return reflectionFactory.newConstructorAccessor(enumClass.getDeclaredConstructor(parameterTypes));
 61     }
 62 
 63     private static Object makeEnum(Class<?> enumClass, String value, int ordinal, Class<?>[] additionalTypes,
 64         Object[] additionalValues) throws Exception {
 65         Object[] parms = new Object[additionalValues.length + 2];
 66         parms[0] = value;
 67         parms[1] = Integer.valueOf(ordinal);
 68         System.arraycopy(additionalValues, 0, parms, 2, additionalValues.length);
 69         return enumClass.cast(getConstructorAccessor(enumClass, additionalTypes).newInstance(parms));
 70     }
 71 
 72     @SuppressWarnings("unchecked")
 73     public static <T extends Enum<?>> void addEnum(Class<T> enumType, String enumName, Class<?>[] additionalTypes,
 74         Object[] additionalValues) {
 75 
 76         // 判断该枚举类是否继承自枚举Enum
 77         if (!Enum.class.isAssignableFrom(enumType)) {
 78             throw new RuntimeException("class " + enumType + " is not an instance of Enum");
 79         }
 80 
 81         // 1. Lookup "$VALUES" holder in enum class and get previous enum instances
 82         Field valuesField = null;
 83         Field[] fields = enumType.getDeclaredFields();
 84         for (Field field : fields) {
 85             if (field.getName().contains("$VALUES")) {
 86                 valuesField = field;
 87                 break;
 88             }
 89         }
 90         AccessibleObject.setAccessible(new Field[] {valuesField}, true);
 91 
 92         try {
 93 
 94             // 2. Copy it
 95             T[] previousValues = (T[])valuesField.get(enumType);
 96             List<T> values = new ArrayList<T>(Arrays.asList(previousValues));
 97 
 98             // 3. build new enum
 99             T newValue = (T)makeEnum(enumType, enumName, values.size(), additionalTypes, additionalValues);
100 
101             // 4. add new value
102             values.add(newValue);
103 
104             // 5. Set new values field
105             setFailsafeFieldValue(valuesField, null, values.toArray((T[])Array.newInstance(enumType, 0)));
106 
107             // 6. Clean enum cache
108             cleanEnumCache(enumType);
109 
110         } catch (Exception e) {
111             throw new RuntimeException(e.getMessage(), e);
112         }
113     }
114 }
原文地址:https://www.cnblogs.com/wly1-6/p/14448910.html