Skip to content
This repository has been archived by the owner on Oct 23, 2024. It is now read-only.

Commit

Permalink
BeanToArray support field level config
Browse files Browse the repository at this point in the history
  • Loading branch information
wenshao committed May 5, 2016
1 parent 5dc9b06 commit 708b5c5
Show file tree
Hide file tree
Showing 15 changed files with 181 additions and 70 deletions.
4 changes: 4 additions & 0 deletions src/main/java/com/alibaba/fastjson/parser/JSONLexerBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,10 @@ public final boolean isEnabled(Feature feature) {
public final boolean isEnabled(int feature) {
return (this.features & feature) != 0;
}

public final boolean isEnabled(int features, int feature) {
return (this.features & feature) != 0 || (features & feature) != 0;
}

public abstract String numberString();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,25 +72,11 @@ public ObjectDeserializer createJavaBeanDeserializer(ParserConfig config, Class<

_init(cw, new Context(classNameType, config, beanInfo, 3));
_createInstance(cw, new Context(classNameType, config, beanInfo, 3));
_deserialze(cw, new Context(classNameType, config, beanInfo, 4));
_deserialze(cw, new Context(classNameType, config, beanInfo, 5));

_deserialzeArrayMapping(cw, new Context(classNameType, config, beanInfo, 4));
byte[] code = cw.toByteArray();

// if (JSON.DUMP_CLASS != null) {
// FileOutputStream fos = null;
// try {
// fos = new FileOutputStream(JSON.DUMP_CLASS + File.separator + className + ".class");
// fos.write(code);
// } catch (Exception ex) {
// System.err.println("FASTJSON dump class:" + className + "失败:" + ex.getMessage());
// } finally {
// if (fos != null) {
// fos.close();
// }
// }
// }

Class<?> exampleClass = defineClassPublic(classNameFull, code, 0, code.length);

Constructor<?> constructor = exampleClass.getConstructor(ParserConfig.class, Class.class);
Expand Down Expand Up @@ -318,7 +304,7 @@ private void _deserialzeArrayMapping(ClassWriter cw, Context context) {
mw.visitLdcInsn(com.alibaba.fastjson.parser.JSONToken.LBRACKET);
mw.visitMethodInsn(INVOKEVIRTUAL, JSONLexerBase, "nextToken", "(I)V");

mw.visitVarInsn(ALOAD, 1); // parser
mw.visitVarInsn(ALOAD, Context.parser);
mw.visitVarInsn(ALOAD, 0);
mw.visitLdcInsn(i);
mw.visitMethodInsn(INVOKEVIRTUAL, type(JavaBeanDeserializer.class), "getFieldType",
Expand Down Expand Up @@ -462,7 +448,7 @@ private void _deserialze(ClassWriter cw, Context context) {
context.fieldInfoList = beanInfo.sortedFields;

MethodVisitor mw = new MethodWriter(cw, ACC_PUBLIC, "deserialze",
"(L" + DefaultJSONParser + ";Ljava/lang/reflect/Type;Ljava/lang/Object;)Ljava/lang/Object;",
"(L" + DefaultJSONParser + ";Ljava/lang/reflect/Type;Ljava/lang/Object;I)Ljava/lang/Object;",
null, null);

Label reset_ = new Label();
Expand All @@ -484,16 +470,17 @@ private void _deserialze(ClassWriter cw, Context context) {

if ((beanInfo.parserFeatures & Feature.SupportArrayToBean.mask) == 0) {
mw.visitVarInsn(ALOAD, context.var("lexer"));
mw.visitVarInsn(ILOAD, 4);
mw.visitLdcInsn(Feature.SupportArrayToBean.mask);
mw.visitMethodInsn(INVOKEVIRTUAL, JSONLexerBase, "isEnabled", "(I)Z");
mw.visitMethodInsn(INVOKEVIRTUAL, JSONLexerBase, "isEnabled", "(II)Z");
mw.visitJumpInsn(IFEQ, next_);
}

mw.visitVarInsn(ALOAD, 0);
mw.visitVarInsn(ALOAD, 1);
mw.visitVarInsn(ALOAD, Context.parser);
mw.visitVarInsn(ALOAD, 2);
mw.visitVarInsn(ALOAD, 3);
mw.visitVarInsn(ALOAD, 4);
mw.visitInsn(ACONST_NULL); //mw.visitVarInsn(ALOAD, 5);
mw.visitMethodInsn(INVOKESPECIAL, //
context.className, //
"deserialzeArrayMapping", //
Expand Down Expand Up @@ -790,9 +777,10 @@ private void _deserialze(ClassWriter cw, Context context) {
mw.visitVarInsn(ALOAD, 2);
mw.visitVarInsn(ALOAD, 3);
mw.visitVarInsn(ALOAD, context.var("instance"));
mw.visitVarInsn(ILOAD, 4);
mw.visitMethodInsn(INVOKEVIRTUAL, type(JavaBeanDeserializer.class),
"parseRest", "(L" + DefaultJSONParser
+ ";Ljava/lang/reflect/Type;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+ ";Ljava/lang/reflect/Type;Ljava/lang/Object;Ljava/lang/Object;I)Ljava/lang/Object;");
mw.visitTypeInsn(CHECKCAST, type(context.clazz)); // cast
mw.visitInsn(ARETURN);

Expand All @@ -801,12 +789,13 @@ private void _deserialze(ClassWriter cw, Context context) {
mw.visitVarInsn(ALOAD, 1);
mw.visitVarInsn(ALOAD, 2);
mw.visitVarInsn(ALOAD, 3);
mw.visitVarInsn(ILOAD, 4);
mw.visitMethodInsn(INVOKESPECIAL, type(JavaBeanDeserializer.class), //
"deserialze", //
"(L" + DefaultJSONParser + ";Ljava/lang/reflect/Type;Ljava/lang/Object;)Ljava/lang/Object;");
"(L" + DefaultJSONParser + ";Ljava/lang/reflect/Type;Ljava/lang/Object;I)Ljava/lang/Object;");
mw.visitInsn(ARETURN);

mw.visitMaxs(5, context.variantIndex);
mw.visitMaxs(6, context.variantIndex);
mw.visitEnd();

}
Expand Down Expand Up @@ -1343,6 +1332,34 @@ private void _deserialze_obj(Context context, MethodVisitor mw, Label reset_, Fi
private void _deserObject(Context context, MethodVisitor mw, FieldInfo fieldInfo, Class<?> fieldClass, int i) {
_getFieldDeser(context, mw, fieldInfo);

Label instanceOfElse_ = new Label(), instanceOfEnd_ = new Label();
if ((fieldInfo.parserFeatures & Feature.SupportArrayToBean.mask) != 0) {
mw.visitInsn(DUP);
mw.visitTypeInsn(INSTANCEOF, type(JavaBeanDeserializer.class));
mw.visitJumpInsn(IFEQ, instanceOfElse_);

mw.visitTypeInsn(CHECKCAST, type(JavaBeanDeserializer.class)); // cast
mw.visitVarInsn(ALOAD, 1);
if (fieldInfo.fieldType instanceof Class) {
mw.visitLdcInsn(com.alibaba.fastjson.asm.Type.getType(desc(fieldInfo.fieldClass)));
} else {
mw.visitVarInsn(ALOAD, 0);
mw.visitLdcInsn(i);
mw.visitMethodInsn(INVOKEVIRTUAL, type(JavaBeanDeserializer.class), "getFieldType",
"(I)Ljava/lang/reflect/Type;");
}
mw.visitLdcInsn(fieldInfo.name);
mw.visitLdcInsn(fieldInfo.parserFeatures);
mw.visitMethodInsn(INVOKEVIRTUAL, type(JavaBeanDeserializer.class), "deserialze",
"(L" + DefaultJSONParser + ";Ljava/lang/reflect/Type;Ljava/lang/Object;I)Ljava/lang/Object;");
mw.visitTypeInsn(CHECKCAST, type(fieldClass)); // cast
mw.visitVarInsn(ASTORE, context.var(fieldInfo.name + "_asm"));

mw.visitJumpInsn(GOTO, instanceOfEnd_);

mw.visitLabel(instanceOfElse_);
}

mw.visitVarInsn(ALOAD, 1);
if (fieldInfo.fieldType instanceof Class) {
mw.visitLdcInsn(com.alibaba.fastjson.asm.Type.getType(desc(fieldInfo.fieldClass)));
Expand All @@ -1357,6 +1374,8 @@ private void _deserObject(Context context, MethodVisitor mw, FieldInfo fieldInfo
"(L" + DefaultJSONParser + ";Ljava/lang/reflect/Type;Ljava/lang/Object;)Ljava/lang/Object;");
mw.visitTypeInsn(CHECKCAST, type(fieldClass)); // cast
mw.visitVarInsn(ASTORE, context.var(fieldInfo.name + "_asm"));

mw.visitLabel(instanceOfEnd_);
}

private void _getFieldDeser(Context context, MethodVisitor mw, FieldInfo fieldInfo) {
Expand All @@ -1383,7 +1402,11 @@ private void _getFieldDeser(Context context, MethodVisitor mw, FieldInfo fieldIn

static class Context {

private int variantIndex = 5;
static final int parser = 1;
static final int type = 2;
static final int fieldName = 3;

private int variantIndex = -1;
private final Map<String, Integer> variants = new HashMap<String, Integer>();

private final Class<?> clazz;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,13 @@ public Object createInstance(DefaultJSONParser parser, Type type) {

return object;
}

public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
return deserialze(parser, type, fieldName, null);
return deserialze(parser, type, fieldName, 0);
}

public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName, int features) {
return deserialze(parser, type, fieldName, null, features);
}

@SuppressWarnings({ "unchecked" })
Expand Down Expand Up @@ -206,7 +210,11 @@ protected Enum<?> scanEnum(JSONLexer lexer, char seperator) {
}

@SuppressWarnings({ "unchecked", "rawtypes" })
protected <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName, Object object) {
protected <T> T deserialze(DefaultJSONParser parser, //
Type type, //
Object fieldName, //
Object object, //
int features) {
if (type == JSON.class || type == JSONObject.class) {
return (T) parser.parse();
}
Expand Down Expand Up @@ -237,8 +245,11 @@ protected <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName
}

if (token == JSONToken.LBRACKET) {
boolean isSupportArrayToBean = (beanInfo.parserFeatures & Feature.SupportArrayToBean.mask) != 0
|| lexer.isEnabled(Feature.SupportArrayToBean);
final int mask = Feature.SupportArrayToBean.mask;
boolean isSupportArrayToBean = (beanInfo.parserFeatures & mask) != 0 //
|| lexer.isEnabled(Feature.SupportArrayToBean) //
|| (features & mask) != 0
;
if (isSupportArrayToBean) {
return deserialzeArrayMapping(parser, type, fieldName, object);
}
Expand Down Expand Up @@ -707,8 +718,8 @@ public Type getFieldType(int ordinal) {
return sortedFieldDeserializers[ordinal].fieldInfo.fieldType;
}

protected Object parseRest(DefaultJSONParser parser, Type type, Object fieldName, Object instance) {
Object value = deserialze(parser, type, fieldName, instance);
protected Object parseRest(DefaultJSONParser parser, Type type, Object fieldName, Object instance, int features) {
Object value = deserialze(parser, type, fieldName, instance, features);

return value;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1571,9 +1571,13 @@ private void _writeObject(MethodVisitor mw, FieldInfo fieldInfo, Context context
mw.visitTypeInsn(INSTANCEOF, JavaBeanSerializer);
mw.visitJumpInsn(IFEQ, instanceOfElse_);

String writeMethodName = context.nonContext && context.writeDirect ? //
"writeDirectNonContext" //
: "write";
boolean fieldBeanToArray = (fieldInfo.serialzeFeatures & SerializerFeature.BeanToArray.mask) != 0;
String writeMethodName;
if (context.nonContext && context.writeDirect) {
writeMethodName = fieldBeanToArray ? "writeAsArrayNonContext" : "writeDirectNonContext";
} else {
writeMethodName = fieldBeanToArray ? "writeAsArray" : "write";
}

mw.visitVarInsn(ALOAD, context.var("fied_ser"));
mw.visitTypeInsn(CHECKCAST, JavaBeanSerializer); // cast
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,13 +175,16 @@ public void writeValue(JSONSerializer serializer, Object propertyValue) throws E
}

Class<?> valueClass = propertyValue.getClass();
ObjectSerializer valueSerializer;
if (valueClass == runtimeInfo.runtimeFieldClass) {
runtimeInfo.fieldSerializer.write(serializer, propertyValue, fieldInfo.name, fieldInfo.fieldType, fieldFeatures);
return;
valueSerializer = runtimeInfo.fieldSerializer;
} else {
valueSerializer = serializer.getObjectWriter(valueClass);
}

ObjectSerializer valueSerializer = serializer.getObjectWriter(valueClass);

valueSerializer.write(serializer, propertyValue, fieldInfo.name, fieldInfo.fieldType, fieldFeatures);


}

static class RuntimeSerializerInfo {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,14 @@ public void writeDirectNonContext(JSONSerializer serializer, //
write(serializer, object, fieldName, fieldType, features);
}

public void writeAsArray(JSONSerializer serializer, //
Object object, //
Object fieldName, //
Type fieldType, //
int features) throws IOException {
write(serializer, object, fieldName, fieldType, features);
}

public void writeAsArrayNonContext(JSONSerializer serializer, //
Object object, //
Object fieldName, //
Expand Down Expand Up @@ -121,7 +129,7 @@ public void write(JSONSerializer serializer, //
SerialContext parent = serializer.context;
serializer.setContext(parent, object, fieldName, this.beanInfo.features, features);

final boolean writeAsArray = isWriteAsArray(serializer);
final boolean writeAsArray = isWriteAsArray(serializer, features);

try {
final char startSeperator = writeAsArray ? '[' : '{';
Expand Down Expand Up @@ -342,9 +350,16 @@ public boolean writeReference(JSONSerializer serializer, Object object, int fiel
return false;
}
}

protected boolean isWriteAsArray(JSONSerializer serializer) {
return (beanInfo.features & SerializerFeature.BeanToArray.mask) != 0 || serializer.out.beanToArray;
return isWriteAsArray(serializer, 0);
}

protected boolean isWriteAsArray(JSONSerializer serializer, int fieldFeatrues) {
final int mask = SerializerFeature.BeanToArray.mask;
return (beanInfo.features & mask) != 0 //
|| serializer.out.beanToArray //
|| (fieldFeatrues & mask) != 0;
}

public Object getFieldValue(Object object, String key) {
Expand Down
7 changes: 6 additions & 1 deletion src/main/java/com/alibaba/fastjson/util/FieldInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class FieldInfo implements Comparable<FieldInfo> {
public final Class<?> declaringClass;
public final boolean getOnly;
public final int serialzeFeatures;
public final int parserFeatures;
public final String label;

private final JSONField fieldAnnotation;
Expand All @@ -45,7 +46,8 @@ public FieldInfo(String name, //
Type fieldType, //
Field field, //
int ordinal, //
int serialzeFeatures){
int serialzeFeatures, //
int parserFeatures){
this.name = name;
this.declaringClass = declaringClass;
this.fieldClass = fieldClass;
Expand All @@ -54,6 +56,7 @@ public FieldInfo(String name, //
this.field = field;
this.ordinal = ordinal;
this.serialzeFeatures = serialzeFeatures;
this.parserFeatures = 0;

isEnum = fieldClass.isEnum();

Expand Down Expand Up @@ -85,6 +88,7 @@ public FieldInfo(String name, //
Type type, //
int ordinal, //
int serialzeFeatures, //
int parserFeatures, //
JSONField fieldAnnotation, //
JSONField methodAnnotation, //
String label){
Expand All @@ -100,6 +104,7 @@ public FieldInfo(String name, //
this.field = field;
this.ordinal = ordinal;
this.serialzeFeatures = serialzeFeatures;
this.parserFeatures = parserFeatures;
this.fieldAnnotation = fieldAnnotation;
this.methodAnnotation = methodAnnotation;

Expand Down
Loading

0 comments on commit 708b5c5

Please sign in to comment.