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