Browse Source

增加对泛型list的转换

zhouhao 7 years ago
parent
commit
78e5e60887

+ 1 - 1
hsweb-core/src/main/java/org/hswebframework/web/bean/Converter.java

@@ -2,5 +2,5 @@ package org.hswebframework.web.bean;
 
 @FunctionalInterface
 public interface Converter {
-    <T> T convert(Object source, Class<T> targetClass);
+    <T> T convert(Object source, Class<T> targetClass,Class[] genericType);
 }

+ 54 - 16
hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java

@@ -8,9 +8,12 @@ import org.apache.commons.beanutils.PropertyUtilsBean;
 import org.hswebframework.utils.time.DateFormatter;
 import org.hswebframework.web.dict.EnumDict;
 import org.hswebframework.web.proxy.Proxy;
+import org.springframework.core.ResolvableType;
 import org.springframework.util.ClassUtils;
+import org.springframework.util.ReflectionUtils;
 
 import java.beans.PropertyDescriptor;
+import java.lang.reflect.Field;
 import java.util.*;
 import java.util.function.BiFunction;
 import java.util.function.Function;
@@ -32,6 +35,8 @@ public final class FastBeanCopier {
 
     public static final DefaultConvert DEFAULT_CONVERT = new DefaultConvert();
 
+    public static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
+
     static {
         wrapperClassMapping.put(byte.class, Byte.class);
         wrapperClassMapping.put(short.class, Short.class);
@@ -155,7 +160,8 @@ public final class FastBeanCopier {
             if (!sourceProperty.isPrimitive()) {
                 code.append("if(source.").append(sourceProperty.getReadMethod()).append("!=null){\n");
             }
-            code.append(targetProperty.generateVar(targetProperty.getName())).append("=").append(sourceProperty.generateGetter(targetProperty.getType()))
+            code.append(targetProperty.generateVar(targetProperty.getName())).append("=")
+                    .append(sourceProperty.generateGetter(target, targetProperty.getType()))
                     .append(";\n");
 
             if (!targetProperty.isPrimitive()) {
@@ -185,7 +191,7 @@ public final class FastBeanCopier {
         protected String writeMethodName;
 
         @Getter
-        protected Function<Class, String> getter;
+        protected BiFunction<Class, Class, String> getter;
 
         @Getter
         protected BiFunction<Class, String, String> setter;
@@ -193,6 +199,9 @@ public final class FastBeanCopier {
         @Getter
         protected Class type;
 
+        @Getter
+        protected Class beanType;
+
         public String getReadMethod() {
             return readMethodName + "()";
         }
@@ -245,13 +254,26 @@ public final class FastBeanCopier {
             return getWrapperType().getSimpleName().concat(".valueOf(").concat(getter).concat(")");
         }
 
-        public Function<Class, String> createGetterFunction() {
+        public BiFunction<Class, Class, String> createGetterFunction() {
 
-            return (targetType) -> {
+            return (targetBeanType, targetType) -> {
                 String getterCode = "source." + getReadMethod();
 
+                String generic = "org.hswebframework.web.bean.FastBeanCopier.EMPTY_CLASS_ARRAY";
+                Field field = ReflectionUtils.findField(targetBeanType, name);
+                boolean hasGeneric = false;
+                if (field != null) {
+                    String[] arr = Arrays.stream(ResolvableType.forField(field)
+                            .getGenerics()).map(ResolvableType::getRawClass)
+                            .map(t -> t.getName().concat(".class"))
+                            .toArray(String[]::new);
+                    if (arr.length > 0) {
+                        generic = "new Class[]{" + String.join(",", arr) + "}";
+                        hasGeneric = true;
+                    }
+                }
                 String convert = "converter.convert((Object)(" + (isPrimitive() ? castWrapper(getterCode) : getterCode) + "),"
-                        + getTypeName(targetType) + ".class)";
+                        + getTypeName(targetType) + ".class," + generic + ")";
                 StringBuilder convertCode = new StringBuilder();
 
                 if (targetType != getType()) {
@@ -301,13 +323,18 @@ public final class FastBeanCopier {
                 } else {
                     if (Cloneable.class.isAssignableFrom(targetType)) {
                         try {
-//                            targetType.getDeclaredMethod("clone");
                             convertCode.append("(" + getTypeName() + ")").append(getterCode).append(".clone()");
                         } catch (Exception e) {
                             convertCode.append(getterCode);
                         }
                     } else {
-                        convertCode.append(getterCode);
+                        if ((Map.class.isAssignableFrom(targetType)
+                                || Collection.class.isAssignableFrom(type)) && hasGeneric) {
+                            convertCode.append("(" + getTypeName() + ")").append(convert);
+                        } else {
+                            convertCode.append(getterCode);
+                        }
+
                     }
 
                 }
@@ -322,8 +349,8 @@ public final class FastBeanCopier {
             return (sourceType, paramGetter) -> settingNameSupplier.apply(paramGetter);
         }
 
-        public String generateGetter(Class targetType) {
-            return getGetter().apply(targetType);
+        public String generateGetter(Class targetBeanType, Class targetType) {
+            return getGetter().apply(targetBeanType, targetType);
         }
 
         public String generateSetter(Class targetType, String getter) {
@@ -340,6 +367,8 @@ public final class FastBeanCopier {
             getter = createGetterFunction();
             setter = createSetterFunction(paramGetter -> writeMethodName + "(" + paramGetter + ")");
             name = descriptor.getName();
+            beanType = descriptor.getReadMethod().getDeclaringClass();
+
         }
     }
 
@@ -352,6 +381,7 @@ public final class FastBeanCopier {
 
             this.getter = createGetterFunction();
             this.setter = createSetterFunction(paramGetter -> "put(\"" + name + "\"," + paramGetter + ")");
+            beanType = Map.class;
         }
 
         @Override
@@ -387,7 +417,7 @@ public final class FastBeanCopier {
 
         @Override
         @SuppressWarnings("all")
-        public <T> T convert(Object source, Class<T> targetClass) {
+        public <T> T convert(Object source, Class<T> targetClass, Class[] genericType) {
             if (source == null) {
                 return null;
             }
@@ -397,7 +427,7 @@ public final class FastBeanCopier {
                     if (targetClass.isInstance(val)) {
                         return ((T) val);
                     }
-                    return convert(val, targetClass);
+                    return convert(val, targetClass, genericType);
                 }
             }
             if (targetClass == String.class) {
@@ -430,18 +460,26 @@ public final class FastBeanCopier {
             }
             if (Collection.class.isAssignableFrom(targetClass)) {
                 Collection collection = newCollection(targetClass);
+                Collection sourceCollection;
                 if (source instanceof Collection) {
-                    collection.addAll(((Collection) source));
+                    sourceCollection = (Collection) source;
                 } else if (source instanceof Object[]) {
-                    collection.addAll(Arrays.asList(((Object[]) source)));
+                    sourceCollection = Arrays.asList((Object[]) source);
                 } else {
                     if (source instanceof String) {
                         String stringValue = ((String) source);
-                        collection.addAll(Arrays.asList(stringValue.split("[,]")));
+                        sourceCollection = Arrays.asList(stringValue.split("[,]"));
                     } else {
-                        collection.add(source);
+                        sourceCollection = Arrays.asList(source);
                     }
                 }
+                if (genericType != null && genericType.length > 0 && genericType[0] != Object.class) {
+                    for (Object sourceObj : sourceCollection) {
+                        collection.add(convert(sourceObj, genericType[0], null));
+                    }
+                } else {
+                    collection.addAll(sourceCollection);
+                }
                 return (T) collection;
             }
 
@@ -452,7 +490,7 @@ public final class FastBeanCopier {
                     if (targetClass.isInstance(val)) {
                         return ((T) val);
                     }
-                    return convert(val, targetClass);
+                    return convert(val, targetClass, genericType);
                 }
                 for (T t : targetClass.getEnumConstants()) {
                     if (((Enum) t).name().equalsIgnoreCase(String.valueOf(source))) {

+ 6 - 0
hsweb-core/src/test/java/org/hswebframework/web/bean/NestObject.java

@@ -1,12 +1,18 @@
 package org.hswebframework.web.bean;
 
+import lombok.AllArgsConstructor;
+import lombok.Builder;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 
 /**
  * @author zhouhao
  * @since
  */
 @Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
 public class NestObject implements Cloneable {
     private String name;
 

+ 5 - 4
hsweb-core/src/test/java/org/hswebframework/web/bean/Source.java

@@ -22,20 +22,21 @@ public class Source {
 
     private int age3;
 
-    private Date deleteTime=new Date();
+    private Date deleteTime = new Date();
 
-    private Date createTime=new Date();
+    private Date createTime = new Date();
 
-    private String updateTime="2018-01-01";
+    private String updateTime = "2018-01-01";
 
 
     private NestObject nestObject;
 
+    private List<NestObject> nestObjects = Arrays.asList(new NestObject("test", 1),new NestObject("test", 1));
+
     private Map<String, Object> nestObject2 = new HashMap<>();
 
     private NestObject nestObject3;
 
-
     private Color color = Color.RED;
 
     private String color2 = "红色";

+ 2 - 1
hsweb-core/src/test/java/org/hswebframework/web/bean/Target.java

@@ -17,7 +17,6 @@ public class Target {
     private boolean boy2;
     private String boy3;
 
-
     private int age;
 
     private int age2;
@@ -34,6 +33,8 @@ public class Target {
 
     private NestObject nestObject2;
 
+    private List<Map<String,Object>> nestObjects;
+
     private Map<String, Object> nestObject3;