工具类篇3——反射工具类(对象反射)》

子目录

《工具类篇3——反射工具类(方法反射)》
《工具类篇3——反射工具类(对象反射)》
《工具类篇3——反射工具类(获取泛型类型)》


工具类全都是阿里代码规范与SonalLint扫描通过的,可以放心使用!

本工具包的公网Maven引用地址如下

<dependency>
    <groupId>com.gitee.taotaojs</groupId>
    <artifactId>comn-basic</artifactId>
    <version>1.0.0</version>
</dependency>

直接引用即可。
之后我也会出一个关于上传公网的踩坑手册,以及发布一下我用的CheckStyle文件检查相关异味,敬请期待!

【附上仓库地址】
阿里云的Maven仓库
sonatype仓库


注意事项:
本工具类有使用到同包下的工具类,详情请看gitee的代码,有所有工具类的代码~

import com.taotaojs.exception.MyInnerException; - 内部异常类,直接继承RuntimeException
import com.gitee.taotaojs.util.CollectionUtil; - 集合工具类
import com.gitee.taotaojs.util.ConstantUtil; - 常量类
(后期全都会在优快云上更新的)

主要功能

  • 支持对象与Map的互转
  • 判断对象是否为空
  • 获取泛型实例
  • 以某属性为key将集合整理为Map对象的方法
  • 两个不同类型对象的相同属性拷贝,支持黑白名单与指定属性
  • 两个不同类型集合的相同属性拷贝,支持黑白名单与指定属性
  • 对象深克隆

具体代码

package com.gitee.taotaojs.util.reflect;

import com.gitee.taotaojs.exception.MyInnerException;
import com.gitee.taotaojs.util.CollectionUtil;
import com.gitee.taotaojs.util.ConstantUtil;

import java.beans.PropertyDescriptor;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author TaoTaojs
 * @date 2019/4/28 14:56
 * <p>Description</p>
 * <h1>对象操作工具</h1>
 * <h2>简介</h2>
 * 对对象进行判断、整理等一系列操作
 * <h3>主要功能:</h3>
 * <ol>
 *     <li>支持对象与Map的互转</li>
 *     <li>判断对象是否为空</li>
 *     <li>获取泛型实例</li>
 *     <li>以某属性为key将集合整理为Map对象的方法</li>
 *     <li>两个不同类型对象的相同属性拷贝,支持黑白名单与指定属性</li>
 *     <li>两个不同类型集合的相同属性拷贝,支持黑白名单与指定属性</li>
 *     <li>对象深克隆</li>
 * </ol>
 * 关联类:
 */
public final class EntityUtil {

    private EntityUtil(){}

    /**
     * 对象转为Map结构
     * @param obj 具体对象
     * @return Map结构
     * @throws Exception
     */
    public static Map<String, Object> obj2Map(Object obj){
        Map<String, Object> map=new HashMap<>(ConstantUtil.TWO);
        PropertyDescriptor[] propertyDescriptors = ReflectUtil.getPropertyList(obj.getClass());
        for (PropertyDescriptor property : propertyDescriptors) {
            String key = property.getName();
            if (key.compareToIgnoreCase("class") == 0) {
                continue;
            }
            Method getter = property.getReadMethod();
            if(getter != null){
                map.put(key, ReflectUtil.invokeMethod(obj, getter));
            }
        }
        return map;
    }

    /**
     * Map映射为具体对象(推荐直接使用BeanMap类)
     * @param map 属性数据
     * @param clz 类类型
     * @return 具体对象
     * @throws Exception
     */
    public static Object map2Obj(Map<String, Object> map, Class<?> clz){
        if (map == null) {
            return null;
        }
        Object obj = getInstance(clz);
        PropertyDescriptor[] propertyDescriptors = ReflectUtil.getPropertyList(obj.getClass());
        for (PropertyDescriptor property : propertyDescriptors) {
            Method setter = property.getWriteMethod();
            if (setter != null) {
                ReflectUtil.invokeMethod(obj, setter, map.get(property.getName()));
            }
        }
        return obj;
    }


