From 56f00a8e29c3f9bf9453cd6b39fbfd12ab086a4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E9=93=81?= Date: Sat, 2 Apr 2016 19:32:51 +0800 Subject: [PATCH] improved performance --- src/main/java/com/alibaba/fastjson/JSON.java | 3 +- .../fastjson/parser/DefaultJSONParser.java | 2 +- .../alibaba/fastjson/parser/ParserConfig.java | 2 +- .../serializer/ASMSerializerFactory.java | 23 +++++- .../fastjson/serializer/FieldSerializer.java | 6 +- .../serializer/JavaBeanSerializer.java | 35 +++++++-- .../com/alibaba/fastjson/util/ASMUtils.java | 2 +- .../fastjson/util/DeserializeBeanInfo.java | 52 +++++++------ .../com/alibaba/fastjson/util/TypeUtils.java | 16 ++-- .../json/test/benchmark/BenchmarkMain.java | 13 ++-- .../json/test/codec/FastjsonSCodec.java | 74 +++++++++++++++++++ 11 files changed, 173 insertions(+), 55 deletions(-) create mode 100644 src/test/java/com/alibaba/json/test/codec/FastjsonSCodec.java diff --git a/src/main/java/com/alibaba/fastjson/JSON.java b/src/main/java/com/alibaba/fastjson/JSON.java index 0c819a3eb..a2c4b2cd6 100755 --- a/src/main/java/com/alibaba/fastjson/JSON.java +++ b/src/main/java/com/alibaba/fastjson/JSON.java @@ -29,6 +29,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import com.alibaba.fastjson.annotation.JSONType; import com.alibaba.fastjson.parser.DefaultJSONParser; import com.alibaba.fastjson.parser.Feature; import com.alibaba.fastjson.parser.JSONLexer; @@ -679,7 +680,7 @@ public abstract class JSON implements JSONStreamAware, JSONAware { } try { - List getters = TypeUtils.computeGetters(clazz, null); + List getters = TypeUtils.computeGetters(clazz, clazz.getAnnotation(JSONType.class), null, false); JSONObject json = new JSONObject(getters.size()); diff --git a/src/main/java/com/alibaba/fastjson/parser/DefaultJSONParser.java b/src/main/java/com/alibaba/fastjson/parser/DefaultJSONParser.java index 80164ea7b..f2552e23f 100755 --- a/src/main/java/com/alibaba/fastjson/parser/DefaultJSONParser.java +++ b/src/main/java/com/alibaba/fastjson/parser/DefaultJSONParser.java @@ -192,7 +192,7 @@ public class DefaultJSONParser extends AbstractJSONParser implements Closeable { final JSONLexer lexer = this.lexer; if (lexer.token() == JSONToken.NULL) { - lexer.next(); + lexer.nextToken(); return null; } diff --git a/src/main/java/com/alibaba/fastjson/parser/ParserConfig.java b/src/main/java/com/alibaba/fastjson/parser/ParserConfig.java index 25b36da29..d8990de2e 100644 --- a/src/main/java/com/alibaba/fastjson/parser/ParserConfig.java +++ b/src/main/java/com/alibaba/fastjson/parser/ParserConfig.java @@ -473,7 +473,7 @@ public class ParserConfig { public ObjectDeserializer createJavaBeanDeserializer(Class clazz, Type type) { boolean asmEnable = this.asmEnable; if (asmEnable) { - Class superClass = DeserializeBeanInfo.getBuilderClass(clazz); + Class superClass = DeserializeBeanInfo.getBuilderClass(clazz.getAnnotation(JSONType.class)); if (superClass == null) { superClass = clazz; } diff --git a/src/main/java/com/alibaba/fastjson/serializer/ASMSerializerFactory.java b/src/main/java/com/alibaba/fastjson/serializer/ASMSerializerFactory.java index fcf2f2df1..2d4236d40 100755 --- a/src/main/java/com/alibaba/fastjson/serializer/ASMSerializerFactory.java +++ b/src/main/java/com/alibaba/fastjson/serializer/ASMSerializerFactory.java @@ -10,7 +10,9 @@ import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.math.BigDecimal; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -122,8 +124,10 @@ public class ASMSerializerFactory implements Opcodes { if (clazz.isPrimitive()) { throw new JSONException("unsupportd class " + clazz.getName()); } + + JSONType jsonType = clazz.getAnnotation(JSONType.class); - List getters = TypeUtils.computeGetters(clazz, aliasMap, false); + List getters = TypeUtils.computeGetters(clazz, jsonType, aliasMap, false); if (getters.size() > 256) { return null; @@ -197,8 +201,6 @@ public class ASMSerializerFactory implements Opcodes { "()Lcom/alibaba/fastjson/serializer/SerializeWriter;"); mw.visitVarInsn(ASTORE, context.var("out")); - JSONType jsonType = clazz.getAnnotation(JSONType.class); - if (jsonType == null || jsonType.alphabetic()) { Label _else = new Label(); @@ -231,7 +233,20 @@ public class ASMSerializerFactory implements Opcodes { mw.visitEnd(); } - List sortedGetters = TypeUtils.computeGetters(clazz, aliasMap, true); + String[] orders = null; + + if (jsonType != null) { + orders = jsonType.orders(); + } + + final List sortedGetters; + if (orders != null && orders.length != 0) { + sortedGetters = TypeUtils.computeGetters(clazz, jsonType, aliasMap, true); + } else { + sortedGetters = new ArrayList(getters); + Collections.sort(sortedGetters); + } + { // sortField support diff --git a/src/main/java/com/alibaba/fastjson/serializer/FieldSerializer.java b/src/main/java/com/alibaba/fastjson/serializer/FieldSerializer.java index a8f2f183c..b13ce5d13 100755 --- a/src/main/java/com/alibaba/fastjson/serializer/FieldSerializer.java +++ b/src/main/java/com/alibaba/fastjson/serializer/FieldSerializer.java @@ -25,7 +25,7 @@ import com.alibaba.fastjson.util.FieldInfo; /** * @author wenshao[szujobs@hotmail.com] */ -public abstract class FieldSerializer { +public abstract class FieldSerializer implements Comparable { public final FieldInfo fieldInfo; private final String double_quoted_fieldPrefix; @@ -91,4 +91,8 @@ public abstract class FieldSerializer { public abstract void writeProperty(JSONSerializer serializer, Object propertyValue) throws Exception; public abstract void writeValue(JSONSerializer serializer, Object propertyValue) throws Exception; + + public int compareTo(FieldSerializer o) { + return this.fieldInfo.compareTo(o.fieldInfo); + } } diff --git a/src/main/java/com/alibaba/fastjson/serializer/JavaBeanSerializer.java b/src/main/java/com/alibaba/fastjson/serializer/JavaBeanSerializer.java index f89f5a2ed..2873c7488 100644 --- a/src/main/java/com/alibaba/fastjson/serializer/JavaBeanSerializer.java +++ b/src/main/java/com/alibaba/fastjson/serializer/JavaBeanSerializer.java @@ -20,12 +20,14 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONException; +import com.alibaba.fastjson.annotation.JSONType; import com.alibaba.fastjson.util.FieldInfo; import com.alibaba.fastjson.util.TypeUtils; @@ -64,10 +66,16 @@ public class JavaBeanSerializer implements ObjectSerializer { public JavaBeanSerializer(Class clazz, Map aliasMap){ this.features = TypeUtils.getSerializeFeatures(clazz); + + JSONType jsonType = clazz.getAnnotation(JSONType.class); + + if (jsonType != null) { + features = SerializerFeature.of(jsonType.serialzeFeatures()); + } { List getterList = new ArrayList(); - List fieldInfoList = TypeUtils.computeGetters(clazz, aliasMap, false); + List fieldInfoList = TypeUtils.computeGetters(clazz, jsonType, aliasMap, false); for (FieldInfo fieldInfo : fieldInfoList) { getterList.add(createFieldSerializer(fieldInfo)); @@ -75,15 +83,26 @@ public class JavaBeanSerializer implements ObjectSerializer { getters = getterList.toArray(new FieldSerializer[getterList.size()]); } - { - List getterList = new ArrayList(); - List fieldInfoList = TypeUtils.computeGetters(clazz, aliasMap, true); + + String[] orders = null; - for (FieldInfo fieldInfo : fieldInfoList) { - getterList.add(createFieldSerializer(fieldInfo)); - } + if (jsonType != null) { + orders = jsonType.orders(); + } + + if (orders != null && orders.length != 0) { + List fieldInfoList = TypeUtils.computeGetters(clazz, jsonType, aliasMap, true); + List getterList = new ArrayList(); - sortedGetters = getterList.toArray(new FieldSerializer[getterList.size()]); + for (FieldInfo fieldInfo : fieldInfoList) { + getterList.add(createFieldSerializer(fieldInfo)); + } + + sortedGetters = getterList.toArray(new FieldSerializer[getterList.size()]); + } else { + sortedGetters = new FieldSerializer[getters.length]; + System.arraycopy(getters, 0, sortedGetters, 0, getters.length); + Arrays.sort(sortedGetters); } } diff --git a/src/main/java/com/alibaba/fastjson/util/ASMUtils.java b/src/main/java/com/alibaba/fastjson/util/ASMUtils.java index f319fe086..15e187ae8 100755 --- a/src/main/java/com/alibaba/fastjson/util/ASMUtils.java +++ b/src/main/java/com/alibaba/fastjson/util/ASMUtils.java @@ -32,7 +32,7 @@ public class ASMUtils { return IS_ANDROID; } - public static String getDesc(Method method) { + public static String getDesc(Method method) { Class[] types = method.getParameterTypes(); StringBuilder buf = new StringBuilder((types.length + 1) << 4); buf.append('('); diff --git a/src/main/java/com/alibaba/fastjson/util/DeserializeBeanInfo.java b/src/main/java/com/alibaba/fastjson/util/DeserializeBeanInfo.java index 089ed2661..d0f25b832 100755 --- a/src/main/java/com/alibaba/fastjson/util/DeserializeBeanInfo.java +++ b/src/main/java/com/alibaba/fastjson/util/DeserializeBeanInfo.java @@ -37,13 +37,17 @@ public class DeserializeBeanInfo { private final List sortedFieldList = new ArrayList(); private int parserFeatures = 0; + + public final JSONType jsonType; - public DeserializeBeanInfo(Class clazz - , Class builderClass - , Constructor defaultConstructor - , Constructor creatorConstructor - , Method factoryMethod - , Method buildMethod){ + public DeserializeBeanInfo(Class clazz, // + Class builderClass, // + Constructor defaultConstructor, // + Constructor creatorConstructor, // + Method factoryMethod, // + Method buildMethod, // + JSONType jsonType + ){ this.clazz = clazz; this.builderClass = builderClass; this.defaultConstructor = defaultConstructor; @@ -51,6 +55,8 @@ public class DeserializeBeanInfo { this.factoryMethod = factoryMethod; this.parserFeatures = TypeUtils.getParserFeatures(clazz); + this.jsonType = jsonType; + defaultConstructorParameterSize = defaultConstructor != null ? defaultConstructor.getParameterTypes().length : 0; } @@ -113,18 +119,23 @@ public class DeserializeBeanInfo { public static DeserializeBeanInfo computeSetters(Class clazz, Type type) { DeserializeBeanInfo beanInfo = null; + + JSONType jsonType = clazz.getAnnotation(JSONType.class); - Class builderClass = getBuilderClass(clazz); + Class builderClass = getBuilderClass(jsonType); + + Field[] declaredFields = clazz.getDeclaredFields(); + Method[] methods = clazz.getMethods(); Constructor defaultConstructor = getDefaultConstructor(builderClass == null ? clazz : builderClass); if (defaultConstructor != null) { // 如果存在默认构造方法 TypeUtils.setAccessible(defaultConstructor); - beanInfo = new DeserializeBeanInfo(clazz, builderClass, defaultConstructor, null, null, null); + beanInfo = new DeserializeBeanInfo(clazz, builderClass, defaultConstructor, null, null, null, jsonType); } else if (defaultConstructor == null && !(clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers()))) { Constructor creatorConstructor = getCreatorConstructor(clazz); if (creatorConstructor != null) { // 基于标记 JSONCreator 注解的构造方法 TypeUtils.setAccessible(creatorConstructor); - beanInfo = new DeserializeBeanInfo(clazz, builderClass, null, creatorConstructor, null, null); + beanInfo = new DeserializeBeanInfo(clazz, builderClass, null, creatorConstructor, null, null, jsonType); Class[] types = creatorConstructor.getParameterTypes(); if (types.length > 0) { @@ -143,7 +154,7 @@ public class DeserializeBeanInfo { } Class fieldClass = types[i]; Type fieldType = creatorConstructor.getGenericParameterTypes()[i]; - Field field = TypeUtils.getField(clazz, fieldAnnotation.name()); + Field field = TypeUtils.getField(clazz, fieldAnnotation.name(), declaredFields); final int ordinal = fieldAnnotation.ordinal(); final int serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures()); FieldInfo fieldInfo = new FieldInfo(fieldAnnotation.name(), clazz, fieldClass, fieldType, field, @@ -154,11 +165,11 @@ public class DeserializeBeanInfo { return beanInfo; } - Method factoryMethod = getFactoryMethod(clazz); // 基于标记 JSONCreator 注解的工厂方法 + Method factoryMethod = getFactoryMethod(clazz, methods); // 基于标记 JSONCreator 注解的工厂方法 if (factoryMethod != null) { TypeUtils.setAccessible(factoryMethod); - beanInfo = new DeserializeBeanInfo(clazz, builderClass, null, null, factoryMethod, null); + beanInfo = new DeserializeBeanInfo(clazz, builderClass, null, null, factoryMethod, null, jsonType); Class[] types = factoryMethod.getParameterTypes(); if (types.length > 0) { Annotation[][] paramAnnotationArrays = factoryMethod.getParameterAnnotations(); @@ -177,7 +188,7 @@ public class DeserializeBeanInfo { Class fieldClass = types[i]; Type fieldType = factoryMethod.getGenericParameterTypes()[i]; - Field field = TypeUtils.getField(clazz, fieldAnnotation.name()); + Field field = TypeUtils.getField(clazz, fieldAnnotation.name(), declaredFields); final int ordinal = fieldAnnotation.ordinal(); final int serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures()); FieldInfo fieldInfo = new FieldInfo(fieldAnnotation.name(), clazz, fieldClass, fieldType, field, ordinal, serialzeFeatures); @@ -191,7 +202,7 @@ public class DeserializeBeanInfo { } if (beanInfo == null) { - beanInfo = new DeserializeBeanInfo(clazz, builderClass, null, null, null, null); + beanInfo = new DeserializeBeanInfo(clazz, builderClass, null, null, null, null, jsonType); } if (builderClass != null) { String withPrefix = null; @@ -300,7 +311,7 @@ public class DeserializeBeanInfo { } } - for (Method method : clazz.getMethods()) { // + for (Method method : methods) { // int ordinal = 0, serialzeFeatures = 0; String methodName = method.getName(); if (methodName.length() < 4) { @@ -366,10 +377,10 @@ public class DeserializeBeanInfo { continue; } - Field field = TypeUtils.getField(clazz, propertyName); + Field field = TypeUtils.getField(clazz, propertyName, declaredFields); if (field == null && types[0] == boolean.class) { String isFieldName = "is" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1); - field = TypeUtils.getField(clazz, isFieldName); + field = TypeUtils.getField(clazz, isFieldName, declaredFields); } JSONField fieldAnnotation = null; @@ -515,10 +526,10 @@ public class DeserializeBeanInfo { return creatorConstructor; } - public static Method getFactoryMethod(Class clazz) { + private static Method getFactoryMethod(Class clazz, Method[] methods) { Method factoryMethod = null; - for (Method method : clazz.getDeclaredMethods()) { + for (Method method : methods) { if (!Modifier.isStatic(method.getModifiers())) { continue; } @@ -544,8 +555,7 @@ public class DeserializeBeanInfo { return parserFeatures; } - public static Class getBuilderClass(Class clazz) { - JSONType type = clazz.getAnnotation(JSONType.class); + public static Class getBuilderClass(JSONType type) { if (type == null) { return null; } diff --git a/src/main/java/com/alibaba/fastjson/util/TypeUtils.java b/src/main/java/com/alibaba/fastjson/util/TypeUtils.java index 9d21b1dd2..f143eeeda 100755 --- a/src/main/java/com/alibaba/fastjson/util/TypeUtils.java +++ b/src/main/java/com/alibaba/fastjson/util/TypeUtils.java @@ -897,9 +897,7 @@ public class TypeUtils { Map setters = mapping.getFieldDeserializers(clazz); Constructor constructor = clazz.getDeclaredConstructor(); - if (!constructor.isAccessible()) { - constructor.setAccessible(true); - } + constructor.setAccessible(true); T object = constructor.newInstance(); for (Map.Entry entry : setters.entrySet()) { @@ -1035,11 +1033,7 @@ public class TypeUtils { return clazz; } - public static List computeGetters(Class clazz, Map aliasMap) { - return computeGetters(clazz, aliasMap, true); - } - - public static List computeGetters(Class clazz, Map aliasMap, boolean sorted) { + public static List computeGetters(Class clazz, JSONType jsonType, Map aliasMap, boolean sorted) { Map fieldInfoMap = new LinkedHashMap(); for (Method method : clazz.getMethods()) { @@ -1471,8 +1465,8 @@ public class TypeUtils { return Object.class; } - public static Field getField(Class clazz, String fieldName) { - for (Field field : clazz.getDeclaredFields()) { + public static Field getField(Class clazz, String fieldName, Field[] declaredFields) { + for (Field field : declaredFields) { if (fieldName.equals(field.getName())) { return field; } @@ -1480,7 +1474,7 @@ public class TypeUtils { Class superClass = clazz.getSuperclass(); if (superClass != null && superClass != Object.class) { - return getField(superClass, fieldName); + return getField(superClass, fieldName, superClass.getDeclaredFields()); } return null; diff --git a/src/test/java/com/alibaba/json/test/benchmark/BenchmarkMain.java b/src/test/java/com/alibaba/json/test/benchmark/BenchmarkMain.java index cdd3977eb..a97aca1d6 100755 --- a/src/test/java/com/alibaba/json/test/benchmark/BenchmarkMain.java +++ b/src/test/java/com/alibaba/json/test/benchmark/BenchmarkMain.java @@ -1,15 +1,16 @@ package com.alibaba.json.test.benchmark; -import com.alibaba.json.test.benchmark.decode.EishayDecode; -import com.alibaba.json.test.codec.FastjsonCodec; +import com.alibaba.json.test.benchmark.decode.*; +import com.alibaba.json.test.benchmark.encode.*; +import com.alibaba.json.test.codec.*; public class BenchmarkMain { public static void main(String[] args) throws Exception { // 注意,byte[]在jackson中是使用base64编码的,不正确的。 BenchmarkExecutor executor = new BenchmarkExecutor(); - executor.setExecuteCount(5); - executor.getCodecList().add(new FastjsonCodec()); + executor.setExecuteCount(3); + executor.getCodecList().add(new FastjsonSCodec()); // executor.getCodecList().add(new FastjsonGenCodec()); // executor.getCodecList().add(new FastjsonBeanToArrayCodec()); // executor.getCodecList().add(new JacksonCodec()); @@ -19,14 +20,14 @@ public class BenchmarkMain { // executor.getCodecList().add(new JsonLibCodec()); // executor.getCodecList().add(new JsonSmartCodec()); - executor.setLoopCount(1000 * 1000 * 1); + executor.setLoopCount(1000 * 1 * 1); // executor.getCaseList().add(new EishayDecodeBytes()); // executor.getCaseList().add(new EishayDecode2Bytes()); executor.getCaseList().add(new EishayDecode()); // executor.getCaseList().add(new EishayDecodeByClassName()); // executor.getCaseList().add(new EishayTreeDecode()); -// executor.getCaseList().add(new EishayEncode()); + executor.getCaseList().add(new EishayEncode()); // executor.getCaseList().add(new EishayEncodeManual()); // executor.getCaseList().add(new IntArray1000Decode()); // executor.getCaseList().add(new StringArray1000Decode()); diff --git a/src/test/java/com/alibaba/json/test/codec/FastjsonSCodec.java b/src/test/java/com/alibaba/json/test/codec/FastjsonSCodec.java new file mode 100644 index 000000000..540bd8761 --- /dev/null +++ b/src/test/java/com/alibaba/json/test/codec/FastjsonSCodec.java @@ -0,0 +1,74 @@ +package com.alibaba.json.test.codec; + +import java.util.Collection; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.parser.DefaultExtJSONParser; +import com.alibaba.fastjson.parser.DefaultJSONParser; +import com.alibaba.fastjson.parser.Feature; +import com.alibaba.fastjson.parser.ParserConfig; +import com.alibaba.fastjson.serializer.JSONSerializer; +import com.alibaba.fastjson.serializer.PropertyFilter; +import com.alibaba.fastjson.serializer.SerializeConfig; +import com.alibaba.fastjson.serializer.SerializeWriter; +import com.alibaba.fastjson.serializer.SerializerFeature; + +public class FastjsonSCodec implements Codec { + + + public String getName() { + return "fastjson"; + } + + public T decodeObject(String text, Class clazz) { + ParserConfig config = new ParserConfig(); + DefaultExtJSONParser parser = new DefaultExtJSONParser(text, config); + parser.config(Feature.DisableCircularReferenceDetect, true); + return parser.parseObject(clazz); + } + + public Collection decodeArray(String text, Class clazz) throws Exception { + ParserConfig config = new ParserConfig(); + DefaultExtJSONParser parser = new DefaultExtJSONParser(text, config); + parser.config(Feature.DisableCircularReferenceDetect, true); + return parser.parseArray(clazz); + } + + public final Object decodeObject(String text) { + ParserConfig config = new ParserConfig(); + DefaultJSONParser parser = new DefaultJSONParser(text, config); + parser.config(Feature.DisableCircularReferenceDetect, true); + return parser.parse(); + } + + public final Object decode(String text) { + ParserConfig config = new ParserConfig(); + DefaultJSONParser parser = new DefaultJSONParser(text, config); + parser.config(Feature.DisableCircularReferenceDetect, true); + return parser.parse(); + } + + // private JavaBeanSerializer serializer = new JavaBeanSerializer(Long_100_Entity.class); + + public String encode(Object object) throws Exception { + SerializeConfig config = new SerializeConfig(); + SerializeWriter out = new SerializeWriter(); + out.config(SerializerFeature.DisableCircularReferenceDetect, true); +// out.config(SerializerFeature.DisableCheckSpecialChar, true); + + JSONSerializer serializer = new JSONSerializer(out, config); + serializer.write(object); + + String text = out.toString(); + + out.close(); + + return text; + } + + @SuppressWarnings("unchecked") + public T decodeObject(byte[] input, Class clazz) throws Exception { + return (T) JSON.parseObject(input, clazz, Feature.DisableCircularReferenceDetect); + } + +}