枚举动态修改

动态枚举

 

package com.xd100.lzll;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.xd100.lzll.db.po.Goods;
import com.xd100.lzll.module.log.description.GoodsDsp;
import sun.reflect.ConstructorAccessor;
import sun.reflect.FieldAccessor;
import sun.reflect.ReflectionFactory;

/**
 *
 * @author Jason Yang
 * @version 1.0  2017年3月16日下午7:43:41
 */
public class DynamicEnumTest {
	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
	   }

	   private static ConstructorAccessor getConstructorAccessor(Class enumClass, Class[] additionalParameterTypes)
	           throws NoSuchMethodException {
	       Class[] parameterTypes = new Class[additionalParameterTypes.length + 5];
		   parameterTypes[0] = String.class;
		   parameterTypes[1] = int.class;
		   parameterTypes[2] = int.class;
		   parameterTypes[3] = String.class;
	       parameterTypes[4] = int.class;
	       System.arraycopy(additionalParameterTypes, 0, parameterTypes, 5, additionalParameterTypes.length);
	       return reflectionFactory.newConstructorAccessor(enumClass.getDeclaredConstructor(parameterTypes));
	   }

	   private static Object makeEnum(Class enumClass, String value, int ordinal, Class[] additionalTypes,
	           Object[] additionalValues) throws Exception {
	       Object[] parms = new Object[additionalValues.length + 5];
		   parms[0] = value;
		   parms[1] = Integer.valueOf(ordinal);
		   parms[2] = Integer.valueOf(12041);
		   parms[3] = "啊";
		   parms[4] = Integer.valueOf(3);
	       System.arraycopy(additionalValues, 0, parms, 5, additionalValues.length);
	       return enumClass.cast(getConstructorAccessor(enumClass, additionalTypes).newInstance(parms));
	   }

	   /**
	    * Add an enum instance to the enum class given as argument
	    *
	    * @param  the type of the enum (implicit)
	    * @param enumType the class of the enum to be modified
	    * @param enumName the name of the new enum instance to be added to the class.
	    */
	   @SuppressWarnings("unchecked")
	   public static > void addEnum(Class enumType, String enumName) {

	       // 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 = GoodsDsp.class.getDeclaredFields();
	       for (Field field : fields) {
	           if (field.getName().contains("$VALUES")) {
	               valuesField = field;
	               break;
	           }
	       }
	       AccessibleObject.setAccessible(new Field[] { valuesField }, true);

	       try {

	           // 2. Copy it
	           T[] previousValues = (T[]) valuesField.get(enumType);
	           List values = new ArrayList(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
	                   new Object[] {}); // could be used to pass values to the enum constuctor if needed

	           // 4. add new value
	           values.add(newValue);

	           // 5. Set new values field
	           setFailsafeFieldValue(valuesField, null, values.toArray((T[]) Array.newInstance(enumType, 0)));

	           // 6. Clean enum cache
	           cleanEnumCache(enumType);

	       } catch (Exception e) {
	           e.printStackTrace();
	           throw new RuntimeException(e.getMessage(), e);
	       }
	   }


	   public static void main(String[] args) {

	       // Dynamically add 3 new enum instances d, e, f to TestEnum
	       addEnum(GoodsDsp.class, "gAstrologyPrize");

	       // Run a few tests just to show it works OK.
	       System.out.println(Arrays.deepToString(GoodsDsp.values()));
	       // Shows : [a, b, c, d, e, f]
	   }
}

 

 

你可能感兴趣的:(游戏研发)