    /**
     * 对象添加属性
     * 使用反射获取对应属性的set方法
     * @param item 对象
     * @param map [属性名:值]
     * @param <T> 对象泛型
     * @param <V> 属性对象泛型
     * @return 添加好对象之后的属性
     */
    public static <T, V> T addProperty(T item, Map<String, V> map){
        for (Map.Entry<String, V> stringObjectEntry : map.entrySet()) {
            String key = stringObjectEntry.getKey();
            ReflectUtil.invokeSet(item, key, stringObjectEntry.getValue());
        }
        return item;
    }

    /**
     * 判断对象是否为空
     * @param obj 对象
     * @return 为空返回true
     */
    public static boolean isEmpty(Object obj){
        if(obj == null){
            return true;
        }
        for (Field f : obj.getClass().getDeclaredFields()) {
            //公有化属性
            f.setAccessible(true);
            //判断字段是否为空,并且对象属性中的基本都会转为对象类型来判断
            if (ReflectUtil.invokeGet(obj, f) != null) {
                return false;
            }
        }
        return true;
    }

    /**
     * 获取两个对象中相同名称和类型的属性
     * @param clazz1 类型1
     * @param clazz2 类型2
     * @param <T1> 泛型1
     * @param <T2> 泛型2
     * @return map类型的属性
     */
    protected static <T1, T2> Map<String, Class<?>> getFieldList(Class<T1> clazz1, Class<T2> clazz2) {
        //获取所有属性
        Field[] fields1 = clazz1.getDeclaredFields();
        Field[] fields2 = clazz2.getDeclaredFields();
        //创建Map容器
        Map<String, Class<?>> fieldMap = new HashMap<>(2);
        for (Field f1 : fields1) {
            for (Field f2 : fields2) {
                //判断两个字段是否名称相同而且类型相同
                if (f1.getName().equals(f2.getName())
                        && equalFieldsType(f1, f2)) {
                    fieldMap.put(f1.getName(), f1.getType());
                }
            }
        }
        return fieldMap;
    }

    /**
     * 获取一个泛型的实例
     * @param clazz 类型
     * @param <T> 泛型
     * @return 泛型实例
     */
    public static <T> T getInstance(Class<T> clazz) {
        try {
            return clazz.newInstance();
        } catch (Exception e) {
            throw new MyInnerException(e);
        }
    }

    /**
     * 判断两个字段的类型是否相同
     *
     * @param field1 复制源
     * @param field2 复制目标
     * @return 相同返回true
     */
    public static boolean equalFieldsType(Field field1, Field field2) {
        String fTypeName1 = field1.getType().getSimpleName();
        String fTypeName2 = field2.getType().getSimpleName();
        //1. 处理基本数据类型和包装类
        Map<String, String> map = new HashMap<>(ConstantUtil.EIGHT);
        map.put(int.class.getSimpleName(), Integer.class.getSimpleName());
        map.put(byte.class.getSimpleName(), Byte.class.getSimpleName());
        map.put(short.class.getSimpleName(), Short.class.getSimpleName());
        map.put(char.class.getSimpleName(), Character.class.getSimpleName());
        map.put(long.class.getSimpleName(), Long.class.getSimpleName());
        map.put(float.class.getSimpleName(), Float.class.getSimpleName());
        map.put(double.class.getSimpleName(), Double.class.getSimpleName());
        map.put(boolean.class.getSimpleName(), Boolean.class.getSimpleName());

        /**
         * 在涉及包装类的判断逻辑中,源数据不能是包装类
         * 因为包装类一旦为null,会引发异常
         */
        for (Map.Entry<String, String> stringStringEntry : map.entrySet()) {
            boolean flag =  stringStringEntry.getKey().equals(fTypeName2) && map.get(stringStringEntry.getKey()).equals(fTypeName1);
            boolean flag1 = stringStringEntry.getKey().equals(fTypeName1) && map.get(stringStringEntry.getKey()).equals(fTypeName2);
            if (flag1 || flag) {
                return true;
            }
        }
        //2. 类型相同
        return fTypeName1.equals(fTypeName2);
    }


