diff --git a/src/main/java/com/alibaba/fastjson/parser/JSONLexer.java b/src/main/java/com/alibaba/fastjson/parser/JSONLexer.java index 285f46542..0649dfdb3 100755 --- a/src/main/java/com/alibaba/fastjson/parser/JSONLexer.java +++ b/src/main/java/com/alibaba/fastjson/parser/JSONLexer.java @@ -1524,6 +1524,7 @@ public abstract class JSONLexer implements Closeable { return list; } + @SuppressWarnings("unchecked") public Collection scanStringArray(Class type, int expectNextChar) { matchStat = UNKOWN; diff --git a/src/main/java/com/alibaba/fastjson/serializer/ASMSerializerFactory.java b/src/main/java/com/alibaba/fastjson/serializer/ASMSerializerFactory.java index c0e9495ea..f90215441 100755 --- a/src/main/java/com/alibaba/fastjson/serializer/ASMSerializerFactory.java +++ b/src/main/java/com/alibaba/fastjson/serializer/ASMSerializerFactory.java @@ -246,6 +246,29 @@ public class ASMSerializerFactory implements Opcodes { mw.visitEnd(); } + // writeAsArray + { + Context context = new Context(className); + + mw = cw.visitMethod(ACC_PUBLIC, + "writeAsArray", + "(Lcom/alibaba/fastjson/serializer/JSONSerializer;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/reflect/Type;)V", + null, new String[] { "java/io/IOException" }); + + mw.visitVarInsn(ALOAD, context.serializer()); // serializer + mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONSerializer.class), "getWriter", + "()" + getDesc(SerializeWriter.class)); + mw.visitVarInsn(ASTORE, context.var("out")); + + mw.visitVarInsn(ALOAD, context.obj()); // obj + mw.visitTypeInsn(CHECKCAST, getType(clazz)); // serializer + mw.visitVarInsn(ASTORE, context.var("entity")); // obj + generateWriteAsArray(clazz, mw, sortedGetters, context); + mw.visitInsn(RETURN); + mw.visitMaxs(5, context.getVariantCount() + 1); + mw.visitEnd(); + } + byte[] code = cw.toByteArray(); // // org.apache.commons.io.IOUtils.write(code, new java.io.FileOutputStream( @@ -258,6 +281,89 @@ public class ASMSerializerFactory implements Opcodes { return (ObjectSerializer) instance; } + private void generateWriteAsArray(Class clazz, MethodVisitor mw, List getters, Context context) + throws Exception { + + mw.visitVarInsn(ALOAD, context.var("out")); + mw.visitVarInsn(BIPUSH, '['); + mw.visitMethodInsn(INVOKEVIRTUAL, getType(SerializeWriter.class), "write", "(C)V"); + + int size = getters.size(); + for (int i = 0; i < size; ++i) { + final char seperator = (i == size - 1) ? ']' : ','; + + FieldInfo property = getters.get(i); + Class propertyClass = property.getFieldClass(); + + mw.visitLdcInsn(property.getName()); + mw.visitVarInsn(ASTORE, context.fieldName()); + + if (propertyClass == byte.class) { + throw new JSONException("TODO : " + propertyClass); + } else if (propertyClass == short.class) { + throw new JSONException("TODO : " + propertyClass); + } else if (propertyClass == int.class) { + mw.visitVarInsn(ALOAD, context.var("out")); + _get(mw, context, property); + mw.visitVarInsn(BIPUSH, seperator); + mw.visitMethodInsn(INVOKEVIRTUAL, getType(SerializeWriter.class), "writeIntAndChar", "(IC)V"); + } else if (propertyClass == long.class) { + mw.visitVarInsn(ALOAD, context.var("out")); + _get(mw, context, property); + mw.visitVarInsn(BIPUSH, seperator); + mw.visitMethodInsn(INVOKEVIRTUAL, getType(SerializeWriter.class), "writeLongAndChar", "(JC)V"); + } else if (propertyClass == float.class) { + throw new JSONException("TODO : " + propertyClass); + } else if (propertyClass == double.class) { + throw new JSONException("TODO : " + propertyClass); + } else if (propertyClass == boolean.class) { + throw new JSONException("TODO : " + propertyClass); + } else if (propertyClass == char.class) { + throw new JSONException("TODO : " + propertyClass); + } else if (propertyClass == String.class) { + mw.visitVarInsn(ALOAD, context.var("out")); + _get(mw, context, property); + mw.visitVarInsn(BIPUSH, seperator); + mw.visitMethodInsn(INVOKEVIRTUAL, getType(SerializeWriter.class), "writeString", + "(Ljava/lang/String;C)V"); + } else if (propertyClass == BigDecimal.class) { + throw new JSONException("TODO : " + propertyClass); + } else if (List.class.isAssignableFrom(propertyClass)) { + throw new JSONException("TODO : " + propertyClass); + } else if (propertyClass.isEnum()) { + throw new JSONException("TODO : " + propertyClass); + } else { + String format = property.getFormat(); + + mw.visitVarInsn(ALOAD, context.serializer()); + _get(mw, context, property); + if (format != null) { + mw.visitLdcInsn(format); + mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONSerializer.class), "writeWithFormat", + "(Ljava/lang/Object;Ljava/lang/String;)V"); + } else { + mw.visitVarInsn(ALOAD, context.fieldName()); + if (property.getFieldType() instanceof Class // + && ((Class) property.getFieldType()).isPrimitive()) { + mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONSerializer.class), "writeWithFieldName", + "(Ljava/lang/Object;Ljava/lang/Object;)V"); + } else { + mw.visitVarInsn(ALOAD, 0); + mw.visitFieldInsn(GETFIELD, context.getClassName(), property.getName() + "_asm_fieldType", + "Ljava/lang/reflect/Type;"); + + mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONSerializer.class), "writeWithFieldName", + "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/reflect/Type;)V"); + } + } + + mw.visitVarInsn(ALOAD, context.var("out")); + mw.visitVarInsn(BIPUSH, seperator); + mw.visitMethodInsn(INVOKEVIRTUAL, getType(SerializeWriter.class), "write", "(C)V"); + } + } + } + private void generateWriteMethod(Class clazz, MethodVisitor mw, List getters, Context context) throws Exception { Label end = new Label(); @@ -329,6 +435,30 @@ public class ASMSerializerFactory implements Opcodes { mw.visitLabel(endRef_); } + { + Label endWriteAsArray_ = new Label(); + + mw.visitVarInsn(ALOAD, context.serializer()); + mw.visitVarInsn(ALOAD, context.obj()); + mw.visitVarInsn(ALOAD, context.paramFieldType()); + mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONSerializer.class), "isWriteAsArray", + "(Ljava/lang/Object;Ljava/lang/reflect/Type;)Z"); + mw.visitJumpInsn(IFEQ, endWriteAsArray_); + + // ///// + mw.visitVarInsn(ALOAD, 0); // this + mw.visitVarInsn(ALOAD, 1); // serializer + mw.visitVarInsn(ALOAD, 2); // obj + mw.visitVarInsn(ALOAD, 3); // fieldObj + mw.visitVarInsn(ALOAD, 4); // fieldType + mw.visitMethodInsn(INVOKEVIRTUAL, context.getClassName(), "writeAsArray", + "(Lcom/alibaba/fastjson/serializer/JSONSerializer;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/reflect/Type;)V"); + + mw.visitInsn(RETURN); + + mw.visitLabel(endWriteAsArray_); + } + { mw.visitVarInsn(ALOAD, context.serializer()); mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONSerializer.class), "getContext", @@ -386,7 +516,7 @@ public class ASMSerializerFactory implements Opcodes { } mw.visitVarInsn(ISTORE, context.var("seperator")); - + _before(mw, context); for (int i = 0; i < size; ++i) { @@ -1011,16 +1141,7 @@ public class ASMSerializerFactory implements Opcodes { } private void _writeObject(MethodVisitor mw, FieldInfo fieldInfo, Context context, Label _end) { - String format = null; - JSONField annotation = fieldInfo.getAnnotation(JSONField.class); - - if (annotation != null) { - format = annotation.format(); - - if (format.trim().length() == 0) { - format = null; - } - } + String format = fieldInfo.getFormat(); Label _not_null = new Label(); @@ -1041,7 +1162,7 @@ public class ASMSerializerFactory implements Opcodes { mw.visitMethodInsn(INVOKEVIRTUAL, getType(SerializeWriter.class), "writeFieldName", "(Ljava/lang/String;)V"); // serializer.write(obj) - mw.visitVarInsn(ALOAD, context.serializer()); // serializer + mw.visitVarInsn(ALOAD, context.serializer()); mw.visitVarInsn(ALOAD, context.processValue()); if (format != null) { mw.visitLdcInsn(format); @@ -1049,12 +1170,11 @@ public class ASMSerializerFactory implements Opcodes { "(Ljava/lang/Object;Ljava/lang/String;)V"); } else { mw.visitVarInsn(ALOAD, context.fieldName()); - if (fieldInfo.getFieldType() instanceof Class && ((Class) fieldInfo.getFieldType()).isPrimitive()) { + if (fieldInfo.getFieldType() instanceof Class // + && ((Class) fieldInfo.getFieldType()).isPrimitive()) { mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONSerializer.class), "writeWithFieldName", "(Ljava/lang/Object;Ljava/lang/Object;)V"); } else { - // fieldInfo.getName() + "_asm_fieldType" - mw.visitVarInsn(ALOAD, 0); mw.visitFieldInsn(GETFIELD, context.getClassName(), fieldInfo.getName() + "_asm_fieldType", "Ljava/lang/reflect/Type;"); @@ -1066,13 +1186,13 @@ public class ASMSerializerFactory implements Opcodes { _seperator(mw, context); } - + private void _before(MethodVisitor mw, Context context) { mw.visitVarInsn(ALOAD, context.serializer()); mw.visitVarInsn(ALOAD, context.obj()); mw.visitVarInsn(ILOAD, context.var("seperator")); mw.visitMethodInsn(INVOKESTATIC, getType(FilterUtils.class), "writeBefore", - "(Lcom/alibaba/fastjson/serializer/JSONSerializer;Ljava/lang/Object;C)C"); + "(Lcom/alibaba/fastjson/serializer/JSONSerializer;Ljava/lang/Object;C)C"); mw.visitVarInsn(ISTORE, context.var("seperator")); } diff --git a/src/main/java/com/alibaba/fastjson/serializer/JSONSerializer.java b/src/main/java/com/alibaba/fastjson/serializer/JSONSerializer.java index ac44719ab..e7c6a5f79 100755 --- a/src/main/java/com/alibaba/fastjson/serializer/JSONSerializer.java +++ b/src/main/java/com/alibaba/fastjson/serializer/JSONSerializer.java @@ -520,4 +520,15 @@ public class JSONSerializer { public void close() { this.out.close(); } + + public final boolean isWriteAsArray(Object object, Type fieldType) { + boolean writeAsArray; + if (out.isEnabled(SerializerFeature.WriteJavaBeanAsArray)) { + writeAsArray = true; + } else { + writeAsArray = false; + } + + return writeAsArray; + } } diff --git a/src/main/java/com/alibaba/fastjson/serializer/JavaBeanSerializer.java b/src/main/java/com/alibaba/fastjson/serializer/JavaBeanSerializer.java index 1fdda975f..db3eca91f 100755 --- a/src/main/java/com/alibaba/fastjson/serializer/JavaBeanSerializer.java +++ b/src/main/java/com/alibaba/fastjson/serializer/JavaBeanSerializer.java @@ -85,7 +85,7 @@ public class JavaBeanSerializer implements ObjectSerializer { protected boolean isWriteClassName(JSONSerializer serializer, Object obj, Type fieldType, Object fieldName) { return serializer.isWriteClassName(fieldType, obj); } - + public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType) throws IOException { SerializeWriter out = serializer.getWriter(); @@ -110,12 +110,7 @@ public class JavaBeanSerializer implements ObjectSerializer { SerialContext parent = serializer.getContext(); serializer.setContext(parent, object, fieldName); - boolean writeAsArray; - if (out.isEnabled(SerializerFeature.WriteJavaBeanAsArray)) { - writeAsArray = true; - } else { - writeAsArray = false; - } + final boolean writeAsArray = serializer.isWriteAsArray(object, fieldType); try { final char startSeperator = writeAsArray ? '[' : '{'; diff --git a/src/main/java/com/alibaba/fastjson/util/FieldInfo.java b/src/main/java/com/alibaba/fastjson/util/FieldInfo.java index ad91ee0af..22f7bae03 100755 --- a/src/main/java/com/alibaba/fastjson/util/FieldInfo.java +++ b/src/main/java/com/alibaba/fastjson/util/FieldInfo.java @@ -9,6 +9,8 @@ import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; +import com.alibaba.fastjson.annotation.JSONField; + public class FieldInfo implements Comparable { private final String name; @@ -214,6 +216,20 @@ public class FieldInfo implements Comparable { return annotation; } + + public String getFormat() { + String format = null; + JSONField annotation = getAnnotation(JSONField.class); + + if (annotation != null) { + format = annotation.format(); + + if (format.trim().length() == 0) { + format = null; + } + } + return format; + } public Object get(Object javaObject) throws IllegalAccessException, InvocationTargetException { if (method != null) { diff --git a/src/test/java/com/alibaba/json/bvt/writeAsArray/WriteAsArray_0.java b/src/test/java/com/alibaba/json/bvt/writeAsArray/WriteAsArray_0_private.java similarity index 94% rename from src/test/java/com/alibaba/json/bvt/writeAsArray/WriteAsArray_0.java rename to src/test/java/com/alibaba/json/bvt/writeAsArray/WriteAsArray_0_private.java index e3b81f7b5..a9cea6b27 100644 --- a/src/test/java/com/alibaba/json/bvt/writeAsArray/WriteAsArray_0.java +++ b/src/test/java/com/alibaba/json/bvt/writeAsArray/WriteAsArray_0_private.java @@ -7,7 +7,7 @@ import org.junit.Assert; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.serializer.SerializerFeature; -public class WriteAsArray_0 extends TestCase { +public class WriteAsArray_0_private extends TestCase { public void test_0 () throws Exception { VO vo = new VO(); vo.setId(123);