diff --git a/src/main/java/com/alibaba/fastjson/asm/TypeCollector.java b/src/main/java/com/alibaba/fastjson/asm/TypeCollector.java index 16d38417e2..f5b2ab612b 100644 --- a/src/main/java/com/alibaba/fastjson/asm/TypeCollector.java +++ b/src/main/java/com/alibaba/fastjson/asm/TypeCollector.java @@ -6,10 +6,12 @@ import java.util.HashMap; import java.util.Map; -public class TypeCollector { - private static String JSONType = ASMUtils.desc(com.alibaba.fastjson.annotation.JSONType.class); - private static final Map primitives = new HashMap() { + +public abstract class BaseCollector { + protected static final String JSON_TYPE = ASMUtils.desc(com.alibaba.fastjson.annotation.JSONType.class); + + protected static final Map PRIMITIVES = new HashMap() { { put("int","I"); put("boolean","Z"); @@ -22,59 +24,29 @@ public class TypeCollector { } }; - private final String methodName; + protected final String methodName; - private final Class[] parameterTypes; + protected final Class[] parameterTypes; protected MethodCollector collector; protected boolean jsonType; - public TypeCollector(String methodName, Class[] parameterTypes) { + protected BaseCollector(String methodName, Class[] parameterTypes) { this.methodName = methodName; this.parameterTypes = parameterTypes; this.collector = null; } - protected MethodCollector visitMethod(int access, String name, String desc) { - if (collector != null) { - return null; - } - - if (!name.equals(methodName)) { - return null; - } - - Type[] argTypes = Type.getArgumentTypes(desc); - int longOrDoubleQuantity = 0; - for (Type t : argTypes) { - String className = t.getClassName(); - if (className.equals("long") || className.equals("double")) { - longOrDoubleQuantity++; - } - } - - if (argTypes.length != this.parameterTypes.length) { - return null; - } - for (int i = 0; i < argTypes.length; i++) { - if (!correctTypeName(argTypes[i], this.parameterTypes[i].getName())) { - return null; - } - } - - return collector = new MethodCollector( - Modifier.isStatic(access) ? 0 : 1, - argTypes.length + longOrDoubleQuantity); - } + protected abstract MethodCollector visitMethod(int access, String name, String desc); public void visitAnnotation(String desc) { - if (JSONType.equals(desc)) { + if (JSON_TYPE.equals(desc)) { jsonType = true; } } - private boolean correctTypeName(Type type, String paramTypeName) { + protected boolean correctTypeName(Type type, String paramTypeName) { String s = type.getClassName(); // array notation needs cleanup. StringBuilder braces = new StringBuilder(); @@ -83,8 +55,8 @@ private boolean correctTypeName(Type type, String paramTypeName) { s = s.substring(0, s.length() - 2); } if (braces.length() != 0) { - if (primitives.containsKey(s)) { - s = braces.append(primitives.get(s)).toString(); + if (PRIMITIVES.containsKey(s)) { + s = braces.append(PRIMITIVES.get(s)).toString(); } else { s = braces.append('L').append(s).append(';').toString(); } @@ -106,4 +78,4 @@ public boolean matched() { public boolean hasJsonType() { return jsonType; } -} \ No newline at end of file +} diff --git a/src/main/java/com/alibaba/fastjson/parser/SymbolTable.java b/src/main/java/com/alibaba/fastjson/parser/SymbolTable.java index 1346a4feb4..01ded4a01c 100644 --- a/src/main/java/com/alibaba/fastjson/parser/SymbolTable.java +++ b/src/main/java/com/alibaba/fastjson/parser/SymbolTable.java @@ -24,19 +24,19 @@ public class SymbolTable { private final String[] symbols; private final int indexMask; - + public SymbolTable(int tableSize){ this.indexMask = tableSize - 1; this.symbols = new String[tableSize]; - + this.addSymbol("$ref", 0, 4, "$ref".hashCode()); this.addSymbol(JSON.DEFAULT_TYPE_KEY, 0, JSON.DEFAULT_TYPE_KEY.length(), JSON.DEFAULT_TYPE_KEY.hashCode()); } - public String addSymbol(char[] buffer, int offset, int len) { + public String addSymbol(char[] buffer, int offset, int length) { // search for identical symbol - int hash = hash(buffer, offset, len); - return addSymbol(buffer, offset, len, hash); + int hash = hash(buffer, offset, length); + return addSymbol(buffer, offset, length, hash); } /** @@ -46,54 +46,54 @@ public String addSymbol(char[] buffer, int offset, int len) { * * @param buffer The buffer containing the new symbol. * @param offset The offset into the buffer of the new symbol. - * @param len The length of the new symbol in the buffer. + * @param length The length of the new symbol in the buffer. */ - public String addSymbol(char[] buffer, int offset, int len, int hash) { + public String addSymbol(char[] buffer, int offset, int length, int hash) { final int bucket = hash & indexMask; - + String symbol = symbols[bucket]; - if (symbol != null) { - boolean eq = true; - if (hash == symbol.hashCode() // - && len == symbol.length()) { - for (int i = 0; i < len; i++) { - if (buffer[offset + i] != symbol.charAt(i)) { - eq = false; - break; - } - } - } else { - eq = false; - } - - if (eq) { - return symbol; - } else { - return new String(buffer, offset, len); - } + if (symbol != null && areSymbolsEqual(buffer, offset, length, hash, symbol)) { + return symbol; + } else if (symbol != null) { + return createNewSymbol(buffer, offset, length); } - - symbol = new String(buffer, offset, len).intern(); + + symbol = createNewSymbol(buffer, offset, length).intern(); symbols[bucket] = symbol; return symbol; } - public String addSymbol(String buffer, int offset, int len, int hash) { - return addSymbol(buffer, offset, len, hash, false); + + private boolean areSymbolsEqual(char[] buffer, int offset, int length, int hash, String symbol) { + if (hash == symbol.hashCode() && length == symbol.length()) { + for (int i = 0; i < length; i++) { + if (buffer[offset + i] != symbol.charAt(i)) { + return false; + } + } + return true; + } + return false; + } + + private String createNewSymbol(char[] buffer, int offset, int length) { + return new String(buffer, offset, length); } - public String addSymbol(String buffer, int offset, int len, int hash, boolean replace) { + public String addSymbol(String buffer, int offset, int length, int hash) { + return addSymbol(buffer, offset, length, hash, false); + } + + public String addSymbol(String buffer, int offset, int length, int hash, boolean replace) { final int bucket = hash & indexMask; String symbol = symbols[bucket]; if (symbol != null) { - if (hash == symbol.hashCode() // - && len == symbol.length() // - && buffer.startsWith(symbol, offset)) { + if (areSymbolsEqual(buffer.toCharArray(), offset, length, hash, symbol)) { return symbol; } - String str = subString(buffer, offset, len); + String str = subString(buffer, offset, length); if (replace) { symbols[bucket] = str; @@ -101,26 +101,24 @@ public String addSymbol(String buffer, int offset, int len, int hash, boolean re return str; } - - symbol = len == buffer.length() // - ? buffer // - : subString(buffer, offset, len); + + symbol = length == buffer.length() ? buffer : subString(buffer, offset, length); symbol = symbol.intern(); symbols[bucket] = symbol; return symbol; } - - private static String subString(String src, int offset, int len) { - char[] chars = new char[len]; - src.getChars(offset, offset + len, chars, 0); + + private static String subString(String src, int offset, int length) { + char[] chars = new char[length]; + src.getChars(offset, offset + length, chars, 0); return new String(chars); } - public static int hash(char[] buffer, int offset, int len) { + public static int hash(char[] buffer, int offset, int length) { int h = 0; int off = offset; - for (int i = 0; i < len; i++) { + for (int i = 0; i < length; i++) { h = 31 * h + buffer[off++]; } return h; diff --git a/src/main/java/com/alibaba/fastjson/serializer/ArraySerializer.java b/src/main/java/com/alibaba/fastjson/serializer/ArraySerializer.java index dedad4d4d1..6d4efde0c2 100644 --- a/src/main/java/com/alibaba/fastjson/serializer/ArraySerializer.java +++ b/src/main/java/com/alibaba/fastjson/serializer/ArraySerializer.java @@ -18,21 +18,16 @@ import java.io.IOException; import java.lang.reflect.Type; -/** - * @author wenshao[szujobs@hotmail.com] - */ public class ArraySerializer implements ObjectSerializer { - private final Class componentType; - private final ObjectSerializer compObjectSerializer; + private final ArrayItemSerializer[] itemSerializers; - public ArraySerializer(Class componentType, ObjectSerializer compObjectSerializer){ - this.componentType = componentType; - this.compObjectSerializer = compObjectSerializer; + public ArraySerializer(ArrayItemSerializer[] itemSerializers){ + this.itemSerializers = itemSerializers; } public final void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) - throws IOException { + throws IOException { SerializeWriter out = serializer.out; if (object == null) { @@ -49,9 +44,9 @@ public final void write(JSONSerializer serializer, Object object, Object fieldNa try { out.append('['); for (int i = 0; i < size; ++i) { - if (i != 0) { - out.append(','); - } + if (i != 0) { + out.append(','); + } Object item = array[i]; if (item == null) { @@ -60,11 +55,9 @@ public final void write(JSONSerializer serializer, Object object, Object fieldNa } else { out.append("null"); } - } else if (item.getClass() == componentType) { - compObjectSerializer.write(serializer, item, i, null, 0); } else { - ObjectSerializer itemSerializer = serializer.getObjectWriter(item.getClass()); - itemSerializer.write(serializer, item, i, null, 0); + ArrayItemSerializer itemSerializer = getItemSerializer(item); + itemSerializer.serialize(serializer, item, i, null, 0); } } out.append(']'); @@ -72,4 +65,13 @@ public final void write(JSONSerializer serializer, Object object, Object fieldNa serializer.context = context; } } + + private ArrayItemSerializer getItemSerializer(Object item) { + for (ArrayItemSerializer serializer : itemSerializers) { + if (serializer.canSerialize(item)) { + return serializer; + } + } + throw new IllegalArgumentException("No serializer found for item: " + item); + } } diff --git a/src/main/java/com/alibaba/fastjson/serializer/SerialContext.java b/src/main/java/com/alibaba/fastjson/serializer/SerialContext.java index a65a9fe88a..df17cb7fd4 100644 --- a/src/main/java/com/alibaba/fastjson/serializer/SerialContext.java +++ b/src/main/java/com/alibaba/fastjson/serializer/SerialContext.java @@ -1,100 +1,37 @@ package com.alibaba.fastjson.serializer; public class SerialContext { - - public final SerialContext parent; - public final Object object; - public final Object fieldName; - public final int features; + private final SerialContextHierarchy hierarchy; + private final SerialContextToStringGenerator stringGenerator; public SerialContext(SerialContext parent, Object object, Object fieldName, int features, int fieldFeatures){ - this.parent = parent; - this.object = object; - this.fieldName = fieldName; - this.features = features; + this.hierarchy = new SerialContextHierarchy(parent, object, fieldName, features); + this.stringGenerator = new SerialContextToStringGenerator(parent, object, fieldName); } public String toString() { - if (parent == null) { - return "$"; - } else { - StringBuilder buf = new StringBuilder(); - toString(buf); - return buf.toString(); - } - } - - protected void toString(StringBuilder buf) { - if (parent == null) { - buf.append('$'); - } else { - parent.toString(buf); - if (fieldName == null) { - buf.append(".null"); - } else if (fieldName instanceof Integer) { - buf.append('['); - buf.append(((Integer)fieldName).intValue()); - buf.append(']'); - } else { - buf.append('.'); - - String fieldName = this.fieldName.toString(); - boolean special = false; - for (int i = 0; i < fieldName.length(); ++i) { - char ch = fieldName.charAt(i); - if ((ch >= '0' && ch <='9') || (ch >= 'A' && ch <='Z') || (ch >= 'a' && ch <='z') || ch > 128) { - continue; - } - special = true; - break; - } - - if (special) { - for (int i = 0; i < fieldName.length(); ++i) { - char ch = fieldName.charAt(i); - if (ch == '\\') { - buf.append('\\'); - buf.append('\\'); - buf.append('\\'); - } else if ((ch >= '0' && ch <='9') || (ch >= 'A' && ch <='Z') || (ch >= 'a' && ch <='z') || ch > 128) { - buf.append(ch); - continue; - } else if(ch == '\"'){ - buf.append('\\'); - buf.append('\\'); - buf.append('\\'); - } else { - buf.append('\\'); - buf.append('\\'); - } - buf.append(ch); - } - } else { - buf.append(fieldName); - } - } - } + return stringGenerator.toString(); } /** * @deprecated */ public SerialContext getParent() { - return parent; + return hierarchy.getParent(); } /** * @deprecated */ public Object getObject() { - return object; + return hierarchy.getObject(); } /** * @deprecated */ public Object getFieldName() { - return fieldName; + return hierarchy.getFieldName(); } /**