|
@@ -0,0 +1,183 @@
|
|
|
|
|
+package com.wei.base.springframework.util;
|
|
|
|
|
+
|
|
|
|
|
+import com.fasterxml.jackson.core.JsonProcessingException;
|
|
|
|
|
+import com.fasterxml.jackson.databind.DeserializationFeature;
|
|
|
|
|
+import com.fasterxml.jackson.databind.JavaType;
|
|
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
|
+import com.fasterxml.jackson.databind.SerializationFeature;
|
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
+import org.springframework.cglib.beans.BeanCopier;
|
|
|
|
|
+import org.springframework.cglib.beans.BeanMap;
|
|
|
|
|
+import org.springframework.util.CollectionUtils;
|
|
|
|
|
+
|
|
|
|
|
+import java.util.*;
|
|
|
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+@Slf4j
|
|
|
|
|
+public class BeanUtil {
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Map<source class,<target class , BeanCopier>>
|
|
|
|
|
+ */
|
|
|
|
|
+ private static final ConcurrentHashMap<Class<?>, ConcurrentHashMap<Class<?>, BeanCopier>> cache = new ConcurrentHashMap<>();
|
|
|
|
|
+
|
|
|
|
|
+ private static final ObjectMapper objectMapper = new ObjectMapper();
|
|
|
|
|
+
|
|
|
|
|
+ static {
|
|
|
|
|
+ // 转换为格式化的json
|
|
|
|
|
+ objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
|
|
|
|
|
+
|
|
|
|
|
+ // 如果json中有新增的字段并且是实体类类中不存在的,不报错
|
|
|
|
|
+ objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 浅拷贝,对象属性都是基本类型时使用, 性能最优
|
|
|
|
|
+ */
|
|
|
|
|
+ public static <T> T copy(Object source, Class<T> targetClass) {
|
|
|
|
|
+
|
|
|
|
|
+ ConcurrentHashMap<Class<?>, BeanCopier> map = cache.get(source.getClass());
|
|
|
|
|
+ if (map == null) {
|
|
|
|
|
+ cache.putIfAbsent(source.getClass(), new ConcurrentHashMap<>());
|
|
|
|
|
+ map = cache.get(source.getClass());
|
|
|
|
|
+ }
|
|
|
|
|
+ BeanCopier copier = map.get(targetClass);
|
|
|
|
|
+ if (copier == null) {
|
|
|
|
|
+ map.putIfAbsent(targetClass, BeanCopier.create(source.getClass(), targetClass, false));
|
|
|
|
|
+ copier = map.get(targetClass);
|
|
|
|
|
+ }
|
|
|
|
|
+ T targetObj;
|
|
|
|
|
+ try {
|
|
|
|
|
+ targetObj = targetClass.newInstance();
|
|
|
|
|
+ copier.copy(source, targetObj, null);
|
|
|
|
|
+ return targetObj;
|
|
|
|
|
+ } catch (InstantiationException | IllegalAccessException e) {
|
|
|
|
|
+ throw new IllegalArgumentException(targetClass.getName() + " could not initial ! ", e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 列表,浅拷贝, 参数对象没有其他复杂数据类型时使用 , 性能比deepCopy高
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param source ,可以是单个对象或者是列表,如果是列表则返回List
|
|
|
|
|
+ * @param targetClass ,返回的对象类型
|
|
|
|
|
+ * @return 空列表或者是List(类型为targetClass)
|
|
|
|
|
+ */
|
|
|
|
|
+ public static <T, E> List<T> copy(List<E> source, Class<T> targetClass) {
|
|
|
|
|
+ if (CollectionUtils.isEmpty(source)) {
|
|
|
|
|
+ return Collections.emptyList();
|
|
|
|
|
+ }
|
|
|
|
|
+ return source.stream().map(sourceObj -> copy(sourceObj, targetClass)).collect(Collectors.toList());
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 深拷贝,对象存在其它引用时候使用
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param source ,源对象
|
|
|
|
|
+ * @param targetClass ,返回的对象类型
|
|
|
|
|
+ * @return null 或者 targetClass
|
|
|
|
|
+ */
|
|
|
|
|
+ public static <T> T deepCopy(Object source, Class<T> targetClass) throws JsonProcessingException {
|
|
|
|
|
+ if (source == null) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return objectMapper.readValue(objectMapper.writeValueAsString(source), targetClass);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 深拷贝,对象存在其它引用时候使用
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param source ,源对象列表
|
|
|
|
|
+ * @param targetClass ,返回的对象类型
|
|
|
|
|
+ * @return 空列表 或者是List(类型为targetClass)
|
|
|
|
|
+ */
|
|
|
|
|
+ public static <T, E> List<T> deepCopy(List<E> source, Class<T> targetClass) throws JsonProcessingException {
|
|
|
|
|
+ if (CollectionUtils.isEmpty(source)) {
|
|
|
|
|
+ return Collections.emptyList();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ JavaType javaType = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, targetClass);
|
|
|
|
|
+ return objectMapper.readValue(objectMapper.writeValueAsString(source), javaType);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 将对象转换成Map
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param bean
|
|
|
|
|
+ * @return map ,key为属性名,如果属性为复杂类型,则为嵌套map
|
|
|
|
|
+ */
|
|
|
|
|
+ public static Map<String, Object> bean2Map(Object bean) {
|
|
|
|
|
+ Map<String, Object> map = new HashMap<>(1);
|
|
|
|
|
+ BeanMap beanMap = BeanMap.create(bean);
|
|
|
|
|
+ Set<?> set = beanMap.keySet();
|
|
|
|
|
+ for (Object key : set) {
|
|
|
|
|
+ Object value = beanMap.get(key);
|
|
|
|
|
+ bean2MapRecursion(map, value, key.toString());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return map;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ private static void bean2MapRecursion(Map<String, Object> map, Object bean, String propertyName) {
|
|
|
|
|
+ if (bean != null) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ if (isPrimitive(bean.getClass())) {
|
|
|
|
|
+ map.put(propertyName, bean);
|
|
|
|
|
+ } else if (Object[].class.isInstance(bean)) {
|
|
|
|
|
+ List<Map<String, Object>> list = new ArrayList<>();
|
|
|
|
|
+ for (Object item : (Object[]) bean) {
|
|
|
|
|
+ list.add(bean2Map(item));
|
|
|
|
|
+ }
|
|
|
|
|
+ map.put(propertyName, list);
|
|
|
|
|
+ } else if (Collection.class.isInstance(bean)) {
|
|
|
|
|
+ List<Map<String, Object>> list = new ArrayList<>();
|
|
|
|
|
+ for (Object item : (Collection<?>) bean) {
|
|
|
|
|
+ list.add(bean2Map(item));
|
|
|
|
|
+ }
|
|
|
|
|
+ map.put(propertyName, list);
|
|
|
|
|
+ } else if (Map.class.isInstance(bean)) {
|
|
|
|
|
+ Map<String, Object> subMap = new HashMap<>();
|
|
|
|
|
+ for (Map.Entry<?, ?> entry : ((Map<?, ?>) bean).entrySet()) {
|
|
|
|
|
+ bean2MapRecursion(subMap, entry.getValue(), entry.getKey().toString());
|
|
|
|
|
+ }
|
|
|
|
|
+ map.put(propertyName, subMap);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ Map<String, Object> subMap = new HashMap<>();
|
|
|
|
|
+ BeanMap beanMap = BeanMap.create(bean);
|
|
|
|
|
+ Set<?> set = beanMap.keySet();
|
|
|
|
|
+ for (Object key : set) {
|
|
|
|
|
+ Object value = beanMap.get(key);
|
|
|
|
|
+ bean2MapRecursion(subMap, value, key.toString());
|
|
|
|
|
+ }
|
|
|
|
|
+ map.put(propertyName, subMap);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (RuntimeException e) {
|
|
|
|
|
+ log.error("propertyName = {} , value = ", propertyName, bean);
|
|
|
|
|
+ throw e;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 是否基本类型
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param cls
|
|
|
|
|
+ * @return
|
|
|
|
|
+ */
|
|
|
|
|
+ public static boolean isPrimitive(Class<?> cls) {
|
|
|
|
|
+ if (cls.isArray()) {
|
|
|
|
|
+ return isPrimitive(cls.getComponentType());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return cls.isPrimitive() || cls == Class.class || cls == String.class || cls == Boolean.class || cls == Character.class || Number.class.isAssignableFrom(cls)
|
|
|
|
|
+ || Date.class.isAssignableFrom(cls);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|