    /**
     * 以某个属性名称为key,将集合整理为Map对象(默认属性名为id)
     * @param clazz 类类型
     * @param list 集合
     * @param proName 属性名
     * @param <K> 属性名类型泛型
     * @param <V> 集合泛型
     * @return map对象
     */
    public static<K, V> Map<K, V> objList2Map(Class<V> clazz, List<V> list, String proName){
        Map<K, V> map = new HashMap<>(2);
        Method getIdMethod = ReflectUtil.getGetMethod(clazz, proName);
        for (V v : list) {
            try {
                map.put((K) getIdMethod.invoke(v), v);
            } catch (Exception e) {
                throw new MyInnerException(e);
            }
        }
        return map;
    }
    @SuppressWarnings("checkstyle:MissingJavadocMethod")
    public static<T> Map<Integer, T> objList2Map(Class<T> clazz, List<T> list){
        return objList2Map(clazz, list, "id");
    }

    /**
     * 根据类类型和属性名称获取对应的Field对象
     * @param clazz 类类型
     * @param fieldName 属性名
     * @param <T> 类泛型
     * @return 属性对象
     */
    public static<T> Field getField(Class<T> clazz, String fieldName){
        try {
            return clazz.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            throw new MyInnerException(e);
        }
    }


    /**
     * 深克隆对象
     * @param orig 对象
     * @return 深克隆之后的对象
     */
    public static Object clone(Object orig) {
        Object obj = null;
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(bos);
            out.writeObject(orig);
            out.flush();
            out.close();

            ObjectInputStream in = new ObjectInputStream(
                    new ByteArrayInputStream(bos.toByteArray()));
            obj = in.readObject();
        } catch (Exception e) {
            throw new MyInnerException(e);
        }
        return obj;
    }

    /**
     * 将第一个对象的值复制到第二个对象中
     * @param sourceObj 源实体
     * @param targetObj 目标实体
     * @param fields 需要复制的属性(可以为空,为空则默认复制全部,且受黑名单与白名单的约束)
     * @param notFields 黑名单
     * @param yesFields 白名单
     * @param <T1> 源泛型
     * @param <T2> 目标泛型
     */
    public static<T1, T2> void copyData(T1 sourceObj, T2 targetObj, Field[] fields, Field[] notFields, Field[] yesFields){
        if(sourceObj == null || targetObj == null){
            throw new MyInnerException("对象不能为null");
        }
        if(fields != null && fields.length > 0){
            //fields存在时,not和yes不生效,仅复制fields中的属性
            for (Field field : fields) {
                copyFieldValue(sourceObj, targetObj, field);
            }
        } else if(notFields != null || yesFields != null) {
            //fields不存在则not和yes生效,循环所有字段并复制
            fields = sourceObj.getClass().getDeclaredFields();
            for(Field field : fields) {
                boolean notFlag = CollectionUtil.isExist(notFields, field, Field.class, "getName");
                boolean yesFlag = CollectionUtil.isExist(yesFields, field, Field.class, "getName");
                if(yesFlag || !notFlag){
                    copyFieldValue(sourceObj, targetObj, field);
                }
            }
        } else {
            Field[] fieldList = sourceObj.getClass().getDeclaredFields();
            ReflectUtil.fieldAccess(true, fieldList);
            for (Field field : fieldList) {
                copyFieldValue(sourceObj, targetObj, field);
            }
            ReflectUtil.fieldAccess(true, fieldList);
        }
    }
    @SuppressWarnings("checkstyle:MissingJavadocMethod")
    public static<T1, T2> T2 copyData(T1 sourceObj, Class<T2> targetClass, Field[] fields, Field[] notFields, Field[] yesFields){
        T2 targetObj = EntityUtil.getInstance(targetClass);
        copyData(sourceObj, targetObj, fields, notFields, yesFields);
        return targetObj;
    }
    @SuppressWarnings("checkstyle:MissingJavadocMethod")
    public static<T1, T2> void copyData(T1 sourceObj, T2 targetObj){
        copyData(sourceObj, targetObj, null, null, null);
    }
    @SuppressWarnings("checkstyle:MissingJavadocMethod")
    public static<T1, T2> T2 copyData(T1 sourceObj, Class<T2> targetClass){
        T2 targetObj = EntityUtil.getInstance(targetClass);
        copyData(sourceObj, targetObj);
        return targetObj;
    }

    /**
     * 将列表对象转换为另一个列表对象
     * @param sourceList 源实体
     * @param sourceClass 目标实体
     * @param fields 需要复制的属性(可以为空,为空则默认复制全部,且受黑名单与白名单的约束)
     * @param notFields 黑名单
     * @param yesFields 白名单
     * @param <T1> 源泛型
     * @param <T2> 目标泛型
     * @return 部门对象集合
     */
    public static<T1, T2> List<T2> copyListData(Collection<T1> sourceList, Class<T2> sourceClass, Field[] fields, Field[] notFields, Field[] yesFields){
        List<T2> list = new ArrayList<>();
        for (T1 source : sourceList) {
            list.add(copyData(source, sourceClass, fields, notFields, yesFields));
        }
        return list;
    }

    /**
     * 将第一个对象的指定属性复制到第二个对象中
     * @param sourceObj 源实体
     * @param targetObj 目标实体
     * @param field 属性对象
     * @param <T1> 源泛型
     * @param <T2> 目标泛型
     */
    private static <T1, T2> void copyFieldValue(T1 sourceObj, T2 targetObj, Field field) {
        T1 t1 = ReflectUtil.invokeGet(sourceObj, field);
        if(t1 != null) {
            ReflectUtil.invokeSet(targetObj, field, t1);
        }
    }


    /**
     * 复制字段的值????这特么是啥
     * @param sourceObj 被转换的
     * @param targetObj 转换得到的 - null
     * @param field1 源属性对象
     * @param field2 目标属性对象
     * @param <T1> 源泛型
     * @param <T2> 目标泛型
     */
    public static <T1, T2> void copyFieldValue(T1 sourceObj, T2 targetObj, Field field1, Field field2) {
        //1. 判断两个字段是否名称相同而且类型相同
        if (field1.getName().equals(field2.getName())
                && EntityUtil.equalFieldsType(field1, field2)) {
            //2. 获取源数据字段的值
            field1.setAccessible(true);
            Object value = ReflectUtil.invokeGet(sourceObj, field1);
            //3. 给目标数据字段赋值
            field2.setAccessible(true);
            ReflectUtil.invokeSet(targetObj, field2, value);
            //4. 访问权限还原
            ReflectUtil.fieldAccess(false, field1, field2);
            return;
        }
        if (field1.getName().equals(field2.getName())){
            String fTypeName1 = field1.getType().getSimpleName();
            String fTypeName2 = field2.getType().getSimpleName();
            String dateName = Date.class.getSimpleName();
            String stringName = String.class.getSimpleName();
            ReflectUtil.fieldAccess(true, field1, field2);
            Object value = ReflectUtil.invokeGet(sourceObj, field1);
            if(value == null) {
                return;
            }
            if(fTypeName1.equals(stringName) && fTypeName2.equals(dateName)){

                field2.setAccessible(true);
                try {
                    ReflectUtil.invokeSet(targetObj, field2, new SimpleDateFormat("yyyy-MM-dd").parse((String) value));
                } catch (ParseException e) {
                    throw new MyInnerException(e);
                }

                //4. 访问权限还原
                ReflectUtil.fieldAccess(false, field1, field2);
            }
            if(fTypeName1.equals(dateName) && fTypeName2.equals(stringName)){
                ReflectUtil.fieldAccess(true, field1, field2);
                //3. 获取源数据字段的值给目标数据字段赋值
                ReflectUtil.invokeSet(targetObj, field2, new SimpleDateFormat("yyyy-MM-dd").format((Date) value));

                //4. 访问权限还原
                ReflectUtil.fieldAccess(false, field1, field2);
            }
        }
    }


}

PS:

文章链接

《工具类篇1——POI工具类》——待更新
《工具类篇2——集合工具类》
《工具类篇3——反射工具类》(共三篇)
《工具类篇4——大数字工具类》(共三篇)——待更新
《工具类篇5——时间戳工具类》(共两篇)——待更新
《工具类篇6——字符串工具类》——待更新
《工具类篇7——线程池工具类》——待更新
《…》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值