From 0985590c3d77faaf8ac48d37b23d0f10d59bf2d3 Mon Sep 17 00:00:00 2001
From: wenshao <szujobs@hotmail.com>
Date: Sun, 6 Aug 2017 14:24:15 +0800
Subject: [PATCH] improved support kotlin data class. #1374

---
 .../alibaba/fastjson/parser/JavaBeanInfo.java |  11 ++--
 .../com/alibaba/fastjson/util/TypeUtils.java  |  62 ++++++++++++++----
 .../json/bvt/kotlin/DataClassTest.java        |   2 +-
 .../json/bvt/kotlin/MyStateObjectTest.java    |  38 +++++++++++
 src/test/resources/kotlin/MyStateObject.clazz | Bin 0 -> 2345 bytes
 5 files changed, 95 insertions(+), 18 deletions(-)
 create mode 100644 src/test/java/com/alibaba/json/bvt/kotlin/MyStateObjectTest.java
 create mode 100644 src/test/resources/kotlin/MyStateObject.clazz

diff --git a/src/main/java/com/alibaba/fastjson/parser/JavaBeanInfo.java b/src/main/java/com/alibaba/fastjson/parser/JavaBeanInfo.java
index b52dfb268..56edea9e4 100755
--- a/src/main/java/com/alibaba/fastjson/parser/JavaBeanInfo.java
+++ b/src/main/java/com/alibaba/fastjson/parser/JavaBeanInfo.java
@@ -286,9 +286,10 @@ class JavaBeanInfo {
                 Type[] getGenericParameterTypes = fieldGenericSupport //
                     ? creatorConstructor.getGenericParameterTypes() //
                     : parameterTypes;
-                    
+
+                Annotation[][] paramAnnotationArrays = creatorConstructor.getParameterAnnotations();
                 for (int i = 0; i < parameterTypes.length; ++i) {
-                    Annotation[] paramAnnotations = creatorConstructor.getParameterAnnotations()[i];
+                    Annotation[] paramAnnotations = paramAnnotationArrays[i];
                     JSONField fieldAnnotation = null;
                     for (Annotation paramAnnotation : paramAnnotations) {
                         if (paramAnnotation instanceof JSONField) {
@@ -341,8 +342,9 @@ class JavaBeanInfo {
                             ? factoryMethod.getGenericParameterTypes() //
                             : parameterTypes;
 
+                    Annotation[][] paramAnnotationArrays = factoryMethod.getParameterAnnotations();
                     for (int i = 0; i < parameterTypes.length; ++i) {
-                        Annotation[] paramAnnotations = factoryMethod.getParameterAnnotations()[i];
+                        Annotation[] paramAnnotations = paramAnnotationArrays[i];
                         JSONField fieldAnnotation = null;
                         for (Annotation paramAnnotation : paramAnnotations) {
                             if (paramAnnotation instanceof JSONField) {
@@ -397,10 +399,11 @@ class JavaBeanInfo {
                                 ? creatorConstructor.getGenericParameterTypes() //
                                 : parameterTypes;
 
+                        Annotation[][] paramAnnotationArrays = creatorConstructor.getParameterAnnotations();
                         for (int i = 0; i < parameterTypes.length; ++i) {
                             String paramName = parameters[i];
 
-                            Annotation[] paramAnnotations = creatorConstructor.getParameterAnnotations()[i];
+                            Annotation[] paramAnnotations = paramAnnotationArrays[i];
                             JSONField fieldAnnotation = null;
                             for (Annotation paramAnnotation : paramAnnotations) {
                                 if (paramAnnotation instanceof JSONField) {
diff --git a/src/main/java/com/alibaba/fastjson/util/TypeUtils.java b/src/main/java/com/alibaba/fastjson/util/TypeUtils.java
index 78dc0f7bc..2f8a96375 100755
--- a/src/main/java/com/alibaba/fastjson/util/TypeUtils.java
+++ b/src/main/java/com/alibaba/fastjson/util/TypeUtils.java
@@ -15,25 +15,14 @@
  */
 package com.alibaba.fastjson.util;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.*;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.security.AccessControlException;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
+import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
@@ -926,6 +915,8 @@ public class TypeUtils {
         Map<String, FieldInfo> fieldInfoMap = new LinkedHashMap<String, FieldInfo>();
         Map<Class<?>, Field[]> classFieldCache = new HashMap<Class<?>, Field[]>();
 
+        boolean kotlin = TypeUtils.isKotlin(clazz);
+
         Field[] declaredFields = clazz.getDeclaredFields();
         if (!fieldOnly) {
             List<Method> methodList = new ArrayList<Method>();
@@ -954,6 +945,11 @@ public class TypeUtils {
                 }
             }
 
+            // for kotlin
+            Constructor[] constructors = null;
+            Annotation[][] paramAnnotationArrays = null;
+            String[] paramNames = null;
+            short[] paramNameMapping = null;
 
             for (Method method : methodList) {
                 String methodName = method.getName();
@@ -970,6 +966,46 @@ public class TypeUtils {
                     annotation = getSupperMethodAnnotation(clazz, method);
                 }
 
+                if (annotation == null && kotlin) {
+                    if (constructors == null) {
+                        constructors = clazz.getDeclaredConstructors();
+                        if (constructors.length == 1) {
+                            paramAnnotationArrays = constructors[0].getParameterAnnotations();
+                            paramNames = TypeUtils.getKoltinConstructorParameters(clazz);
+
+                            if (paramNames != null) {
+                                String[] paramNames_sorted = new String[paramNames.length];
+                                System.arraycopy(paramNames, 0,paramNames_sorted, 0, paramNames.length);
+                                Arrays.sort(paramNames_sorted);
+
+                                paramNameMapping = new short[paramNames.length];
+                                for (short p = 0; p < paramNames.length; p++) {
+                                    int index = Arrays.binarySearch(paramNames_sorted, paramNames[p]);
+                                    paramNameMapping[index] = p;
+                                }
+                                paramNames = paramNames_sorted;
+                            }
+
+                        }
+                    }
+                    if (paramNames != null && paramNameMapping != null && methodName.startsWith("get")) {
+                        String propertyName = decapitalize(methodName.substring(3));
+                        int p = Arrays.binarySearch(paramNames, propertyName);
+                        if (p >= 0) {
+                            short index = paramNameMapping[p];
+                            Annotation[] paramAnnotations = paramAnnotationArrays[index];
+                            if (paramAnnotations != null) {
+                                for (Annotation paramAnnotation : paramAnnotations) {
+                                    if (paramAnnotation instanceof JSONField) {
+                                        annotation = (JSONField) paramAnnotation;
+                                        break;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+
                 if (annotation != null) {
                     if (!annotation.serialize()) {
                         continue;
diff --git a/src/test/java/com/alibaba/json/bvt/kotlin/DataClassTest.java b/src/test/java/com/alibaba/json/bvt/kotlin/DataClassTest.java
index ffabd01f8..709db510c 100644
--- a/src/test/java/com/alibaba/json/bvt/kotlin/DataClassTest.java
+++ b/src/test/java/com/alibaba/json/bvt/kotlin/DataClassTest.java
@@ -18,7 +18,7 @@ public class DataClassTest extends TestCase {
 
         String json = "{\"aa\":1001,\"bb\":1002}";
         Object obj = JSON.parseObject(json, clazz);
-        assertEquals("{\"a\":1001,\"b\":1002}", JSON.toJSONString(obj));
+        assertEquals("{\"aa\":1001,\"bb\":1002}", JSON.toJSONString(obj));
     }
 
     public static class ExtClassLoader extends ClassLoader {
diff --git a/src/test/java/com/alibaba/json/bvt/kotlin/MyStateObjectTest.java b/src/test/java/com/alibaba/json/bvt/kotlin/MyStateObjectTest.java
new file mode 100644
index 000000000..d50109d22
--- /dev/null
+++ b/src/test/java/com/alibaba/json/bvt/kotlin/MyStateObjectTest.java
@@ -0,0 +1,38 @@
+package com.alibaba.json.bvt.kotlin;
+
+import com.alibaba.fastjson.JSON;
+import junit.framework.TestCase;
+import org.apache.commons.io.IOUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Created by wenshao on 06/08/2017.
+ */
+public class MyStateObjectTest extends TestCase {
+    public void test_user() throws Exception {
+        ExtClassLoader classLoader = new ExtClassLoader();
+        Class clazz = classLoader.loadClass("MyStateObject");
+
+        String json = "{\"name\":\"wenshao\",\"age\":99}";
+        Object obj = JSON.parseObject(json, clazz);
+        assertEquals("{\"age\":99,\"name\":\"wenshao\"}", JSON.toJSONString(obj));
+    }
+
+    public static class ExtClassLoader extends ClassLoader {
+
+        public ExtClassLoader() throws IOException {
+            super(Thread.currentThread().getContextClassLoader());
+
+            {
+                byte[] bytes;
+                InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("kotlin/MyStateObject.clazz");
+                bytes = IOUtils.toByteArray(is);
+                is.close();
+
+                super.defineClass("MyStateObject", bytes, 0, bytes.length);
+            }
+        }
+    }
+}
diff --git a/src/test/resources/kotlin/MyStateObject.clazz b/src/test/resources/kotlin/MyStateObject.clazz
new file mode 100644
index 0000000000000000000000000000000000000000..8ad08b9be96c30eaf104d86202fad66bc3be1484
GIT binary patch
literal 2345
zcmah}T~8ZV5IuLjw%3b+wH*>5kdQzde~_4vH2p|u18FFxhNK}SCG=~tx3FM#UGEwx
zFIArM6OeeTDn;o-9$Kk^sF5m4q(1aV^oLYc)tTLmW8+kj?47xH@0@$i%<TO6@2|fB
z7{`|aopbjVT-`NptgIU)Hwq!3t?OHQzM@;J`4_t(0ol?w4S{6w<=X|fW?HM41%``u
zZ8g7cxGOc?w4A(dSvG;1Hu>|mJ72F<=u~voaOXXcBk4>#OdMfEVvwNHW$v2k2y_=)
z*bzoZUnLTvAP^z6NnV7~nL-?0=;qiYy|`jpru)9Y(RBMIh0LOYu)v88+pU;Zetl~*
zZ(6QVv-C>7V6h;_EICme6F62{GfEpb^%`-e69p%bB5<Y|+0W7C_Pa8RarB{IMK6wf
zG--VVgDPa45Kv3@X4SR~%RS$`7$@;1yLwMxr1_E{)rHKVj4)!4O2S73;v6?pHonp8
z6<1(7edugE!$P5HFVN9`!)Xlj4QT<zwS6L#oWpG}RW~bTqZUO@#V89*wbU-n?K7d^
z92H2fRt>8xaP}1n+Z!VQz8uFG&NDWpC^9-kjX-c01qRZTmH%Pm1zqBxx2bC~3f_$)
zix_WEGbwAjvv$oc8*xk^!F8doY3hDoYZO=MLgU-IUZIxkY3BSQWp@cnuNl|*%xk-&
z5fsOVxX#@%Es!V%4LN7HdRcdMq9<)`h3GRC{D{zU#an`eY|yGqZS&Xu{UKHAl~hUF
zzpv6y(z<-3sFD(+Wd~VVIe4J-?%yAm#>7-lGNMWS(pZSBOg4P*LqyUdvoWoMcW0hI
z2$3J>H=aMJb&^lPiX!=ep67+q0Wq7>y68anxT0zOa<3Q@GtajfBH=@93-XiX6ZE#Y
zm1tb55Yc{FiE0XMdW?ukuo=_TgC8R)R!PMs#bMiBGiuc0ewMy++<KWl5#{#1s^Og5
zpl&~Yt8TgGrctoAOvhZQ7?Uq&5PecyWgcF3Nv|yGHB+Y(xB0<C#<Yz2`sRvJ3wA~h
zV>M<#3uq?|&eF!5UJb(31-o7=8Pg`C_5~P=ZESF!J|>xJO4Eu*9?4te3X_eJP4Xxs
zt0DmfJk##bD$ivn8_xcMj-SYp@EJYh{wCQ@S}oC^VL*Y+kO^o6Cfa~fkLl>^fCNvN
zfW-n??#7;6^5|0xWcP3~n|p$e?7$PGer|vb`G*2lbUcvB9*dJ2Oe4hfF2%(pqQ~k%
zM28xxhiSJ(wRnZ<R;8yJN}Gc{rLPK3fTkPK<s45@Ral+ot9u4%DL1f(H#psXtS?M!
z2-6zEv_M!hnO0$10dL|=kjM*kQJ7!{2j%Z}pm0%(gW<qUO=NQeyU6(WF4Hj?Qis}7
zQo&=4STXO51j<=TKf~zK9?mB7ySTuRWRh?Bergx*B;O-{7grdU717KK5H17=eH^v)
z2V%SU;1R-iLfXkS+Dd)RjUvEQ6iD+?OiprPrf@9)SR?>W-KA{qA;xmQL)t+uw-0HK
z5l89&6d&!Nm%(V2`W{jF5#-Pg!t&$LOY|<t|KMB{(pB*{B>MjGIiX7U6km|7(rq)8
zx56?)1<ZQCk5PQFnxhTO^W(-cgoB&-WEn>sbUL`@AnZN6yl0OC%|XI};vnW=$iXQG
RryWdrZx<X)ILJD<{U0-^)<ggR

literal 0
HcmV?d00001

-- 
GitLab