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 fieldInfoMap = new LinkedHashMap(); Map, Field[]> classFieldCache = new HashMap, Field[]>(); + boolean kotlin = TypeUtils.isKotlin(clazz); + Field[] declaredFields = clazz.getDeclaredFields(); if (!fieldOnly) { List methodList = new ArrayList(); @@ -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 000000000..8ad08b9be Binary files /dev/null and b/src/test/resources/kotlin/MyStateObject.clazz differ