diff --git a/article_creator.html b/article_creator.html index 9dfb93b71..b63deed6d 100644 --- a/article_creator.html +++ b/article_creator.html @@ -31,51 +31,81 @@

        Creator是一个接口, 只有一个public T create(Object... params)方法,可变参数既适合空参数的Constructor也适合含参数的Constructor。得利于Java 8的新语法特性可以在接口上加上静态方法,Creator对象可以通过Creator.create(Class clazz)方法创建。构建原理是通过Constructor的参数来动态创建的。

-
Constructor<T> constructor0 = null;
-for (Constructor c : clazz.getConstructors()) {  //优先找public 的构造函数
-if (c.getParameterCount() == 0) {
-        constructor0 = c;
-        break;
-    }
-}
-if (constructor0 == null) {//其次找非private带ConstructorProperties的构造函数
-    for (Constructor c : clazz.getDeclaredConstructors()) {
-        if (Modifier.isPrivate(c.getModifiers())) continue;
-        if (c.getAnnotation(ConstructorProperties.class) != null) {
-            constructor0 = c;
-            break;
-        }
-    }
-}
-if (constructor0 == null) {//再次找非private且带-parameters编译项的构造函数 java 8以上才支持
-    for (Constructor c : clazz.getDeclaredConstructors()) {
-        if (Modifier.isPrivate(c.getModifiers())) continue;
-        Parameter[] params = c.getParameters();
-        if (params.length == 0) continue;
-        boolean flag = true;
-        for (Parameter param : params) {
-            try {
-                clazz.getDeclaredField(param.getName());
-            } catch (Exception e) {
-                flag = false;
-                break;
-            }
-        }
-        if (flag) {
-            constructor0 = c;
-            break;
-        }
-    }
-}
-if (constructor0 == null) {//最后找非private的空构造函数
-    for (Constructor c : clazz.getDeclaredConstructors()) {
-        if (Modifier.isPrivate(c.getModifiers())) continue;
-        if (c.getParameterCount() == 0) {
-            constructor0 = c;
-            break;
-        }
-    }
-}
+
        Constructor<T> constructor0 = null;
+        SimpleEntry<String, Class>[] constructorParameters0 = null; //构造函数的参数
+
+        if (constructor0 == null) {  // 1、查找public的空参数构造函数
+            for (Constructor c : clazz.getConstructors()) {
+                if (c.getParameterCount() == 0) {
+                    constructor0 = c;
+                    constructorParameters0 = new SimpleEntry[0];
+                    break;
+                }
+            }
+        }
+        if (constructor0 == null) {  // 2、查找public带ConstructorProperties注解的构造函数
+            for (Constructor c : clazz.getConstructors()) {
+                ConstructorProperties cp = (ConstructorProperties) c.getAnnotation(ConstructorProperties.class);
+                if (cp == null) continue;
+                SimpleEntry<String, Class>[] fields = ConstructorParameters.CreatorInner.getConstructorField(clazz, cp.value());
+                if (fields != null) {
+                    constructor0 = c;
+                    constructorParameters0 = fields;
+                    break;
+                }
+            }
+        }
+        if (constructor0 == null) {  // 3、查找public且不带ConstructorProperties注解的构造函数
+            List<Constructor> cs = new ArrayList<>();
+            for (Constructor c : clazz.getConstructors()) {
+                if (c.getAnnotation(ConstructorProperties.class) != null) continue;
+                if (c.getParameterCount() < 1) continue;
+                cs.add(c);
+            }
+            //优先参数最多的构造函数
+            cs.sort((o1, o2) -> o2.getParameterCount() - o1.getParameterCount());
+            for (Constructor c : cs) {
+                SimpleEntry<String, Class>[] fields = ConstructorParameters.CreatorInner.getConstructorField(clazz, Type.getConstructorDescriptor(c));
+                if (fields != null) {
+                    constructor0 = c;
+                    constructorParameters0 = fields;
+                    break;
+                }
+            }
+        }
+        if (constructor0 == null) {  // 4、查找非private带ConstructorProperties的构造函数
+            for (Constructor c : clazz.getDeclaredConstructors()) {
+                if (Modifier.isPublic(c.getModifiers()) || Modifier.isPrivate(c.getModifiers())) continue;
+                ConstructorProperties cp = (ConstructorProperties) c.getAnnotation(ConstructorProperties.class);
+                if (cp == null) continue;
+                SimpleEntry<String, Class>[] fields = ConstructorParameters.CreatorInner.getConstructorField(clazz, cp.value());
+                if (fields != null) {
+                    constructor0 = c;
+                    constructorParameters0 = fields;
+                    break;
+                }
+            }
+        }
+        if (constructor0 == null) {  // 5、查找非private且不带ConstructorProperties的构造函数
+            List<Constructor> cs = new ArrayList<>();
+            for (Constructor c : clazz.getDeclaredConstructors()) {
+                if (Modifier.isPublic(c.getModifiers()) || Modifier.isPrivate(c.getModifiers())) continue;
+                if (c.getAnnotation(ConstructorProperties.class) != null) continue;
+                if (c.getParameterCount() < 1) continue;
+                cs.add(c);
+            }
+            //优先参数最多的构造函数
+            cs.sort((o1, o2) -> o2.getParameterCount() - o1.getParameterCount());
+            for (Constructor c : cs) {
+                SimpleEntry<String, Class>[] fields = ConstructorParameters.CreatorInner.getConstructorField(clazz, Type.getConstructorDescriptor(c));
+                if (fields != null) {
+                    constructor0 = c;
+                    constructorParameters0 = fields;
+                    break;
+                }
+            }
+        }
+                

        从以上代码可以看出,根据优先级选择Constructor,为了减少学习成本,Creator直接重用了java.beans.ConstructorProperties注解,又因ConstructorProperties只能标记在Constructor上,因此定义一个Creator.ConstructorParameters注解,用于标记在Creator的create方法上。

diff --git a/convert.html b/convert.html index c929291fa..d0acdcfbd 100644 --- a/convert.html +++ b/convert.html @@ -276,7 +276,6 @@ }

        通常JavaBean类默认有个public空参数的构造函数,因此大部分情况下不要自定义Creator,其实只要不是private的空参数构造函数Convert都能自动支持(其他的框架都仅支持public的构造函数),只有仅含private的构造函数才需要自定义Creator。带参数的构造函数就需要标记@java.beans.ConstructorProperties,常见于Immutable Object。
-         [小技巧]: 若使用Java 8编译项的新特性,带上 -parameters 编译项进行编译的类,带参数的构造函数可以省去@ConstructorProperties注解,Convert会自动匹配参数名动态生成Creator。


        Convert 支持自定义Decode、Encode。