java dynamic update enumeration class

At work, it is necessary to dynamically update the value of the enumeration class. It is unrealistic and inconvenient to manually change it. Now it is recorded for future learning and use.

1. Add a tool class for dynamically updating the enumeration class in the project utils package (according to your own project, you can call it in the specified location)

2. I fell into a misunderstanding at the beginning, thinking that I should modify it according to my own enumeration class. The addEnum and makeEnum methods have two parameters because the online examples are all.

And mine is 5. It took me a long time to find out that it is an array.

package com.genju.ziji.dexiangmu.util;

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.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
* Dynamically add enumeration tool class
*/
public class DynamicEnumUtil { 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/6blankField(enumClass, "enumConstants"); // IBM JDK}


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 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));}





/**
* 判断枚举是否已存在
*
* @param values
* @param enumName
* @param <T>
* @return
*/
public static <T extends Enum<?>> boolean contains(List<T> values, String enumName) { for (T value : values) { if (value.name().equals(enumName)) { return true;}}return false;}







/**
* Add an enum instance to the enum class given as argument
*
* @param <T> 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 <T extends Enum<?>> void addEnum(Class<T> enumType, String enumName, Class<?>[] additionalTypes, Object[] additionalValues) {

// 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();
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<T> values = new ArrayList<T>(Arrays.asList(previousValues));

// 3. build new enum
T newValue = (T) makeEnum(enumType, enumName, values.size(), additionalTypes, additionalValues);

if (contains(values, enumName)) { System.out.println("Enum:" + enumName + " 已存在");return;}


// 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);}}



}

3. Test

public static void main(String args[]) {

  addEnum("1","2","3","4","5");

  for(SubBank e : SunBank.values()){

    System.out.println(e.getBankName());

  }

}

private static void addEnum(String enumName,String id,String name,String desc,AreaType       areaType,List<Class<? extends Enum>> paramTypes){

      DynamicEnumUtil.addEnum(Subank.class,enumName,

      new Class<?>[]{Stirng.class,String.class,AreaType.class,List.Class}, 

      new object[]{id,nae,desc,areaType,paramTypes});

  }

 

Finally, the effect of printing is ok and can be added. I am writing the enumeration class directly here. If necessary, it can also be made dynamic according to your own needs;

If there is any inaccuracy, please give pointers

Reprinted in: https://www.cnblogs.com/KpGo/p/11527473.html

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326486256&siteId=291194637