weaver-hrm-salary/src/com/engine/salary/util/EnumUtil.java

358 lines
14 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.engine.salary.util;
import lombok.extern.slf4j.Slf4j;
import sun.reflect.ConstructorAccessor;
import sun.reflect.FieldAccessor;
import sun.reflect.MethodAccessor;
import sun.reflect.ReflectionFactory;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Slf4j
public class EnumUtil {
/**
* 扩展枚举(把新枚举的值加入旧枚举里,从旧枚举里删除不要的枚举值)
* @param oldEnumClass 旧枚举类
* @param newEnumClass 需要扩展的枚举类
* @param removeOldEnums 需要删除的旧枚举值
* @param <O>
* @param <N>
* @throws Exception
*/
public static <O extends Enum,N extends Enum> void extendEnum(Class<O> oldEnumClass,Class<N> newEnumClass,O... removeOldEnums) throws Exception {
boolean needToRemoveOldEnum = removeOldEnums!=null&&removeOldEnums.length>0;
if(needToRemoveOldEnum){
removeEnum(oldEnumClass,removeOldEnums);
}
List newEnums = values(newEnumClass);
Field[] fields = getFields(newEnumClass);
for (Object newEnumObject : newEnums) {
Enum newEnum = Enum.class.cast(newEnumObject);
List<Class> fieldTypeList = new ArrayList<>();
//枚举名称的类型String.class
fieldTypeList.add(String.class);
for (Field field : fields) {
fieldTypeList.add(field.getType());
}
List<Object> fieldValueList = new ArrayList<>();
//枚举名称
fieldValueList.add(newEnum.name());
for (Field field : fields) {
Object value = field.get(newEnum);
fieldValueList.add(value);
}
Class[] fieldTypes = fieldTypeList.toArray(new Class[]{});
String[] fieldValues = fieldValueList.toArray(new String[]{});
addEnum(oldEnumClass,fieldTypes,fieldValues);
}
}
/**
* 新增枚举值
* @param enumClass 枚举类型
* @param fieldTypes 字段的类型第一个是枚举名类型String
* @param fieldValues 字段的值,第一个是枚举名称
* @throws Exception
*/
public static <T extends Enum<T>> T addEnum(Class<T> enumClass, Class[] fieldTypes, Object[] fieldValues) throws Exception {
if(fieldTypes==null||fieldTypes.length==0){
throw new RuntimeException("参数fieldTypes为空");
}
if(fieldValues==null||fieldValues.length==0){
throw new RuntimeException("参数fieldValues为空");
}
if(fieldTypes[0]!=String.class){
throw new RuntimeException("参数fieldTypes[0]不是String.class");
}
if(!(fieldValues[0] instanceof String)){
throw new RuntimeException("参数fieldValues[0]不是字符串");
}
if(fieldTypes.length!=fieldValues.length){
throw new RuntimeException("参数fieldTypes和参数fieldValues的长度不一致");
}
ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
String enumName = fieldValues[0].toString();
synchronized (enumClass){
//判断name是否已经添加过了
if(hasEnumName(enumClass,enumName)){
log.info("枚举类{}中已存在该枚举名:{}",enumClass.getSimpleName(),enumName);
return getEnum(enumClass,enumName);
}
//name,ordinal,其他自定义字段
List<Class> allFieldClass = new ArrayList<>(fieldTypes.length + 1);
allFieldClass.add(String.class);
allFieldClass.add(int.class);
for (int i = 1; i < fieldTypes.length; i++) {
allFieldClass.add(fieldTypes[i]);
}
Class[] classes = allFieldClass.toArray(new Class[]{});
Constructor<T> constructor = enumClass.getDeclaredConstructor(classes);
ConstructorAccessor constructorAccessor = reflectionFactory.newConstructorAccessor(constructor);
List<Object> allFields = new ArrayList<>(fieldValues.length + 1);
allFields.add(enumName);
int maxOrdinal = getMaxOrdinal(enumClass);
allFields.add(maxOrdinal+1);
for (int i = 1; i < fieldValues.length; i++) {
allFields.add(fieldValues[i]);
}
//调用枚举的构造方法,创建新的枚举值
T newEnum = (T) constructorAccessor.newInstance(allFields.toArray());
log.info("新增枚举:{}" , newEnum);
Field valuesField = enumClass.getDeclaredField("$VALUES");
valuesField.setAccessible(true);
//解除values属性的final限制
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
int modifiers = modifiersField.getInt(valuesField);
modifiers &= ~Modifier.FINAL;
modifiersField.setInt(valuesField, modifiers);
//将新增的枚举值加入values属性里
FieldAccessor fieldAccessor = reflectionFactory.newFieldAccessor(valuesField, false);
T[] ts = (T[]) fieldAccessor.get(enumClass);
List<T> list = new ArrayList<>(Arrays.asList(ts));
list.add(newEnum);
fieldAccessor.set(enumClass, list.toArray(ts));
//将Class对象的enumConstants和enumConstantDirectory清空Enum.valueOf()方法会给它们赋值)
/**
* Enum.valueOf()逻辑:
* 1.取enumConstantDirectory
* 1.1如果有值则直接返回
* 1.2如果没值则取enumConstants并拷贝到enumConstantDirectory下次可直接返回
* 1.2.1如果enumConstants有值则返回
* 1.2.2如果enumConstants没值则取枚举的values属性并拷贝到enumConstants下次可直接返回
* 2.enumConstantDirectory.get(name)返回
*/
Field enumConstantDirectoryField = enumClass.getClass().getDeclaredField("enumConstantDirectory");
enumConstantDirectoryField.setAccessible(true);
FieldAccessor enumConstantDirectoryFieldAccessor = reflectionFactory.newFieldAccessor(enumConstantDirectoryField, false);
enumConstantDirectoryFieldAccessor.set(enumClass,null);
Field enumConstantsField = enumClass.getClass().getDeclaredField("enumConstants");
enumConstantsField.setAccessible(true);
FieldAccessor enumConstantsFieldAccessor = reflectionFactory.newFieldAccessor(enumConstantsField, false);
enumConstantsFieldAccessor.set(enumClass,null);
return newEnum;
}
}
/**
* 获取枚举类当前最大序号
* @param enumClass 枚举类型
* @param <T>
* @return
* @throws Exception
*/
public static <T extends Enum<T>> int getMaxOrdinal(Class<T> enumClass) throws Exception {
List<T> values = values(enumClass);
if(values==null||values.size()==0){
return 0;
}
int maxOrdinal = 0;
for (T value : values) {
if(maxOrdinal<value.ordinal()){
maxOrdinal = value.ordinal();
}
}
return maxOrdinal;
}
/**
* 删除枚举值
* @param enumClass 枚举类型
* @param removeOldEnums 需要删除的枚举值
* @param <T>
*/
public static <T extends Enum<T>> void removeEnum(Class<T> enumClass, Enum<T>... removeOldEnums) throws Exception {
if(removeOldEnums==null||removeOldEnums.length==0){
log.warn("removeOldEnums为空");
return;
}
ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
synchronized (enumClass){
Field valuesField = enumClass.getDeclaredField("$VALUES");
valuesField.setAccessible(true);
//解除values属性的final限制
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
int modifiers = modifiersField.getInt(valuesField);
modifiers &= ~Modifier.FINAL;
modifiersField.setInt(valuesField, modifiers);
FieldAccessor fieldAccessor = reflectionFactory.newFieldAccessor(valuesField, false);
T[] oldEnumArray = (T[]) fieldAccessor.get(enumClass);
List<T> enumList = new ArrayList<>(Arrays.asList(oldEnumArray));
for (Enum removeOldEnum : removeOldEnums) {
//将指定的枚举值从values属性里删除
enumList.remove(removeOldEnum);
log.info("删除枚举值:{}",removeOldEnum);
}
//把List转成数组
T[] newEnumArray = (T[]) Arrays.copyOf(enumList.toArray(), enumList.size(), oldEnumArray.getClass());
fieldAccessor.set(enumClass, newEnumArray);
}
}
/**
* 修改枚举属性
* @param enumClass 枚举类型
* @param enumName 枚举名称
* @param attributeName 属性名
* @param attributeValue 属性值
* @param <T>
* @throws Exception
*/
public static <T extends Enum<T>> void setAttribute(Class<T> enumClass,String enumName,String attributeName,Object attributeValue) throws Exception {
List<T> values = values(enumClass);
T target = null;
for (T t:values){
if(t.name().equals(enumName)){
target = t;
break;
}
}
if(target==null){
throw new RuntimeException("该枚举类没有枚举名:"+enumName);
}
Field declaredField = target.getClass().getDeclaredField(attributeName);
declaredField.setAccessible(true);
declaredField.set(target,attributeValue);
}
/**
* 修改枚举属性
* @param targetEnum 枚举值
* @param attributeName 属性名
* @param attributeValue 属性值
* @param <T>
* @throws Exception
*/
public static <T extends Enum<T>> void setAttribute(T targetEnum,String attributeName,Object attributeValue) throws Exception {
Field declaredField = targetEnum.getClass().getDeclaredField(attributeName);
declaredField.setAccessible(true);
declaredField.set(targetEnum,attributeValue);
}
/**
* 判断枚举类是否包含了指定枚举名
* @param clazz
* @param enumName
* @param <T>
* @return
*/
public static <T extends Enum<T>> boolean hasEnumName(Class<T> clazz, String enumName) throws Exception {
// 不要用valueOf方法因为它会初始化enumConstantDirectory使得后续调用valueOf方法后拿不到后面加入的枚举值
// try{
// T t = Enum.valueOf(clazz, enumName);
// if(t!=null){
// return true;
// }
// }catch (Exception e){
// e.printStackTrace();
// System.err.println(e.getMessage());
// }
List<T> values = values(clazz);
for (T t:values){
if(t.name().equals(enumName)){
return true;
}
}
return false;
}
/**
* 根据枚举类型和枚举名获取枚举值
* @param clazz 枚举类型
* @param enumName 枚举名称
* @param <T>
* @return
* @throws Exception
*/
public static <T extends Enum<T>> T getEnum(Class<T> clazz, String enumName) throws Exception {
List<T> values = values(clazz);
for (T t:values){
if(t.name().equals(enumName)){
return t;
}
}
return null;
}
/**
* 获取枚举类的所有枚举值
* @param clazz 枚举类型
* @param <T>
* @return
* @throws Exception
*/
public static <T extends Enum<T>> List<T> values(Class<T> clazz) throws Exception {
ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
Field valuesField = clazz.getDeclaredField("$VALUES");
valuesField.setAccessible(true);
FieldAccessor fieldAccessor = reflectionFactory.newFieldAccessor(valuesField, false);
T[] ts = (T[]) fieldAccessor.get(clazz);
List<T> list = new ArrayList<>(Arrays.asList(ts));
return list;
}
/**
* 获取枚举类的所有枚举值
* @param clazz 枚举类型
* @param <T>
* @return
* @throws Exception
*/
public static <T extends Enum<T>> List<T> values2(Class<T> clazz) throws Exception {
ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
Method valuesMethod = clazz.getDeclaredMethod("values");
valuesMethod.setAccessible(true);
MethodAccessor methodAccessor = reflectionFactory.newMethodAccessor(valuesMethod);
T[] ts = (T[]) methodAccessor.invoke(clazz, null);
List<T> list = new ArrayList<>(Arrays.asList(ts));
return list;
}
/**
* 获取枚举的字段(排除数组类型、枚举类型)
* @param enumClass
* @return
*/
public static Field[] getFields(Class<? extends Enum> enumClass){
List<Field> result = new ArrayList<>();
Field[] declaredFields = enumClass.getDeclaredFields();
for (Field field : declaredFields) {
Class<?> type = field.getType();
//排除数组类型(values)、枚举类型(枚举值)
if(type!=enumClass && !type.isArray()){
field.setAccessible(true);
result.add(field);
}
}
return result.toArray(new Field[]{});
}
/**
* 打印枚举值
* @param enumClass 枚举类型
* @throws Exception
*/
public static void printEnum(Class<? extends Enum> enumClass) throws Exception {
System.out.println("+++++++++++++++++++++++");
List values = values(enumClass);
values.stream().forEach(System.out::println);
System.out.println("+++++++++++++++++++++++");
}
}