动态生成枚举工具类DynamicEnumUtil

该博客介绍了如何使用反射在运行时动态地修改Java枚举类的静态常量和缓存,以及创建新的枚举实例。主要方法包括通过反射工厂设置字段访问权限,清除枚举缓存,以及利用构造访问器生成枚举实例。内容涉及Java反射API的深入应用。
摘要由CSDN通过智能技术生成
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/6
    blankField(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);
    //       parms[1] = parms[parms.length-1];
    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<?>> T 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);

      // 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);
      return newValue;
    } catch (Exception e) {
      e.printStackTrace();
      throw new RuntimeException(e.getMessage(), e);
    }
  }

}

测试:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

焱童鞋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值