
cn.micro.core.util.BeanUtil Maven / Gradle / Ivy
package cn.micro.core.util;
import cn.micro.core.exception.BizException;
import net.sf.cglib.beans.BeanMap;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.cglib.beans.BeanGenerator;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.FastByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.*;
/**
* 实体工具类
*/
public class BeanUtil extends BeanUtils {
/**
* 实例化对象
*
* @param clazz 类
* @param 泛型标记
* @return 对象
*/
@SuppressWarnings("unchecked")
public static T newInstance(Class> clazz) {
return (T) instantiateClass(clazz);
}
/**
* 实例化对象
*
* @param clazzStr 类名
* @param 泛型标记
* @return 对象
*/
public static T newInstance(String clazzStr) {
return newInstance(forName(clazzStr));
}
/**
* forName
*
* @param clazzStr 类名
* @return Class
*/
public static Class> forName(String clazzStr) {
try {
return ClassUtils.forName(clazzStr, null);
} catch (ClassNotFoundException e) {
throw new BizException(e);
}
}
/**
* 获取Bean的属性, 支持 propertyName 多级 :test.user.name
*
* @param bean bean
* @param propertyName 属性名
* @return 属性值
*/
@Nullable
public static Object getProperty(@Nullable Object bean, String propertyName) {
if (bean == null) {
return null;
}
BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(bean);
return beanWrapper.getPropertyValue(propertyName);
}
/**
* 设置Bean属性, 支持 propertyName 多级 :test.user.name
*
* @param bean bean
* @param propertyName 属性名
* @param value 属性值
*/
public static void setProperty(Object bean, String propertyName, Object value) {
BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(Objects.requireNonNull(bean, "bean Could not null"));
beanWrapper.setPropertyValue(propertyName, value);
}
/**
* 深度拷贝
*
* @param source 待拷贝的对象
* @return 拷贝之后的对象
*/
@Nullable
@SuppressWarnings("unchecked")
public static T deepClone(@Nullable T source) {
if (source == null) {
return null;
}
FastByteArrayOutputStream fBos = new FastByteArrayOutputStream(1024);
try (ObjectOutputStream oos = new ObjectOutputStream(fBos)) {
oos.writeObject(source);
oos.flush();
} catch (IOException ex) {
throw new IllegalArgumentException("Failed to serialize object of type: " + source.getClass(), ex);
}
try (ObjectInputStream ois = new ObjectInputStream(fBos.getInputStream())) {
return (T) ois.readObject();
} catch (IOException | ClassNotFoundException ex) {
throw new IllegalArgumentException("Failed to deserialize object", ex);
}
}
/**
* Copy the property values of the given source bean into the target class.
* Note: The source and target classes do not have to match or even be derived
* from each other, as long as the properties match. Any bean properties that the
* source bean exposes but the target bean does not will silently be ignored.
*
This is just a convenience method. For more complex transfer needs,
*
* @param source the source bean
* @param targetClazz the target bean class
* @param 泛型标记
* @return T
* @throws BeansException if the copying failed
*/
@Nullable
public static T copyProperties(@Nullable Object source, Class targetClazz) throws BeansException {
if (source == null) {
return null;
}
T to = newInstance(targetClazz);
BeanUtils.copyProperties(source, to);
return to;
}
/**
* Copy the property values of the given source bean into the target class.
* Note: The source and target classes do not have to match or even be derived
* from each other, as long as the properties match. Any bean properties that the
* source bean exposes but the target bean does not will silently be ignored.
*
This is just a convenience method. For more complex transfer needs,
*
* @param sourceList the source list bean
* @param targetClazz the target bean class
* @param 泛型标记
* @return List
* @throws BeansException if the copying failed
*/
public static List copyProperties(@Nullable Collection> sourceList, Class targetClazz) throws BeansException {
if (sourceList == null || sourceList.isEmpty()) {
return Collections.emptyList();
}
List outList = new ArrayList<>(sourceList.size());
for (Object source : sourceList) {
if (source == null) {
continue;
}
T bean = BeanUtil.copyProperties(source, targetClazz);
outList.add(bean);
}
return outList;
}
/**
* 将对象装成map形式,map 不可写
*
* @param bean 源对象
* @return {Map}
*/
@SuppressWarnings("unchecked")
public static Map toMap(@Nullable Object bean) {
if (bean == null) {
return new HashMap<>(0);
}
BeanMap beanMap = BeanMap.create(bean);
Map objectMap = new HashMap<>(beanMap.size());
for (Object key : beanMap.keySet()) {
objectMap.put(key.toString(), beanMap.get(key));
}
return objectMap;
}
/**
* 将对象装成map形式,map 可写
*
* @param bean 源对象
* @return {Map}
*/
public static Map toNewMap(@Nullable Object bean) {
return new HashMap<>(toMap(bean));
}
/**
* 将map 转为 bean
*
* @param beanMap map
* @param valueType 对象类型
* @param 泛型标记
* @return {T}
*/
public static T toBean(Map beanMap, Class valueType) {
Objects.requireNonNull(beanMap, "beanMap Could not null");
T to = newInstance(valueType);
if (beanMap.isEmpty()) {
return to;
}
BeanMap map = BeanMap.create(to);
map.putAll(beanMap);
return to;
}
/**
* 给一个class添加字段
*
* @param superclass 父级
* @param props 新增属性
* @return {Object}
*/
public static Object generator(Class> superclass, BeanProperty... props) {
BeanGenerator generator = new BeanGenerator();
generator.setSuperclass(superclass);
generator.setUseCache(true);
for (BeanProperty prop : props) {
generator.addProperty(prop.getName(), prop.getType());
}
return generator.create();
}
/**
* 比较对象
*
* @param src 源对象
* @param dist 新对象
* @return {BeanDiff}
*/
public static BeanDiff diff(final Object src, final Object dist) {
Assert.notNull(src, "diff Object src is null.");
Assert.notNull(src, "diff Object dist is null.");
return diff(BeanUtil.toMap(src), BeanUtil.toMap(dist));
}
/**
* 比较Map
*
* @param src 源Map
* @param dist 新Map
* @return {BeanDiff}
*/
public static BeanDiff diff(final Map src, final Map dist) {
Assert.notNull(src, "diff Map src is null.");
Assert.notNull(src, "diff Map dist is null.");
// 改变
Map difference = new HashMap<>(8);
difference.putAll(src);
difference.putAll(dist);
difference.entrySet().removeAll(src.entrySet());
// 老值
Map oldValues = new HashMap<>(8);
difference.keySet().forEach((k) -> oldValues.put(k, src.get(k)));
BeanDiff diff = new BeanDiff();
diff.getFields().addAll(difference.keySet());
diff.getOldValues().putAll(oldValues);
diff.getNewValues().putAll(difference);
return diff;
}
}