|
@@ -0,0 +1,400 @@
|
|
|
+package com.zswl.dataservicestarter.utils;
|
|
|
+
|
|
|
+import com.fasterxml.jackson.core.JsonProcessingException;
|
|
|
+import com.fasterxml.jackson.core.type.TypeReference;
|
|
|
+import com.fasterxml.jackson.databind.DeserializationFeature;
|
|
|
+import com.fasterxml.jackson.databind.JavaType;
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
+import com.zswl.dataservicestarter.domain.base.DataServiceSuperEntity;
|
|
|
+import com.zswl.dataservicestarter.helper.ApplicationContextHolder;
|
|
|
+import com.zswl.dataservicestarter.type.CommonEnum;
|
|
|
+import io.swagger.annotations.ApiModelProperty;
|
|
|
+import org.apache.commons.lang3.ObjectUtils;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.beans.FatalBeanException;
|
|
|
+import org.springframework.cglib.beans.BeanMap;
|
|
|
+import org.springframework.util.ClassUtils;
|
|
|
+
|
|
|
+import java.beans.Introspector;
|
|
|
+import java.beans.PropertyDescriptor;
|
|
|
+import java.lang.reflect.*;
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+public class BeanUtils extends org.springframework.beans.BeanUtils {
|
|
|
+
|
|
|
+ private static Logger log = LoggerFactory.getLogger(BeanUtils.class);
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将对象属性转化为map结合
|
|
|
+ */
|
|
|
+ public static <T> Map<String, Object> beanToMap(T bean) {
|
|
|
+ Map<String, Object> map = new HashMap<>();
|
|
|
+ if (bean != null) {
|
|
|
+ BeanMap beanMap = BeanMap.create(bean);
|
|
|
+ for (Object key : beanMap.keySet()) {
|
|
|
+ map.put(key + "", beanMap.get(key));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static <T> Map<String, Object> beanToMapBlockRef(T bean) {
|
|
|
+ Map<String, Object> data = new HashMap<>();
|
|
|
+ if (ObjectUtils.isNotEmpty(bean)) {
|
|
|
+ Map<String, Object> map = BeanMap.create(bean);
|
|
|
+ for (Map.Entry<String, Object> entry : map.entrySet()) {
|
|
|
+ String key = entry.getKey();
|
|
|
+ Object value = entry.getValue();
|
|
|
+ List<String> _keys = new ArrayList<>();
|
|
|
+ data.put(key, loopValue(value, _keys));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected static Object loopValue(Object value, List<String> _keys) {
|
|
|
+ if (value != null && isCustomObj(value)) {
|
|
|
+ if (isCglibObj(value)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ Map<String, Object> _map = BeanMap.create(value);
|
|
|
+ HashMap<String, Object> map = new HashMap<>();
|
|
|
+ for (Map.Entry<String, Object> entry : _map.entrySet()) {
|
|
|
+ if (!_keys.contains(entry.getKey())) {
|
|
|
+ // prevent custom entity endless loop
|
|
|
+ if (entry.getValue() != null && isCustomObj(entry.getValue())) {
|
|
|
+ _keys.add(entry.getKey());
|
|
|
+ }
|
|
|
+ map.put(entry.getKey(), loopValue(entry.getValue(), _keys));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static boolean isCglibObj(Object value) {
|
|
|
+ String name = value.getClass().getName();
|
|
|
+ return name == null || name.contains(ClassUtils.CGLIB_CLASS_SEPARATOR);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 判断是否是自定义类型
|
|
|
+ *
|
|
|
+ * @param value
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static boolean isCustomObj(Object value) {
|
|
|
+ if (value == null) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ String _name = value.getClass().getName();
|
|
|
+ if (_name.startsWith("java.lang") || _name.startsWith("java.util") || _name.startsWith("java.math") || (value instanceof Enum)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void copyPropertiesWithoutNull(Object source, Object target) {
|
|
|
+ if (source == null || target == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Class<?> actualEditable = target.getClass();
|
|
|
+ PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
|
|
|
+ for (PropertyDescriptor targetPd : targetPds) {
|
|
|
+ if (targetPd.getWriteMethod() == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ Object value = getValueFromSource(source, targetPd);
|
|
|
+ if (value == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (!isSimpleProperty(targetPd.getPropertyType()) && !targetPd.getPropertyType().isInterface()) {
|
|
|
+ Object targetPdValue = targetPd.getReadMethod().invoke(target);
|
|
|
+ targetPdValue = AopTargetUtil.getTarget(targetPdValue);
|
|
|
+ if (targetPdValue == null) {
|
|
|
+ targetPdValue = targetPd.getPropertyType().getDeclaredConstructor().newInstance();
|
|
|
+ }
|
|
|
+ copyPropertiesWithoutNull(value, targetPdValue);
|
|
|
+ setValue(target, targetPd, targetPdValue);
|
|
|
+ } else if (targetPd.getPropertyType().isAssignableFrom(List.class)) {
|
|
|
+ Class paramCls = getFieldActualType(actualEditable.getDeclaredField(targetPd.getName()));
|
|
|
+ if (paramCls != null) {
|
|
|
+ Object targetPdValue = convertListToList((List) value, paramCls);
|
|
|
+ setValue(target, targetPd, targetPdValue);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ setValue(target, targetPd, value);
|
|
|
+ }
|
|
|
+ } catch (Exception ex) {
|
|
|
+ throw new FatalBeanException("Could not copy properties from source to target", ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void setValue(Object target, PropertyDescriptor targetPd, Object value) throws IllegalAccessException, InvocationTargetException {
|
|
|
+ if (value.getClass().isEnum() && targetPd.getPropertyType() == String.class) {
|
|
|
+ if (CommonEnum.class.isAssignableFrom(value.getClass())) {
|
|
|
+ CommonEnum commonEnum = (CommonEnum) value;
|
|
|
+ value = commonEnum.getRemark();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 这里判断以下value是否为空
|
|
|
+ if ("".equals(value)) {
|
|
|
+ value = null;
|
|
|
+ }
|
|
|
+ if (value != null) {
|
|
|
+ Method writeMethod = targetPd.getWriteMethod();
|
|
|
+ if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
|
|
|
+ writeMethod.setAccessible(true);
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ writeMethod.invoke(target, value);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("复制属性出错,target object type:{},target property name:{},type:{},set value type:{}", target.getClass(), targetPd.getName(), targetPd.getPropertyType(), value.getClass());
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static <T> T mapToBean(Map map, T bean) {
|
|
|
+ BeanMap beanMap = BeanMap.create(bean);
|
|
|
+
|
|
|
+ beanMap.putAll(map);
|
|
|
+ return bean;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public static <T> List<T> convertListToList(List bList, TypeReference<List<T>> typeRef) {
|
|
|
+ if (bList == null) return null;
|
|
|
+ ObjectMapper objectMapper = ApplicationContextHolder.getContext().getBean(ObjectMapper.class);
|
|
|
+ List<T> list = null;
|
|
|
+ try {
|
|
|
+ //objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
|
|
+ String json = objectMapper.writeValueAsString(bList);
|
|
|
+ list = objectMapper.readValue(json, typeRef);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public static <T> List<T> convertListToList(List bList, Class targetClass) {
|
|
|
+ if (bList == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ List<T> list = null;
|
|
|
+ ObjectMapper objectMapper = ApplicationContextHolder.getContext().getBean(ObjectMapper.class);
|
|
|
+ if (targetClass == Map.class) {
|
|
|
+ targetClass = HashMap.class;
|
|
|
+ }
|
|
|
+ JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class, targetClass);
|
|
|
+ objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
|
|
+ String json = null;
|
|
|
+ try {
|
|
|
+ json = objectMapper.writeValueAsString(bList);
|
|
|
+ list = objectMapper.readValue(json, javaType);
|
|
|
+ } catch (JsonProcessingException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+/* public static <T> List<T> fastConvertListToList(List bList, Class targetClass) {
|
|
|
+ if (bList == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ String json = JSON.toJSONString(bList, JSONWriter.Feature.FieldBased,JSONWriter.Feature.ReferenceDetection,JSONWriter.Feature.LargeObject);
|
|
|
+ List<T> list = JSON.parseArray(json,targetClass);
|
|
|
+ return list;
|
|
|
+ }*/
|
|
|
+
|
|
|
+ public static <T> List<T> beanConvertListToList(List bList, Class<T> targetClass) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
|
|
|
+ if (bList == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ List<T> list = new ArrayList<>(bList.size());
|
|
|
+
|
|
|
+ for (Object source : bList) {
|
|
|
+ if (Map.class.equals(targetClass)) {
|
|
|
+ Map map = new HashMap();
|
|
|
+ copyPropertiesWithoutNull(source, map);
|
|
|
+ list.add((T) map);
|
|
|
+ } else if (targetClass.isEnum()) {
|
|
|
+ list.add((T) source);
|
|
|
+ } else {
|
|
|
+ Constructor<T> constructor = targetClass.getDeclaredConstructor();
|
|
|
+ if (constructor != null) {
|
|
|
+ T target = constructor.newInstance();
|
|
|
+ copyPropertiesWithoutNull(source, target);
|
|
|
+ list.add(target);
|
|
|
+ } else {
|
|
|
+ log.warn("复制对象没有默认构造参数,请检查,复制类:{}", targetClass.getName());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static String getActualType(Object o, int index) {
|
|
|
+ Type clazz = o.getClass().getGenericSuperclass();
|
|
|
+ ParameterizedType pt = (ParameterizedType) clazz;
|
|
|
+ return pt.getActualTypeArguments()[index].toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Class getFieldActualType(Field field) {
|
|
|
+ Type genType = field.getGenericType();
|
|
|
+ if (genType == null) {
|
|
|
+ return null;
|
|
|
+ } else if (genType instanceof ParameterizedType) {
|
|
|
+ ParameterizedType pt = (ParameterizedType) genType;
|
|
|
+ if (pt.getActualTypeArguments()[0] instanceof ParameterizedType) {
|
|
|
+ return (Class) ((ParameterizedType) pt.getActualTypeArguments()[0]).getRawType();
|
|
|
+ } else {
|
|
|
+ return (Class) pt.getActualTypeArguments()[0];
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Object getValueFromSource(Object source, PropertyDescriptor targetPd) throws InvocationTargetException, IllegalAccessException {
|
|
|
+ Class sourceClass = source.getClass();
|
|
|
+ PropertyDescriptor sourcePd = getPropertyDescriptor(sourceClass, targetPd.getName());
|
|
|
+ if (sourcePd == null || sourcePd.getReadMethod() == null) {
|
|
|
+ Method readMethod = targetPd.getReadMethod();
|
|
|
+ if (readMethod != null) {
|
|
|
+ String readMethodName = readMethod.getName();
|
|
|
+ Method sourceReadMethod = findMethod(sourceClass, readMethodName);
|
|
|
+ if (sourceReadMethod != null && Modifier.isPublic(sourceReadMethod.getDeclaringClass().getModifiers())) {
|
|
|
+ if (targetPd.getPropertyType().equals(sourceReadMethod.getReturnType())) {
|
|
|
+ Object value = readMethod.invoke(source);
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ boolean changeAccess = false;
|
|
|
+ Method readMethod = sourcePd.getReadMethod();
|
|
|
+ if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
|
|
|
+ readMethod.setAccessible(true);
|
|
|
+ changeAccess = true;
|
|
|
+ }
|
|
|
+ Object value = readMethod.invoke(source);
|
|
|
+ if (changeAccess) {
|
|
|
+ readMethod.setAccessible(false);
|
|
|
+ }
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 比较两个实体属性值,返回一个boolean,true则表时两个对象中的属性值无差异
|
|
|
+ *
|
|
|
+ * @param oldObject 进行属性比较的对象1
|
|
|
+ * @param newObject 进行属性比较的对象2
|
|
|
+ * @return 属性差异比较结果boolean
|
|
|
+ */
|
|
|
+ public static boolean compareObject(Object oldObject, Object newObject) {
|
|
|
+ Map<String, Map<String, Object>> resultMap = compareFields(oldObject, newObject);
|
|
|
+
|
|
|
+ if (resultMap.size() > 0) {
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 比较两个实体属性值,返回一个map以有差异的属性名为key,value为一个Map分别存oldObject,newObject此属性名的值
|
|
|
+ *
|
|
|
+ * @param oldObject 进行属性比较的对象1
|
|
|
+ * @param newObject 进行属性比较的对象2
|
|
|
+ * @return 属性差异比较结果map
|
|
|
+ */
|
|
|
+ public static Map<String, Map<String, Object>> compareFields(Object oldObject, Object newObject) {
|
|
|
+ Map<String, Map<String, Object>> map = new HashMap<>();
|
|
|
+
|
|
|
+ try {
|
|
|
+ /**
|
|
|
+ * 只有两个对象都是同一类型的才有可比性
|
|
|
+ */
|
|
|
+ if (oldObject.getClass() == newObject.getClass()) {
|
|
|
+ Class clazz = oldObject.getClass();
|
|
|
+
|
|
|
+ //获取object的所有属性
|
|
|
+ PropertyDescriptor[] pds = Introspector.getBeanInfo(clazz, Object.class).getPropertyDescriptors();
|
|
|
+
|
|
|
+ for (PropertyDescriptor pd : pds) {
|
|
|
+ //遍历获取属性名
|
|
|
+ String name = pd.getName();
|
|
|
+ String description = name;
|
|
|
+
|
|
|
+ Field field = null;
|
|
|
+ try {
|
|
|
+ field = clazz.getDeclaredField(name);
|
|
|
+ } catch (NoSuchFieldException nsee) {
|
|
|
+ try {
|
|
|
+ field = clazz.getSuperclass().getDeclaredField(name);
|
|
|
+ } catch (NoSuchFieldException nse) {
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (field != null) {
|
|
|
+ if (field.isAnnotationPresent(ApiModelProperty.class)) {
|
|
|
+ ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);
|
|
|
+ description = apiModelProperty.value();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //获取属性的get方法
|
|
|
+ Method readMethod = pd.getReadMethod();
|
|
|
+
|
|
|
+ // 在oldObject上调用get方法等同于获得oldObject的属性值
|
|
|
+ Object oldValue = readMethod.invoke(oldObject);
|
|
|
+ // 在newObject上调用get方法等同于获得newObject的属性值
|
|
|
+ Object newValue = readMethod.invoke(newObject);
|
|
|
+
|
|
|
+ if (oldValue == null && newValue == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (oldValue instanceof List || newValue instanceof List) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (oldValue == null && newValue != null) {
|
|
|
+ Map<String, Object> valueMap = new HashMap<>(2);
|
|
|
+ valueMap.put("oldValue", oldValue);
|
|
|
+ valueMap.put("newValue", newValue);
|
|
|
+ map.put(description, valueMap);
|
|
|
+ } else if (oldValue instanceof DataServiceSuperEntity && newValue instanceof DataServiceSuperEntity) {
|
|
|
+ DataServiceSuperEntity oldSp = (DataServiceSuperEntity) oldValue;
|
|
|
+ DataServiceSuperEntity newSp = (DataServiceSuperEntity) newValue;
|
|
|
+ if (!Objects.equals(oldSp.getId(), newSp.getId())) {
|
|
|
+ Map<String, Object> valueMap = new HashMap<>(2);
|
|
|
+ valueMap.put("oldValue", oldValue);
|
|
|
+ valueMap.put("newValue", newValue);
|
|
|
+ map.put(description, valueMap);
|
|
|
+ }
|
|
|
+ } else if (!Objects.equals(oldValue, newValue)) {// 比较这两个值是否相等,不等就可以放入map了
|
|
|
+ Map<String, Object> valueMap = new HashMap<>(2);
|
|
|
+ valueMap.put("oldValue", oldValue);
|
|
|
+ valueMap.put("newValue", newValue);
|
|
|
+ map.put(description, valueMap);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+}
|