【Java】DynamicEnumKit (动态追加枚举元素)
Implementing dynamic append enum nodes
import lombok.NonNull;
import lombok.SneakyThrows;
import sun.reflect.ConstructorAccessor;
import sun.reflect.FieldAccessor;
import sun.reflect.ReflectionFactory;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
public class DynamicEnumKit {
private static final ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
private static void setFieldValueFailsafe(@NonNull 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(@NonNull Class<?> enumType, @NonNull String fieldName)
throws NoSuchFieldException, IllegalAccessException {
Field field = Class.class.getDeclaredField(fieldName);
field.setAccessible(true);
setFieldValueFailsafe(field, enumType, null);
}
private static void cleanEnumCache(@NonNull Class<?> enumType)
throws NoSuchFieldException, IllegalAccessException {
blankField(enumType, "enumConstantDirectory"); // Sun (Oracle?!?) JDK 1.5/6
blankField(enumType, "enumConstants"); // IBM JDK
}
private static ConstructorAccessor getConstructorAccessor(@NonNull Class<?> enumType,
@NonNull Class<?>[] additionalParamTypes)
throws NoSuchMethodException {
Class<?>[] paramTypes = new Class[additionalParamTypes.length + 2];
paramTypes[0] = String.class;
paramTypes[1] = int.class;
System.arraycopy(additionalParamTypes, 0, paramTypes, 2, additionalParamTypes.length);
return reflectionFactory.newConstructorAccessor(enumType.getDeclaredConstructor(paramTypes));
}
private static Object makeEnum(@NonNull Class<?> enumType,
String value, int ordinal,
@NonNull Class<?>[] additionalTypes,
@NonNull Object[] additionalValues) throws Exception {
Object[] param = new Object[additionalValues.length + 2];
param[0] = value;
param[1] = ordinal;
System.arraycopy(additionalValues, 0, param, 2, additionalValues.length);
return enumType.cast(getConstructorAccessor(enumType, additionalTypes).newInstance(param));
}
/**
* 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.
*/
@SneakyThrows
@SuppressWarnings("unchecked")
public static <T extends Enum<?>> void addEnum(@NonNull Class<T> enumType,
@NonNull String enumName,
@NonNull Class<?>[] additionalTypes,
@NonNull Object[] additionalValues) {
// 0. Sanity checks
if (!Enum.class.isAssignableFrom(enumType)) {
throw new RuntimeException("class " + enumType + " is not an instance of Enum");
}
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (enumType) {
// 1. Lookup "$VALUES" holder in enum class and get previous enum instances
Field field = enumType.getDeclaredField("$VALUES");
field.setAccessible(true);
// 2. Copy it
final T[] values = (T[]) field.get(enumType);
// 3. build new enum
final T newValue = (T) makeEnum(enumType, enumName, values.length, additionalTypes, additionalValues);
// 4. add new value
final T[] newValues = Arrays.copyOf(values, values.length + 1);
newValues[values.length] = newValue;
// 5. Set new values field
setFieldValueFailsafe(field, null, newValues);
// 6. Clean enum cache
cleanEnumCache(enumType);
}
}
}
本文作者:XKIND
本文链接:https://www.cnblogs.com/zhuzhongxing/p/17170903.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
分类:
Java
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步