動態修改Java 列舉類的值
阿新 • • 發佈:2019-02-06
參考地址:111
package com.itmuch.empty; import javassist.ClassPool; import javassist.CtClass; import javassist.CtField; import sun.reflect.ConstructorAccessor; import sun.reflect.FieldAccessor; import sun.reflect.ReflectionFactory; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Array; 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; public class DynamicEnumUtil { public static void addField(String classname, String[] fields) throws Exception { ClassPool pool = ClassPool.getDefault(); // pool.appendClassPath(new LoaderClassPath(ByteUtil.class.getClassLoader())); // pool.insertClassPath(Thread.currentThread().getContextClassLoader().getResource(".").getFile()); CtClass cc = pool.get(classname); for (String field : fields) { field = field.trim().toUpperCase(); CtField ctf = new CtField(cc, field, cc); ctf.setModifiers(Modifier.PUBLIC); cc.addField(ctf); } Class c = cc.toClass(); addEnum(c, fields, new Class<?>[] {}, new Object[] {}); } public static <T> void addEnum(Class enumType, String[] enumNames, Class<?>[] paramClass, Object[] paramValue) { // 0. Sanity checks if (!Enum.class.isAssignableFrom(enumType)) { throw new RuntimeException("class " + enumType + " is not an instance of Enum"); } // 1. Lookup "$VALUES" holder in enum class and get previous enum instances Field valuesField = null; Field[] fields = enumType.getDeclaredFields(); Method[] methods = enumType.getDeclaredMethods(); for (Field field : fields) { if (field.getName().contains("$VALUES")) { valuesField = field; break; } } AccessibleObject.setAccessible(new Field[] { valuesField }, true); try { for (String enumName : enumNames) { enumName = enumName.trim().toUpperCase(); // 2. Copy it T[] previousValues = (T[]) valuesField.get(enumType); List<T> values = new ArrayList<T>(Arrays.asList(previousValues)); // 3. build new enum T newValue = (T) makeEnum(enumType, // The target enum class enumName, // THE NEW ENUM INSTANCE TO BE DYNAMICALLY ADDED values.size(), // new Class<?>[] {}, // could be used to pass values to the enum constuctor if needed paramClass, // new Object[] {} paramValue); // could be used to pass values to the enum constuctor if needed // 4. add new value values.add(newValue); Object object = values.toArray((T[]) Array.newInstance(enumType, 0)); // 5. Set new values field setFailsafeFieldValue(valuesField, null, object); // 6. Clean enum cache cleanEnumCache(enumType); } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e.getMessage(), e); } } private static Object makeEnum(Class<?> enumClass, String value, int ordinal, Class<?>[] additionalTypes, Object[] additionalValues) throws Exception { Object[] parms = new Object[additionalValues.length + 2]; parms[0] = value; parms[1] = Integer.valueOf(ordinal); System.arraycopy(additionalValues, 0, parms, 2, additionalValues.length); return enumClass.cast(getConstructorAccessor(enumClass, additionalTypes).newInstance(parms)); } private static ConstructorAccessor getConstructorAccessor(Class<?> enumClass, Class<?>[] additionalParameterTypes) throws NoSuchMethodException { Class<?>[] parameterTypes = new Class[additionalParameterTypes.length + 2]; parameterTypes[0] = String.class; parameterTypes[1] = int.class; System.arraycopy(additionalParameterTypes, 0, parameterTypes, 2, additionalParameterTypes.length); return reflectionFactory.newConstructorAccessor(enumClass.getDeclaredConstructor(parameterTypes)); } private static ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory(); private static void setFailsafeFieldValue(Field field, Object target, Object value) throws NoSuchFieldException, IllegalAccessException { // let's make the field accessible field.setAccessible(true); // next we change the modifier in the Field instance to // not be final anymore, thus tricking reflection into // letting us modify the static final field Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); int modifiers = modifiersField.getInt(field); // blank out the final bit in the modifiers int modifiers &= ~Modifier.FINAL; modifiersField.setInt(field, modifiers); FieldAccessor fa = reflectionFactory.newFieldAccessor(field, false); fa.set(target, value); } private static void blankField(Class<?> enumClass, String fieldName) throws NoSuchFieldException, IllegalAccessException { for (Field field : Class.class.getDeclaredFields()) { if (field.getName().contains(fieldName)) { AccessibleObject.setAccessible(new Field[] { field }, true); setFailsafeFieldValue(field, enumClass, null); break; } } } private static void cleanEnumCache(Class<?> enumClass) throws NoSuchFieldException, IllegalAccessException { blankField(enumClass, "enumConstantDirectory"); // Sun (Oracle?!?) JDK 1.5/6 blankField(enumClass, "enumConstants"); // IBM JDK } public static void main(String[] args) throws Exception { addField("com.ctrip.framework.apollo.core.enums.Env", new String[] { "mj1", "mj2" }); Gson gson = new Gson(); System.out.println(Env.valueOf("MJ1")); System.out.println(gson.toJson(Env.values())); System.out.println(gson.toJson(Env.valueOf("MJ1"))); System.out.println(gson.toJson(Env.valueOf("MJ2"))); // addEnum(Env.class, "testmj", new Class<?>[]{}, new Object[]{}); // for(Env codeInfo:Env.values()){ // System.out.println(codeInfo.toString()); // } // String test="{\"test1\":\"123\",\"test2\":\"456\"}"; // Gson gson = new Gson(); // Map<String,String> map = gson.fromJson(test, Map.class); // System.out.println(gson.toJson(Env.valueOf("testmj"))); } }