/*
* Copyright 1999-2101 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.fastjson.parser;
import static com.alibaba.fastjson.parser.JSONLexer.EOI;
import static com.alibaba.fastjson.parser.JSONToken.EOF;
import static com.alibaba.fastjson.parser.JSONToken.ERROR;
import static com.alibaba.fastjson.parser.JSONToken.FALSE;
import static com.alibaba.fastjson.parser.JSONToken.LBRACE;
import static com.alibaba.fastjson.parser.JSONToken.LBRACKET;
import static com.alibaba.fastjson.parser.JSONToken.LITERAL_FLOAT;
import static com.alibaba.fastjson.parser.JSONToken.LITERAL_INT;
import static com.alibaba.fastjson.parser.JSONToken.LITERAL_STRING;
import static com.alibaba.fastjson.parser.JSONToken.NEW;
import static com.alibaba.fastjson.parser.JSONToken.NULL;
import static com.alibaba.fastjson.parser.JSONToken.RBRACKET;
import static com.alibaba.fastjson.parser.JSONToken.SET;
import static com.alibaba.fastjson.parser.JSONToken.TREE_SET;
import static com.alibaba.fastjson.parser.JSONToken.TRUE;
import static com.alibaba.fastjson.parser.JSONToken.UNDEFINED;
import java.io.Closeable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.deserializer.ASMJavaBeanDeserializer;
import com.alibaba.fastjson.parser.deserializer.CollectionResolveFieldDeserializer;
import com.alibaba.fastjson.parser.deserializer.ExtraProcessor;
import com.alibaba.fastjson.parser.deserializer.ExtraTypeProvider;
import com.alibaba.fastjson.parser.deserializer.FieldDeserializer;
import com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer;
import com.alibaba.fastjson.parser.deserializer.ListResolveFieldDeserializer;
import com.alibaba.fastjson.parser.deserializer.MapResolveFieldDeserializer;
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
import com.alibaba.fastjson.serializer.IntegerCodec;
import com.alibaba.fastjson.serializer.LongCodec;
import com.alibaba.fastjson.serializer.StringCodec;
import com.alibaba.fastjson.util.TypeUtils;
/**
* @author wenshao[szujobs@hotmail.com]
*/
public class DefaultJSONParser extends AbstractJSONParser implements Closeable {
protected final Object input;
protected final SymbolTable symbolTable;
protected ParserConfig config;
private final static Set<Class<?>> primitiveClasses = new HashSet<Class<?>>();
private String dateFormatPattern = JSON.DEFFAULT_DATE_FORMAT;
private DateFormat dateFormat;
protected final JSONLexer lexer;
protected ParseContext context;
private ParseContext[] contextArray = new ParseContext[8];
private int contextArrayIndex = 0;
private List<ResolveTask> resolveTaskList;
public final static int NONE = 0;
public final static int NeedToResolve = 1;
public final static int TypeNameRedirect = 2;
private int resolveStatus = NONE;
private List<ExtraTypeProvider> extraTypeProviders = null;
private List<ExtraProcessor> extraProcessors = null;
static {
primitiveClasses.add(boolean.class);
primitiveClasses.add(byte.class);
primitiveClasses.add(short.class);
primitiveClasses.add(int.class);
primitiveClasses.add(long.class);
primitiveClasses.add(float.class);
primitiveClasses.add(double.class);
primitiveClasses.add(Boolean.class);
primitiveClasses.add(Byte.class);
primitiveClasses.add(Short.class);
primitiveClasses.add(Integer.class);
primitiveClasses.add(Long.class);
primitiveClasses.add(Float.class);
primitiveClasses.add(Double.class);
primitiveClasses.add(BigInteger.class);
primitiveClasses.add(BigDecimal.class);
primitiveClasses.add(String.class);
}
public String getDateFomartPattern() {
return dateFormatPattern;
}
public DateFormat getDateFormat() {
if (dateFormat == null) {
dateFormat = new SimpleDateFormat(dateFormatPattern);
}
return dateFormat;
}
public void setDateFormat(String dateFormat) {
this.dateFormatPattern = dateFormat;
this.dateFormat = null;
}
public void setDateFomrat(DateFormat dateFormat) {
this.dateFormat = dateFormat;
}
public DefaultJSONParser(String input){
this(input, ParserConfig.getGlobalInstance(), JSON.DEFAULT_PARSER_FEATURE);
}
public DefaultJSONParser(final String input, final ParserConfig config){
this(input, new JSONScanner(input, JSON.DEFAULT_PARSER_FEATURE), config);
}
public DefaultJSONParser(final String input, final ParserConfig config, int features){
this(input, new JSONScanner(input, features), config);
}
public DefaultJSONParser(final char[] input, int length, final ParserConfig config, int features){
this(input, new JSONScanner(input, length, features), config);
}
public DefaultJSONParser(final JSONLexer lexer){
this(lexer, ParserConfig.getGlobalInstance());
}
public DefaultJSONParser(final JSONLexer lexer, final ParserConfig config){
this(null, lexer, config);
}
public DefaultJSONParser(final Object input, final JSONLexer lexer, final ParserConfig config){
this.lexer = lexer;
this.input = input;
this.config = config;
this.symbolTable = config.getSymbolTable();
lexer.nextToken(JSONToken.LBRACE); // prime the pump
}
public SymbolTable getSymbolTable() {
return symbolTable;
}
public String getInput() {
if (input instanceof char[]) {
return new String((char[]) input);
}
return input.toString();
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Object parseObject(final Map object, Object fieldName) {
final JSONLexer lexer = this.lexer;
if (lexer.token() == JSONToken.NULL) {
lexer.next();
return null;
}
if (lexer.token() != JSONToken.LBRACE && lexer.token() != JSONToken.COMMA) {
throw new JSONException("syntax error, expect {, actual " + lexer.tokenName());
}
ParseContext context = this.getContext();
try {
boolean setContextFlag = false;
for (;;) {
lexer.skipWhitespace();
char ch = lexer.getCurrent();
if (isEnabled(Feature.AllowArbitraryCommas)) {
while (ch == ',') {
lexer.next();
lexer.skipWhitespace();
ch = lexer.getCurrent();
}
}
boolean isObjectKey = false;
Object key;
if (ch == '"') {
key = lexer.scanSymbol(symbolTable, '"');
lexer.skipWhitespace();
ch = lexer.getCurrent();
if (ch != ':') {
throw new JSONException("expect ':' at " + lexer.pos() + ", name " + key);
}
} else if (ch == '}') {
lexer.next();
lexer.resetStringPosition();
lexer.nextToken();
return object;
} else if (ch == '\'') {
if (!isEnabled(Feature.AllowSingleQuotes)) {
throw new JSONException("syntax error");
}
key = lexer.scanSymbol(symbolTable, '\'');
lexer.skipWhitespace();
ch = lexer.getCurrent();
if (ch != ':') {
throw new JSONException("expect ':' at " + lexer.pos());
}
} else if (ch == EOI) {
throw new JSONException("syntax error");
} else if (ch == ',') {
throw new JSONException("syntax error");
} else if ((ch >= '0' && ch <= '9') || ch == '-') {
lexer.resetStringPosition();
lexer.scanNumber();
if (lexer.token() == JSONToken.LITERAL_INT) {
key = lexer.integerValue();
} else {
key = lexer.decimalValue(true);
}
ch = lexer.getCurrent();
if (ch != ':') {
throw new JSONException("expect ':' at " + lexer.pos() + ", name " + key);
}
} else if (ch == '{' || ch == '[') {
lexer.nextToken();
key = parse();
isObjectKey = true;
} else {
if (!isEnabled(Feature.AllowUnQuotedFieldNames)) {
throw new JSONException("syntax error");
}
key = lexer.scanSymbolUnQuoted(symbolTable);
lexer.skipWhitespace();
ch = lexer.getCurrent();
if (ch != ':') {
throw new JSONException("expect ':' at " + lexer.pos() + ", actual " + ch);
}
}
if (!isObjectKey) {
lexer.next();
lexer.skipWhitespace();
}
ch = lexer.getCurrent();
lexer.resetStringPosition();
if (key == JSON.DEFAULT_TYPE_KEY) {
String typeName = lexer.scanSymbol(symbolTable, '"');
Class<?> clazz = TypeUtils.loadClass(typeName);
if (clazz == null) {
object.put(JSON.DEFAULT_TYPE_KEY, typeName);
continue;
}
lexer.nextToken(JSONToken.COMMA);
if (lexer.token() == JSONToken.RBRACE) {
lexer.nextToken(JSONToken.COMMA);
try {
Object instance = null;
ObjectDeserializer deserializer = this.config.getDeserializer(clazz);
if (deserializer instanceof ASMJavaBeanDeserializer) {
instance = ((ASMJavaBeanDeserializer) deserializer).createInstance(this, clazz);
} else if (deserializer instanceof JavaBeanDeserializer) {
instance = ((JavaBeanDeserializer) deserializer).createInstance(this, clazz);
}
if (instance == null) {
if (clazz == Cloneable.class) {
instance = new HashMap();
} else {
instance = clazz.newInstance();
}
}
return instance;
} catch (Exception e) {
throw new JSONException("create instance error", e);
}
}
this.setResolveStatus(TypeNameRedirect);
if (this.context != null && !(fieldName instanceof Integer)) {
this.popContext();
}
ObjectDeserializer deserializer = config.getDeserializer(clazz);
return deserializer.deserialze(this, clazz, fieldName);
}
if (key == "$ref") {
lexer.nextToken(JSONToken.LITERAL_STRING);
if (lexer.token() == JSONToken.LITERAL_STRING) {
String ref = lexer.stringVal();
lexer.nextToken(JSONToken.RBRACE);
Object refValue = null;
if ("@".equals(ref)) {
if (this.getContext() != null) {
ParseContext thisContext = this.getContext();
Object thisObj = thisContext.getObject();
if (thisObj instanceof Object[] || thisObj instanceof Collection<?>) {
refValue = thisObj;
} else if (thisContext.getParentContext() != null) {
refValue = thisContext.getParentContext().getObject();
}
}
} else if ("..".equals(ref)) {
ParseContext parentContext = context.getParentContext();
if (parentContext.getObject() != null) {
refValue = parentContext.getObject();
} else {
addResolveTask(new ResolveTask(parentContext, ref));
setResolveStatus(DefaultJSONParser.NeedToResolve);
}
} else if ("$".equals(ref)) {
ParseContext rootContext = context;
while (rootContext.getParentContext() != null) {
rootContext = rootContext.getParentContext();
}
if (rootContext.getObject() != null) {
refValue = rootContext.getObject();
} else {
addResolveTask(new ResolveTask(rootContext, ref));
setResolveStatus(DefaultJSONParser.NeedToResolve);
}
} else {
addResolveTask(new ResolveTask(context, ref));
setResolveStatus(DefaultJSONParser.NeedToResolve);
}
if (lexer.token() != JSONToken.RBRACE) {
throw new JSONException("syntax error");
}
lexer.nextToken(JSONToken.COMMA);
return refValue;
} else {
throw new JSONException("illegal ref, " + JSONToken.name(lexer.token()));
}
}
if (!setContextFlag) {
setContext(object, fieldName);
setContextFlag = true;
}
if (object.getClass() == JSONObject.class) {
key = (key == null) ? "null" : key.toString();
}
Object value;
if (ch == '"') {
lexer.scanString();
String strValue = lexer.stringVal();
value = strValue;
if (lexer.isEnabled(Feature.AllowISO8601DateFormat)) {
JSONScanner iso8601Lexer = new JSONScanner(strValue);
if (iso8601Lexer.scanISO8601DateIfMatch()) {
value = iso8601Lexer.getCalendar().getTime();
}
iso8601Lexer.close();
}
object.put(key, value);
} else if (ch >= '0' && ch <= '9' || ch == '-') {
lexer.scanNumber();
if (lexer.token() == JSONToken.LITERAL_INT) {
value = lexer.integerValue();
} else {
value = lexer.decimalValue(isEnabled(Feature.UseBigDecimal));
}
object.put(key, value);
} else if (ch == '[') { // 减少嵌套,兼容android
lexer.nextToken();
JSONArray list = new JSONArray();
this.parseArray(list, key);
value = list;
object.put(key, value);
if (lexer.token() == JSONToken.RBRACE) {
lexer.nextToken();
return object;
} else if (lexer.token() == JSONToken.COMMA) {
continue;
} else {
throw new JSONException("syntax error");
}
} else if (ch == '{') { // 减少嵌套,兼容android
lexer.nextToken();
final boolean parentIsArray = fieldName != null && fieldName.getClass() == Integer.class;
JSONObject input = new JSONObject();
ParseContext ctxLocal = null;
if (!parentIsArray) {
ctxLocal = setContext(context, input, key);
}
Object obj = this.parseObject(input, key);
if (ctxLocal != null && input != obj) {
ctxLocal.setObject(object);
}
checkMapResolve(object, key.toString());
if (object.getClass() == JSONObject.class) {
object.put(key.toString(), obj);
} else {
object.put(key, obj);
}
if (parentIsArray) {
setContext(context, obj, key);
}
if (lexer.token() == JSONToken.RBRACE) {
lexer.nextToken();
setContext(context);
return object;
} else if (lexer.token() == JSONToken.COMMA) {
continue;
} else {
throw new JSONException("syntax error, " + lexer.tokenName());
}
} else {
lexer.nextToken();
value = parse();
if (object.getClass() == JSONObject.class) {
key = key.toString();
}
object.put(key, value);
if (lexer.token() == JSONToken.RBRACE) {
lexer.nextToken();
return object;
} else if (lexer.token() == JSONToken.COMMA) {
continue;
} else {
throw new JSONException("syntax error, position at " + lexer.pos() + ", name " + key);
}
}
lexer.skipWhitespace();
ch = lexer.getCurrent();
if (ch == ',') {
lexer.next();
continue;
} else if (ch == '}') {
lexer.next();
lexer.resetStringPosition();
lexer.nextToken();
this.setContext(object, fieldName);
return object;
} else {
throw new JSONException("syntax error, position at " + lexer.pos() + ", name " + key);
}
}
} finally {
this.setContext(context);
}
}
public ParserConfig getConfig() {
return config;
}
public void setConfig(ParserConfig config) {
this.config = config;
}
// compatible
@SuppressWarnings("unchecked")
public <T> T parseObject(Class<T> clazz) {
return (T) parseObject((Type) clazz);
}
@SuppressWarnings("unchecked")
public <T> T parseObject(Type type) {
if (lexer.token() == JSONToken.NULL) {
lexer.nextToken();
return null;
}
if (lexer.token() == JSONToken.LITERAL_STRING) {
type = TypeUtils.unwrap(type);
if (type == byte[].class) {
byte[] bytes = lexer.bytesValue();
lexer.nextToken();
return (T) bytes;
}
if (type == char[].class) {
String strVal = lexer.stringVal();
lexer.nextToken();
return (T) strVal.toCharArray();
}
}
ObjectDeserializer derializer = config.getDeserializer(type);
try {
return (T) derializer.deserialze(this, type, null);
} catch (JSONException e) {
throw e;
} catch (Throwable e) {
throw new JSONException(e.getMessage(), e);
}
}
public <T> List<T> parseArray(Class<T> clazz) {
List<T> array = new ArrayList<T>();
parseArray(clazz, array);
return array;
}
public void parseArray(Class<?> clazz, @SuppressWarnings("rawtypes") Collection array) {
parseArray((Type) clazz, array);
}
@SuppressWarnings("rawtypes")
public void parseArray(Type type, Collection array) {
parseArray(type, array, null);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public void parseArray(Type type, Collection array, Object fieldName) {
if (lexer.token() == JSONToken.SET || lexer.token() == JSONToken.TREE_SET) {
lexer.nextToken();
}
if (lexer.token() != JSONToken.LBRACKET) {
throw new JSONException("exepct '[', but " + JSONToken.name(lexer.token()));
}
ObjectDeserializer deserializer = null;
if (int.class == type) {
deserializer = IntegerCodec.instance;
lexer.nextToken(JSONToken.LITERAL_INT);
} else if (String.class == type) {
deserializer = StringCodec.instance;
lexer.nextToken(JSONToken.LITERAL_STRING);
} else {
deserializer = config.getDeserializer(type);
lexer.nextToken(deserializer.getFastMatchToken());
}
ParseContext context = this.getContext();
this.setContext(array, fieldName);
try {
for (int i = 0;; ++i) {
if (isEnabled(Feature.AllowArbitraryCommas)) {
while (lexer.token() == JSONToken.COMMA) {
lexer.nextToken();
continue;
}
}
if (lexer.token() == JSONToken.RBRACKET) {
break;
}
if (int.class == type) {
Object val = IntegerCodec.instance.deserialze(this, null, null);
array.add(val);
} else if (String.class == type) {
String value;
if (lexer.token() == JSONToken.LITERAL_STRING) {
value = lexer.stringVal();
lexer.nextToken(JSONToken.COMMA);
} else {
Object obj = this.parse();
if (obj == null) {
value = null;
} else {
value = obj.toString();
}
}
array.add(value);
} else {
Object val;
if (lexer.token() == JSONToken.NULL) {
lexer.nextToken();
val = null;
} else {
val = deserializer.deserialze(this, type, i);
}
array.add(val);
checkListResolve(array);
}
if (lexer.token() == JSONToken.COMMA) {
lexer.nextToken(deserializer.getFastMatchToken());
continue;
}
}
} finally {
this.setContext(context);
}
lexer.nextToken(JSONToken.COMMA);
}
public Object[] parseArray(Type[] types) {
if (lexer.token() == JSONToken.NULL) {
lexer.nextToken(JSONToken.COMMA);
return null;
}
if (lexer.token() != JSONToken.LBRACKET) {
throw new JSONException("syntax error : " + lexer.tokenName());
}
Object[] list = new Object[types.length];
if (types.length == 0) {
lexer.nextToken(JSONToken.RBRACKET);
if (lexer.token() != JSONToken.RBRACKET) {
throw new JSONException("syntax error");
}
lexer.nextToken(JSONToken.COMMA);
return new Object[0];
}
lexer.nextToken(JSONToken.LITERAL_INT);
for (int i = 0; i < types.length; ++i) {
Object value;
if (lexer.token() == JSONToken.NULL) {
value = null;
lexer.nextToken(JSONToken.COMMA);
} else {
Type type = types[i];
if (type == int.class || type == Integer.class) {
if (lexer.token() == JSONToken.LITERAL_INT) {
value = Integer.valueOf(lexer.intValue());
lexer.nextToken(JSONToken.COMMA);
} else {
value = this.parse();
value = TypeUtils.cast(value, type, config);
}
} else if (type == String.class) {
if (lexer.token() == JSONToken.LITERAL_STRING) {
value = lexer.stringVal();
lexer.nextToken(JSONToken.COMMA);
} else {
value = this.parse();
value = TypeUtils.cast(value, type, config);
}
} else {
boolean isArray = false;
Class<?> componentType = null;
if (i == types.length - 1) {
if (type instanceof Class) {
Class<?> clazz = (Class<?>) type;
isArray = clazz.isArray();
componentType = clazz.getComponentType();
}
}
// support varArgs
if (isArray && lexer.token() != JSONToken.LBRACKET) {
List<Object> varList = new ArrayList<Object>();
ObjectDeserializer derializer = config.getDeserializer(componentType);
int fastMatch = derializer.getFastMatchToken();
if (lexer.token() != JSONToken.RBRACKET) {
for (;;) {
Object item = derializer.deserialze(this, type, null);
varList.add(item);
if (lexer.token() == JSONToken.COMMA) {
lexer.nextToken(fastMatch);
} else if (lexer.token() == JSONToken.RBRACKET) {
break;
} else {
throw new JSONException("syntax error :" + JSONToken.name(lexer.token()));
}
}
}
value = TypeUtils.cast(varList, type, config);
} else {
ObjectDeserializer derializer = config.getDeserializer(type);
value = derializer.deserialze(this, type, null);
}
}
}
list[i] = value;
if (lexer.token() == JSONToken.RBRACKET) {
break;
}
if (lexer.token() != JSONToken.COMMA) {
throw new JSONException("syntax error :" + JSONToken.name(lexer.token()));
}
if (i == types.length - 1) {
lexer.nextToken(JSONToken.RBRACKET);
} else {
lexer.nextToken(JSONToken.LITERAL_INT);
}
}
if (lexer.token() != JSONToken.RBRACKET) {
throw new JSONException("syntax error");
}
lexer.nextToken(JSONToken.COMMA);
return list;
}
public void parseObject(Object object) {
Class<?> clazz = object.getClass();
Map<String, FieldDeserializer> setters = config.getFieldDeserializers(clazz);
if (lexer.token() != JSONToken.LBRACE && lexer.token() != JSONToken.COMMA) {
throw new JSONException("syntax error, expect {, actual " + lexer.tokenName());
}
for (;;) {
// lexer.scanSymbol
String key = lexer.scanSymbol(symbolTable);
if (key == null) {
if (lexer.token() == JSONToken.RBRACE) {
lexer.nextToken(JSONToken.COMMA);
break;
}
if (lexer.token() == JSONToken.COMMA) {
if (isEnabled(Feature.AllowArbitraryCommas)) {
continue;
}
}
}
FieldDeserializer fieldDeser = setters.get(key);
if (fieldDeser == null && key != null) {
for (Map.Entry<String, FieldDeserializer> entry : setters.entrySet()) {
if (key.equalsIgnoreCase((entry.getKey()))) {
fieldDeser = entry.getValue();
break;
}
}
}
if (fieldDeser == null) {
if (!isEnabled(Feature.IgnoreNotMatch)) {
throw new JSONException("setter not found, class " + clazz.getName() + ", property " + key);
}
lexer.nextTokenWithColon();
parse(); // skip
if (lexer.token() == JSONToken.RBRACE) {
lexer.nextToken();
return;
}
continue;
} else {
Class<?> fieldClass = fieldDeser.getFieldClass();
Type fieldType = fieldDeser.getFieldType();
Object fieldValue;
if (fieldClass == int.class) {
lexer.nextTokenWithColon(JSONToken.LITERAL_INT);
fieldValue = IntegerCodec.instance.deserialze(this, fieldType, null);
} else if (fieldClass == String.class) {
lexer.nextTokenWithColon(JSONToken.LITERAL_STRING);
fieldValue = StringCodec.deserialze(this);
} else if (fieldClass == long.class) {
lexer.nextTokenWithColon(JSONToken.LITERAL_INT);
fieldValue = LongCodec.instance.deserialze(this, fieldType, null);
} else {
ObjectDeserializer fieldValueDeserializer = config.getDeserializer(fieldClass, fieldType);
lexer.nextTokenWithColon(fieldValueDeserializer.getFastMatchToken());
fieldValue = fieldValueDeserializer.deserialze(this, fieldType, null);
}
fieldDeser.setValue(object, fieldValue);
}
if (lexer.token() == JSONToken.COMMA) {
continue;
}
if (lexer.token() == JSONToken.RBRACE) {
lexer.nextToken(JSONToken.COMMA);
return;
}
}
}
public Object parseArrayWithType(Type collectionType) {
if (lexer.token() == JSONToken.NULL) {
lexer.nextToken();
return null;
}
Type[] actualTypes = ((ParameterizedType) collectionType).getActualTypeArguments();
if (actualTypes.length != 1) {
throw new JSONException("not support type " + collectionType);
}
Type actualTypeArgument = actualTypes[0];
if (actualTypeArgument instanceof Class) {
List<Object> array = new ArrayList<Object>();
this.parseArray((Class<?>) actualTypeArgument, array);
return array;
}
if (actualTypeArgument instanceof WildcardType) {
WildcardType wildcardType = (WildcardType) actualTypeArgument;
// assert wildcardType.getUpperBounds().length == 1;
Type upperBoundType = wildcardType.getUpperBounds()[0];
// assert upperBoundType instanceof Class;
if (Object.class.equals(upperBoundType)) {
if (wildcardType.getLowerBounds().length == 0) {
// Collection<?>
return parse();
} else {
throw new JSONException("not support type : " + collectionType);
}
}
List<Object> array = new ArrayList<Object>();
this.parseArray((Class<?>) upperBoundType, array);
return array;
// throw new JSONException("not support type : " +
// collectionType);return parse();
}
if (actualTypeArgument instanceof TypeVariable) {
TypeVariable<?> typeVariable = (TypeVariable<?>) actualTypeArgument;
Type[] bounds = typeVariable.getBounds();
if (bounds.length != 1) {
throw new JSONException("not support : " + typeVariable);
}
Type boundType = bounds[0];
if (boundType instanceof Class) {
List<Object> array = new ArrayList<Object>();
this.parseArray((Class<?>) boundType, array);
return array;
}
}
if (actualTypeArgument instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) actualTypeArgument;
List<Object> array = new ArrayList<Object>();
this.parseArray(parameterizedType, array);
return array;
}
throw new JSONException("TODO : " + collectionType);
}
public void acceptType(String typeName) {
JSONLexer lexer = this.lexer;
lexer.nextTokenWithColon();
if (lexer.token() != JSONToken.LITERAL_STRING) {
throw new JSONException("type not match error");
}
if (typeName.equals(lexer.stringVal())) {
lexer.nextToken();
if (lexer.token() == JSONToken.COMMA) {
lexer.nextToken();
}
} else {
throw new JSONException("type not match error");
}
}
public int getResolveStatus() {
return resolveStatus;
}
public void setResolveStatus(int resolveStatus) {
this.resolveStatus = resolveStatus;
}
public Object getObject(String path) {
for (int i = 0; i < contextArrayIndex; ++i) {
if (path.equals(contextArray[i].getPath())) {
return contextArray[i].getObject();
}
}
return null;
}
@SuppressWarnings("rawtypes")
public void checkListResolve(Collection array) {
if (resolveStatus == NeedToResolve) {
if (array instanceof List) {
final int index = array.size() - 1;
final List list = (List) array;
ResolveTask task = getLastResolveTask();
task.setFieldDeserializer(new ListResolveFieldDeserializer(this, list, index));
task.setOwnerContext(context);
setResolveStatus(DefaultJSONParser.NONE);
} else {
ResolveTask task = getLastResolveTask();
task.setFieldDeserializer(new CollectionResolveFieldDeserializer(this, array));
task.setOwnerContext(context);
setResolveStatus(DefaultJSONParser.NONE);
}
}
}
@SuppressWarnings("rawtypes")
public void checkMapResolve(Map object, String fieldName) {
if (resolveStatus == NeedToResolve) {
MapResolveFieldDeserializer fieldResolver = new MapResolveFieldDeserializer(object, fieldName);
ResolveTask task = getLastResolveTask();
task.setFieldDeserializer(fieldResolver);
task.setOwnerContext(context);
setResolveStatus(DefaultJSONParser.NONE);
}
}
@SuppressWarnings("rawtypes")
public Object parseObject(final Map object) {
return parseObject(object, null);
}
public JSONObject parseObject() {
JSONObject object = new JSONObject();
parseObject(object);
return object;
}
@SuppressWarnings("rawtypes")
public final void parseArray(final Collection array) {
parseArray(array, null);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public final void parseArray(final Collection array, Object fieldName) {
final JSONLexer lexer = getLexer();
if (lexer.token() == JSONToken.SET || lexer.token() == JSONToken.TREE_SET) {
lexer.nextToken();
}
if (lexer.token() != JSONToken.LBRACKET) {
throw new JSONException("syntax error, expect [, actual " + JSONToken.name(lexer.token()) + ", pos "
+ lexer.pos());
}
lexer.nextToken(JSONToken.LITERAL_STRING);
ParseContext context = this.getContext();
this.setContext(array, fieldName);
try {
for (int i = 0;; ++i) {
if (isEnabled(Feature.AllowArbitraryCommas)) {
while (lexer.token() == JSONToken.COMMA) {
lexer.nextToken();
continue;
}
}
Object value;
switch (lexer.token()) {
case LITERAL_INT:
value = lexer.integerValue();
lexer.nextToken(JSONToken.COMMA);
break;
case LITERAL_FLOAT:
if (lexer.isEnabled(Feature.UseBigDecimal)) {
value = lexer.decimalValue(true);
} else {
value = lexer.decimalValue(false);
}
lexer.nextToken(JSONToken.COMMA);
break;
case LITERAL_STRING:
String stringLiteral = lexer.stringVal();
lexer.nextToken(JSONToken.COMMA);
if (lexer.isEnabled(Feature.AllowISO8601DateFormat)) {
JSONScanner iso8601Lexer = new JSONScanner(stringLiteral);
if (iso8601Lexer.scanISO8601DateIfMatch()) {
value = iso8601Lexer.getCalendar().getTime();
} else {
value = stringLiteral;
}
iso8601Lexer.close();
} else {
value = stringLiteral;
}
break;
case TRUE:
value = Boolean.TRUE;
lexer.nextToken(JSONToken.COMMA);
break;
case FALSE:
value = Boolean.FALSE;
lexer.nextToken(JSONToken.COMMA);
break;
case LBRACE:
JSONObject object = new JSONObject();
value = parseObject(object, i);
break;
case LBRACKET:
Collection items = new JSONArray();
parseArray(items, i);
value = items;
break;
case NULL:
value = null;
lexer.nextToken(JSONToken.LITERAL_STRING);
break;
case UNDEFINED:
value = null;
lexer.nextToken(JSONToken.LITERAL_STRING);
break;
case RBRACKET:
lexer.nextToken(JSONToken.COMMA);
return;
case EOF:
throw new JSONException("unclosed jsonArray");
default:
value = parse();
break;
}
array.add(value);
checkListResolve(array);
if (lexer.token() == JSONToken.COMMA) {
lexer.nextToken(JSONToken.LITERAL_STRING);
continue;
}
}
} finally {
this.setContext(context);
}
}
public ParseContext getContext() {
return context;
}
public List<ResolveTask> getResolveTaskList() {
if (resolveTaskList == null) {
resolveTaskList = new ArrayList<ResolveTask>(2);
}
return resolveTaskList;
}
public List<ResolveTask> getResolveTaskListDirect() {
return resolveTaskList;
}
public void addResolveTask(ResolveTask task) {
if (resolveTaskList == null) {
resolveTaskList = new ArrayList<ResolveTask>(2);
}
resolveTaskList.add(task);
}
public ResolveTask getLastResolveTask() {
return resolveTaskList.get(resolveTaskList.size() - 1);
}
public List<ExtraProcessor> getExtraProcessors() {
if (extraProcessors == null) {
extraProcessors = new ArrayList<ExtraProcessor>(2);
}
return extraProcessors;
}
public List<ExtraProcessor> getExtraProcessorsDirect() {
return extraProcessors;
}
public List<ExtraTypeProvider> getExtraTypeProviders() {
if (extraTypeProviders == null) {
extraTypeProviders = new ArrayList<ExtraTypeProvider>(2);
}
return extraTypeProviders;
}
public List<ExtraTypeProvider> getExtraTypeProvidersDirect() {
return extraTypeProviders;
}
public void setContext(ParseContext context) {
if (isEnabled(Feature.DisableCircularReferenceDetect)) {
return;
}
this.context = context;
}
public void popContext() {
if (isEnabled(Feature.DisableCircularReferenceDetect)) {
return;
}
this.context = this.context.getParentContext();
contextArray[contextArrayIndex - 1] = null;
contextArrayIndex--;
}
public ParseContext setContext(Object object, Object fieldName) {
if (isEnabled(Feature.DisableCircularReferenceDetect)) {
return null;
}
return setContext(this.context, object, fieldName);
}
public ParseContext setContext(ParseContext parent, Object object, Object fieldName) {
if (isEnabled(Feature.DisableCircularReferenceDetect)) {
return null;
}
this.context = new ParseContext(parent, object, fieldName);
addContext(this.context);
return this.context;
}
private void addContext(ParseContext context) {
int i = contextArrayIndex++;
if (i >= contextArray.length) {
int newLen = (contextArray.length * 3) / 2;
ParseContext[] newArray = new ParseContext[newLen];
System.arraycopy(contextArray, 0, newArray, 0, contextArray.length);
contextArray = newArray;
}
contextArray[i] = context;
}
public Object parse() {
return parse(null);
}
public Object parseKey() {
if (lexer.token() == JSONToken.IDENTIFIER) {
String value = lexer.stringVal();
lexer.nextToken(JSONToken.COMMA);
return value;
}
return parse(null);
}
public Object parse(Object fieldName) {
final JSONLexer lexer = getLexer();
switch (lexer.token()) {
case SET:
lexer.nextToken();
HashSet<Object> set = new HashSet<Object>();
parseArray(set, fieldName);
return set;
case TREE_SET:
lexer.nextToken();
TreeSet<Object> treeSet = new TreeSet<Object>();
parseArray(treeSet, fieldName);
return treeSet;
case LBRACKET:
JSONArray array = new JSONArray();
parseArray(array, fieldName);
return array;
case LBRACE:
JSONObject object = new JSONObject();
return parseObject(object, fieldName);
case LITERAL_INT:
Number intValue = lexer.integerValue();
lexer.nextToken();
return intValue;
case LITERAL_FLOAT:
Object value = lexer.decimalValue(isEnabled(Feature.UseBigDecimal));
lexer.nextToken();
return value;
case LITERAL_STRING:
String stringLiteral = lexer.stringVal();
lexer.nextToken(JSONToken.COMMA);
if (lexer.isEnabled(Feature.AllowISO8601DateFormat)) {
JSONScanner iso8601Lexer = new JSONScanner(stringLiteral);
try {
if (iso8601Lexer.scanISO8601DateIfMatch()) {
return iso8601Lexer.getCalendar().getTime();
}
} finally {
iso8601Lexer.close();
}
}
return stringLiteral;
case NULL:
lexer.nextToken();
return null;
case UNDEFINED:
lexer.nextToken();
return null;
case TRUE:
lexer.nextToken();
return Boolean.TRUE;
case FALSE:
lexer.nextToken();
return Boolean.FALSE;
case NEW:
lexer.nextToken(JSONToken.IDENTIFIER);
if (lexer.token() != JSONToken.IDENTIFIER) {
throw new JSONException("syntax error");
}
lexer.nextToken(JSONToken.LPAREN);
accept(JSONToken.LPAREN);
long time = ((Number) lexer.integerValue()).longValue();
accept(JSONToken.LITERAL_INT);
accept(JSONToken.RPAREN);
return new Date(time);
case EOF:
if (lexer.isBlankInput()) {
return null;
}
throw new JSONException("unterminated json string, pos " + lexer.getBufferPosition());
case ERROR:
default:
throw new JSONException("syntax error, pos " + lexer.getBufferPosition());
}
}
public void config(Feature feature, boolean state) {
getLexer().config(feature, state);
}
public boolean isEnabled(Feature feature) {
return getLexer().isEnabled(feature);
}
public JSONLexer getLexer() {
return lexer;
}
public final void accept(final int token) {
final JSONLexer lexer = getLexer();
if (lexer.token() == token) {
lexer.nextToken();
} else {
throw new JSONException("syntax error, expect " + JSONToken.name(token) + ", actual "
+ JSONToken.name(lexer.token()));
}
}
public final void accept(final int token, int nextExpectToken) {
final JSONLexer lexer = getLexer();
if (lexer.token() == token) {
lexer.nextToken(nextExpectToken);
} else {
throw new JSONException("syntax error, expect " + JSONToken.name(token) + ", actual "
+ JSONToken.name(lexer.token()));
}
}
public void close() {
final JSONLexer lexer = getLexer();
try {
if (isEnabled(Feature.AutoCloseSource)) {
if (lexer.token() != JSONToken.EOF) {
throw new JSONException("not close json text, token : " + JSONToken.name(lexer.token()));
}
}
} finally {
lexer.close();
}
}
public void handleResovleTask(Object value) {
if (resolveTaskList == null) {
return;
}
int size = resolveTaskList.size();
for (int i = 0; i < size; ++i) {
ResolveTask task = resolveTaskList.get(i);
FieldDeserializer fieldDeser = task.getFieldDeserializer();
if (fieldDeser == null) {
continue;
}
Object object = null;
if (task.getOwnerContext() != null) {
object = task.getOwnerContext().getObject();
}
String ref = task.getReferenceValue();
Object refValue;
if (ref.startsWith("$")) {
refValue = getObject(ref);
} else {
refValue = task.getContext().getObject();
}
fieldDeser.setValue(object, refValue);
}
}
public static class ResolveTask {
private final ParseContext context;
private final String referenceValue;
private FieldDeserializer fieldDeserializer;
private ParseContext ownerContext;
public ResolveTask(ParseContext context, String referenceValue){
this.context = context;
this.referenceValue = referenceValue;
}
public ParseContext getContext() {
return context;
}
public String getReferenceValue() {
return referenceValue;
}
public FieldDeserializer getFieldDeserializer() {
return fieldDeserializer;
}
public void setFieldDeserializer(FieldDeserializer fieldDeserializer) {
this.fieldDeserializer = fieldDeserializer;
}
public ParseContext getOwnerContext() {
return ownerContext;
}
public void setOwnerContext(ParseContext ownerContext) {
this.ownerContext = ownerContext;
}
}
}