子目录
《工具类篇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——线程池工具类》——待更新
《…》