java枚举处理工具

package michael.spica.tool.lang;

import michael.spica.tool.common.Strings;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 枚举工具类
 * <p>
 * Created by michael on 2015-11-26
 */
public class Enums extends EnumSupport {

    /**
     * 根据字符串名称(忽略大小写)获取对应枚举中的属性
     *
     * @param <T>
     * @param name  字符串
     * @param clazz 枚举类
     * @return
     */
    public static <T extends Enum<?>> T get(String name, Class<T> clazz) {
        if (!clazz.isEnum()) {
            throw new IllegalArgumentException(clazz + " not an enumeration class.");
        } else {
            Enum[] values = clazz.getEnumConstants();
            Enum[] arr = values;
            for (int i = 0; i < values.length; ++i) {
                Enum<?> value = arr[i];
                if (Strings.equalsIgnoreCase(value.name(), name)) {
                    return ((T) value);
                }
            }
            return null;
        }
    }

    /**
     * 根据字符串名称(忽略大小写)获取对应枚举中的属性
     *
     * @param <T>
     * @param name         字符串
     * @param clazz        枚举类
     * @param defaultValue 默认值
     * @return
     */
    public static <T extends Enum<?>> T get(String name, Class<T> clazz, T defaultValue) {
        Enum<?> value = get(name, clazz);
        return (T) (value == null ? defaultValue : value);
    }

    /**
     * 将Enum转换成List
     *
     * @param <T>
     * @param clazz
     * @return
     */
    public static <T extends Enum<?>> List<T> toList(Class<T> clazz) {
        return Arrays.asList(clazz.getEnumConstants());
    }

    /**
     * 将Enum转换成Map
     *
     * @param <T>
     * @param clazz
     * @param methodName Enum类的指定的方法,当methodName=null时,默认为Enum.name方法<br>
     *                   e.g: <br>
     *                   model.addAttribute("tradeStatusMap", Enums.toMap(Enums.TradeStatus.class,"getValue"));<br>
     *                   ${tradeStatusMap[key].desc},key为入参methodName的值
     * @return
     */
    public static <T extends Enum<?>> Map<Object, T> toMap(Class<T> clazz, String methodName) {
        return enumConstantDirectory(clazz, methodName);
    }
}
package michael.spica.tool.lang;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by michael on 2015-11-26.
 */
public abstract class EnumSupport extends EnumSupportWithDynamic {

    public EnumSupport() {
    }

    protected static <T extends Enum<?>> Map<Object, T> enumConstantDirectory(Class<T> clazz, String methodName) {
        Map<Object, T> directory = null;
        if (directory == null) {
            T[] universe = getEnumConstantsShared(clazz);
            if (universe == null){
                throw new IllegalArgumentException(clazz.getName() + " is not an enum type.");
            }
            Map<Object, T> m = new HashMap<Object, T>(2 * universe.length);
            for (T constant : universe)
                try {
                    Object key = null;
                    if (methodName != null && methodName.trim().length() > 0) {
                        Method method = constant.getClass().getMethod(methodName);
                        key = method.invoke(constant);
                    } else {
                        key = (constant).name(); // 默认KEY为ENUM的NAME
                    }
                    m.put(key, constant);
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }

            directory = m;
        }
        return directory;
    }

    private static <T extends Enum<?>> T[] getEnumConstantsShared(Class<T> clazz) {
        T[] enumConstants = null;
        if (enumConstants == null) {
            if (!clazz.isEnum())
                return null;
            try {
                final Method values = clazz.getMethod("values");
                AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
                    values.setAccessible(true);
                    return null;
                });
                T[] temporaryConstants = (T[]) values.invoke(null);
                enumConstants = temporaryConstants;
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            }
        }
        return enumConstants;
    }
}
package michael.spica.tool.lang;

import org.apache.commons.lang3.StringUtils;
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;
import java.util.stream.Stream;

/**
 * 枚举动态支持(即:程序运行时动态增加枚举类型)
 * <p>
 * Created by michael on 2015-11-26.
 */
public abstract class EnumSupportWithDynamic {

    public EnumSupportWithDynamic() {
    }

    private static ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();

    public static <T extends Enum<?>> void addEnum(Class<T> enumClass, List<String> enumNames) {
        enumNames.stream()
                .filter(enumName -> StringUtils.isNotEmpty(enumName))
                .forEach(enumName -> addEnum(enumClass, enumName));
    }

    public static <T extends Enum<?>> void addEnum(Class<T> enumClass, String... enumNames) {
        Stream.of(enumNames)
                .filter(enumName -> StringUtils.isNotEmpty(enumName))
                .forEach(enumName -> addEnum(enumClass, enumName));
    }

    /**
     * 添加枚举
     *
     * @param enumClass 枚举类
     * @param enumName  枚举名
     * @param <T>
     */
    public static <T extends Enum<?>> void addEnum(Class<T> enumClass, String enumName) {
        if (StringUtils.isEmpty(enumName)) {
            throw new RuntimeException("Enumeration name cannot be empty.");
        }
        // 0. Sanity checks
        if (!Enum.class.isAssignableFrom(enumClass)) {
            throw new RuntimeException("class " + enumClass + " is not an instance of Enum.");
        }
        // 1. Lookup "$VALUES" holder in enum class and get previous enum instances
        Field valuesField = null;
        Field[] fields = enumClass.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(enumClass);
            List values = new ArrayList(Arrays.asList(previousValues));

            // 3. build new enum
            T newValue = (T) makeEnum(enumClass, // The target enum class
                    enumName, // THE NEW ENUM INSTANCE TO BE DYNAMICALLY ADDED
                    values.size(),
                    new Class[]{}, // can be used to pass values to the enum constuctor
                    new Object[]{}); // can be used to pass values to the enum constuctor

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

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

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

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

    /**
     * 清除枚举缓存
     *
     * @param enumClass
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    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 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;
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值