Commit d81a4708 by zinc

添加fastjson源码

parent d3159088
......@@ -28,12 +28,6 @@
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.19.0</version>
......
/*
* Copyright 1999-2017 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;
/**
* Beans that support customized output of JSON text shall implement this interface.
*
* @author wenshao[szujobs@hotmail.com]
*/
public interface JSONAware {
/**
* @return JSON text
*/
String toJSONString();
}
/*
* Copyright 1999-2019 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;
/**
* @author wenshao[szujobs@hotmail.com]
*/
@SuppressWarnings("serial")
public class JSONException extends RuntimeException {
public JSONException() {
super();
}
public JSONException(String message) {
super(message);
}
public JSONException(String message, Throwable cause) {
super(message, cause);
}
}
package com.alibaba.fastjson;
import com.alibaba.fastjson.serializer.JSONSerializable;
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.SerializeWriter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
public class JSONPObject implements JSONSerializable {
public static String SECURITY_PREFIX = "/**/";
private String function;
private final List<Object> parameters = new ArrayList<Object>();
public JSONPObject() {
}
public JSONPObject(String function) {
this.function = function;
}
public String getFunction() {
return function;
}
public void setFunction(String function) {
this.function = function;
}
public List<Object> getParameters() {
return parameters;
}
public void addParameter(Object parameter) {
this.parameters.add(parameter);
}
public String toJSONString() {
return toString();
}
public void write(JSONSerializer serializer, Object fieldName, Type fieldType, int features) throws IOException {
SerializeWriter writer = serializer.out;
if ((features & SerializerFeature.BrowserSecure.mask) != 0
|| (writer.isEnabled(SerializerFeature.BrowserSecure.mask)))
{
writer.write(SECURITY_PREFIX);
}
writer.write(function);
writer.write('(');
for (int i = 0; i < parameters.size(); ++i) {
if (i != 0) {
writer.write(',');
}
serializer.write(parameters.get(i));
}
writer.write(')');
}
public String toString() {
return JSON.toJSONString(this);
}
}
package com.alibaba.fastjson;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.JSONScanner;
public class JSONPatch {
public static String apply(String original, String patch) {
Object object
= apply(
JSON.parse(original, Feature.OrderedField), patch);
return JSON.toJSONString(object);
}
public static Object apply(Object object, String patch) {
Operation[] operations;
if (isObject(patch)) {
operations = new Operation[] {
JSON.parseObject(patch, Operation.class)};
} else {
operations = JSON.parseObject(patch, Operation[].class);
}
for (Operation op : operations) {
JSONPath path = JSONPath.compile(op.path);
switch (op.type) {
case add:
path.patchAdd(object, op.value, false);
break;
case replace:
path.patchAdd(object, op.value, true);
break;
case remove:
path.remove(object);
break;
case copy:
case move:
JSONPath from = JSONPath.compile(op.from);
Object fromValue = from.eval(object);
if (op.type == OperationType.move) {
boolean success = from.remove(object);
if (!success) {
throw new JSONException("json patch move error : " + op.from + " -> " + op.path);
}
}
path.set(object, fromValue);
break;
case test:
Object result = path.eval(object);
if (result == null) {
return op.value == null;
}
return result.equals(op.value);
default:
break;
}
}
return object;
}
private static boolean isObject(String patch) {
if (patch == null) {
return false;
}
for (int i = 0; i < patch.length(); ++i) {
char ch = patch.charAt(i);
if (JSONScanner.isWhitespace(ch)) {
continue;
}
return ch == '{';
}
return false;
}
@JSONType(orders = {"op", "from", "path", "value"})
public static class Operation {
@JSONField(name = "op")
public OperationType type;
public String from;
public String path;
public Object value;
}
public enum OperationType {
add, remove, replace, move, copy, test
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
package com.alibaba.fastjson;
@SuppressWarnings("serial")
public class JSONPathException extends JSONException {
public JSONPathException(String message){
super(message);
}
public JSONPathException(String message, Throwable cause){
super(message, cause);
}
}
package com.alibaba.fastjson;
import static com.alibaba.fastjson.JSONStreamContext.ArrayValue;
import static com.alibaba.fastjson.JSONStreamContext.PropertyKey;
import static com.alibaba.fastjson.JSONStreamContext.PropertyValue;
import static com.alibaba.fastjson.JSONStreamContext.StartArray;
import static com.alibaba.fastjson.JSONStreamContext.StartObject;
import java.io.Closeable;
import java.io.Reader;
import java.lang.reflect.Type;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.JSONLexer;
import com.alibaba.fastjson.parser.JSONReaderScanner;
import com.alibaba.fastjson.parser.JSONToken;
import com.alibaba.fastjson.util.TypeUtils;
public class JSONReader implements Closeable {
private final DefaultJSONParser parser;
private JSONStreamContext context;
private transient JSONStreamContext lastContext;
public JSONReader(Reader reader){
this(reader, new Feature[0]);
}
public JSONReader(Reader reader, Feature... features){
this(new JSONReaderScanner(reader));
for (Feature feature : features) {
this.config(feature, true);
}
}
public JSONReader(JSONLexer lexer){
this(new DefaultJSONParser(lexer));
}
public JSONReader(DefaultJSONParser parser){
this.parser = parser;
}
public void setTimzeZone(TimeZone timezone) {
this.parser.lexer.setTimeZone(timezone);
}
public void setLocale(Locale locale) {
this.parser.lexer.setLocale(locale);
}
public void config(Feature feature, boolean state) {
this.parser.config(feature, state);
}
public Locale getLocal() {
return this.parser.lexer.getLocale();
}
public TimeZone getTimzeZone() {
return this.parser.lexer.getTimeZone();
}
public void startObject() {
if (context == null) {
context = new JSONStreamContext(null, JSONStreamContext.StartObject);
} else {
startStructure();
if (lastContext != null
&& lastContext.parent == context) {
context = lastContext;
if (context.state != JSONStreamContext.StartObject) {
context.state = JSONStreamContext.StartObject;
}
} else {
context = new JSONStreamContext(context, JSONStreamContext.StartObject);
}
}
this.parser.accept(JSONToken.LBRACE, JSONToken.IDENTIFIER);
}
public void endObject() {
this.parser.accept(JSONToken.RBRACE);
endStructure();
}
public void startArray() {
if (context == null) {
context = new JSONStreamContext(null, StartArray);
} else {
startStructure();
context = new JSONStreamContext(context, StartArray);
}
this.parser.accept(JSONToken.LBRACKET);
}
public void endArray() {
this.parser.accept(JSONToken.RBRACKET);
endStructure();
}
private void startStructure() {
final int state = context.state;
switch (state) {
case PropertyKey:
parser.accept(JSONToken.COLON);
break;
case PropertyValue:
case ArrayValue:
parser.accept(JSONToken.COMMA);
break;
case StartArray:
case StartObject:
break;
default:
throw new JSONException("illegal state : " + context.state);
}
}
private void endStructure() {
lastContext = context;
context = context.parent;
if (context == null) {
return;
}
final int state = context.state;
int newState = -1;
switch (state) {
case PropertyKey:
newState = PropertyValue;
break;
case StartArray:
newState = ArrayValue;
break;
case PropertyValue:
case StartObject:
newState = PropertyKey;
break;
default:
break;
}
if (newState != -1) {
context.state = newState;
}
}
public boolean hasNext() {
if (context == null) {
throw new JSONException("context is null");
}
final int token = parser.lexer.token();
final int state = context.state;
switch (state) {
case StartArray:
case ArrayValue:
return token != JSONToken.RBRACKET;
case StartObject:
case PropertyValue:
return token != JSONToken.RBRACE;
default:
throw new JSONException("illegal state : " + state);
}
}
public int peek() {
return parser.lexer.token();
}
public void close() {
parser.close();
}
public Integer readInteger() {
Object object;
if (context == null) {
object = parser.parse();
} else {
readBefore();
object = parser.parse();
readAfter();
}
return TypeUtils.castToInt(object);
}
public Long readLong() {
Object object;
if (context == null) {
object = parser.parse();
} else {
readBefore();
object = parser.parse();
readAfter();
}
return TypeUtils.castToLong(object);
}
public String readString() {
Object object;
if (context == null) {
object = parser.parse();
} else {
readBefore();
JSONLexer lexer = parser.lexer;
if (context.state == JSONStreamContext.StartObject && lexer.token() == JSONToken.IDENTIFIER) {
object = lexer.stringVal();
lexer.nextToken();
} else {
object = parser.parse();
}
readAfter();
}
return TypeUtils.castToString(object);
}
public <T> T readObject(TypeReference<T> typeRef) {
return readObject(typeRef.getType());
}
public <T> T readObject(Type type) {
if (context == null) {
return parser.parseObject(type);
}
readBefore();
T object = parser.parseObject(type);
readAfter();
return object;
}
public <T> T readObject(Class<T> type) {
if (context == null) {
return parser.parseObject(type);
}
readBefore();
T object = parser.parseObject(type);
parser.handleResovleTask(object);
readAfter();
return object;
}
public void readObject(Object object) {
if (context == null) {
parser.parseObject(object);
return;
}
readBefore();
parser.parseObject(object);
readAfter();
}
public Object readObject() {
if (context == null) {
return parser.parse();
}
readBefore();
Object object;
switch (context.state) {
case StartObject:
case PropertyValue:
object = parser.parseKey();
break;
default:
object = parser.parse();
break;
}
readAfter();
return object;
}
@SuppressWarnings("rawtypes")
public Object readObject(Map object) {
if (context == null) {
return parser.parseObject(object);
}
readBefore();
Object value = parser.parseObject(object);
readAfter();
return value;
}
private void readBefore() {
int state = context.state;
// before
switch (state) {
case PropertyKey:
parser.accept(JSONToken.COLON);
break;
case PropertyValue:
parser.accept(JSONToken.COMMA, JSONToken.IDENTIFIER);
break;
case ArrayValue:
parser.accept(JSONToken.COMMA);
break;
case StartObject:
break;
case StartArray:
break;
default:
throw new JSONException("illegal state : " + state);
}
}
private void readAfter() {
int state = context.state;
int newStat = -1;
switch (state) {
case StartObject:
newStat = PropertyKey;
break;
case PropertyKey:
newStat = PropertyValue;
break;
case PropertyValue:
newStat = PropertyKey;
break;
case ArrayValue:
break;
case StartArray:
newStat = ArrayValue;
break;
default:
throw new JSONException("illegal state : " + state);
}
if (newStat != -1) {
context.state = newStat;
}
}
}
/*
* Copyright 1999-2017 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;
import java.io.IOException;
/**
* Beans that support customized output of JSON text to a writer shall implement this interface.
*
* @author wenshao[szujobs@hotmail.com]
*/
public interface JSONStreamAware {
/**
* write JSON string to out.
*/
void writeJSONString(Appendable out) throws IOException;
}
package com.alibaba.fastjson;
class JSONStreamContext {
final static int StartObject = 1001;
final static int PropertyKey = 1002;
final static int PropertyValue = 1003;
final static int StartArray = 1004;
final static int ArrayValue = 1005;
protected final JSONStreamContext parent;
protected int state;
public JSONStreamContext(JSONStreamContext parent, int state){
this.parent = parent;
this.state = state;
}
}
package com.alibaba.fastjson;
import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
import java.io.Writer;
import static com.alibaba.fastjson.JSONStreamContext.*;
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.SerializeWriter;
import com.alibaba.fastjson.serializer.SerializerFeature;
public class JSONWriter implements Closeable, Flushable {
private SerializeWriter writer;
private JSONSerializer serializer;
private JSONStreamContext context;
public JSONWriter(Writer out){
writer = new SerializeWriter(out);
serializer = new JSONSerializer(writer);
}
public void config(SerializerFeature feature, boolean state) {
this.writer.config(feature, state);
}
public void startObject() {
if (context != null) {
beginStructure();
}
context = new JSONStreamContext(context, JSONStreamContext.StartObject);
writer.write('{');
}
public void endObject() {
writer.write('}');
endStructure();
}
public void writeKey(String key) {
writeObject(key);
}
public void writeValue(Object object) {
writeObject(object);
}
public void writeObject(String object) {
beforeWrite();
serializer.write(object);
afterWrite();
}
public void writeObject(Object object) {
beforeWrite();
serializer.write(object);
afterWrite();
}
public void startArray() {
if (context != null) {
beginStructure();
}
context = new JSONStreamContext(context, StartArray);
writer.write('[');
}
private void beginStructure() {
final int state = context.state;
switch (context.state) {
case PropertyKey:
writer.write(':');
break;
case ArrayValue:
writer.write(',');
break;
case StartObject:
break;
case StartArray:
break;
default:
throw new JSONException("illegal state : " + state);
}
}
public void endArray() {
writer.write(']');
endStructure();
}
private void endStructure() {
context = context.parent;
if (context == null) {
return;
}
int newState = -1;
switch (context.state) {
case PropertyKey:
newState = PropertyValue;
break;
case StartArray:
newState = ArrayValue;
break;
case ArrayValue:
break;
case StartObject:
newState = PropertyKey;
break;
default:
break;
}
if (newState != -1) {
context.state = newState;
}
}
private void beforeWrite() {
if (context == null) {
return;
}
switch (context.state) {
case StartObject:
case StartArray:
break;
case PropertyKey:
writer.write(':');
break;
case PropertyValue:
writer.write(',');
break;
case ArrayValue:
writer.write(',');
break;
default:
break;
}
}
private void afterWrite() {
if (context == null) {
return;
}
final int state = context.state;
int newState = -1;
switch (state) {
case PropertyKey:
newState = PropertyValue;
break;
case StartObject:
case PropertyValue:
newState = PropertyKey;
break;
case StartArray:
newState = ArrayValue;
break;
case ArrayValue:
break;
default:
break;
}
if (newState != -1) {
context.state = newState;
}
}
public void flush() throws IOException {
writer.flush();
}
public void close() throws IOException {
writer.close();
}
@Deprecated
public void writeStartObject() {
startObject();
}
@Deprecated
public void writeEndObject() {
endObject();
}
@Deprecated
public void writeStartArray() {
startArray();
}
@Deprecated
public void writeEndArray() {
endArray();
}
}
package com.alibaba.fastjson;
/**
* @since 1.2.15
*/
public enum PropertyNamingStrategy {
CamelCase, // camelCase
PascalCase, // PascalCase
SnakeCase, // snake_case
KebabCase, // kebab-case
NoChange, //
NeverUseThisValueExceptDefaultValue;
public String translate(String propertyName) {
switch (this) {
case SnakeCase: {
StringBuilder buf = new StringBuilder();
for (int i = 0; i < propertyName.length(); ++i) {
char ch = propertyName.charAt(i);
if (ch >= 'A' && ch <= 'Z') {
char ch_ucase = (char) (ch + 32);
if (i > 0) {
buf.append('_');
}
buf.append(ch_ucase);
} else {
buf.append(ch);
}
}
return buf.toString();
}
case KebabCase: {
StringBuilder buf = new StringBuilder();
for (int i = 0; i < propertyName.length(); ++i) {
char ch = propertyName.charAt(i);
if (ch >= 'A' && ch <= 'Z') {
char ch_ucase = (char) (ch + 32);
if (i > 0) {
buf.append('-');
}
buf.append(ch_ucase);
} else {
buf.append(ch);
}
}
return buf.toString();
}
case PascalCase: {
char ch = propertyName.charAt(0);
if (ch >= 'a' && ch <= 'z') {
char[] chars = propertyName.toCharArray();
chars[0] -= 32;
return new String(chars);
}
return propertyName;
}
case CamelCase: {
char ch = propertyName.charAt(0);
if (ch >= 'A' && ch <= 'Z') {
char[] chars = propertyName.toCharArray();
chars[0] += 32;
return new String(chars);
}
return propertyName;
}
case NoChange:
case NeverUseThisValueExceptDefaultValue:
default:
return propertyName;
}
}
}
package com.alibaba.fastjson;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.alibaba.fastjson.util.ParameterizedTypeImpl;
import com.alibaba.fastjson.util.TypeUtils;
/**
* Represents a generic type {@code T}. Java doesn't yet provide a way to
* represent generic types, so this class does. Forces clients to create a
* subclass of this class which enables retrieval the type information even at
* runtime.
*
* <p>For example, to create a type literal for {@code List<String>}, you can
* create an empty anonymous inner class:
*
* <pre>
* TypeReference&lt;List&lt;String&gt;&gt; list = new TypeReference&lt;List&lt;String&gt;&gt;() {};
* </pre>
* This syntax cannot be used to create type literals that have wildcard
* parameters, such as {@code Class<?>} or {@code List<? extends CharSequence>}.
*/
public class TypeReference<T> {
static ConcurrentMap<Type, Type> classTypeCache
= new ConcurrentHashMap<Type, Type>(16, 0.75f, 1);
protected final Type type;
/**
* Constructs a new type literal. Derives represented class from type
* parameter.
*
* <p>Clients create an empty anonymous subclass. Doing so embeds the type
* parameter in the anonymous class's type hierarchy so we can reconstitute it
* at runtime despite erasure.
*/
protected TypeReference(){
Type superClass = getClass().getGenericSuperclass();
Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
Type cachedType = classTypeCache.get(type);
if (cachedType == null) {
classTypeCache.putIfAbsent(type, type);
cachedType = classTypeCache.get(type);
}
this.type = cachedType;
}
/**
* @since 1.2.9
* @param actualTypeArguments
*/
protected TypeReference(Type... actualTypeArguments){
Class<?> thisClass = this.getClass();
Type superClass = thisClass.getGenericSuperclass();
ParameterizedType argType = (ParameterizedType) ((ParameterizedType) superClass).getActualTypeArguments()[0];
Type rawType = argType.getRawType();
Type[] argTypes = argType.getActualTypeArguments();
int actualIndex = 0;
for (int i = 0; i < argTypes.length; ++i) {
if (argTypes[i] instanceof TypeVariable &&
actualIndex < actualTypeArguments.length) {
argTypes[i] = actualTypeArguments[actualIndex++];
}
// fix for openjdk and android env
if (argTypes[i] instanceof GenericArrayType) {
argTypes[i] = TypeUtils.checkPrimitiveArray(
(GenericArrayType) argTypes[i]);
}
// 如果有多层泛型且该泛型已经注明实现的情况下,判断该泛型下一层是否还有泛型
if(argTypes[i] instanceof ParameterizedType) {
argTypes[i] = handlerParameterizedType((ParameterizedType) argTypes[i], actualTypeArguments, actualIndex);
}
}
Type key = new ParameterizedTypeImpl(argTypes, thisClass, rawType);
Type cachedType = classTypeCache.get(key);
if (cachedType == null) {
classTypeCache.putIfAbsent(key, key);
cachedType = classTypeCache.get(key);
}
type = cachedType;
}
public static Type intern(ParameterizedTypeImpl type) {
Type cachedType = classTypeCache.get(type);
if (cachedType == null) {
classTypeCache.putIfAbsent(type, type);
cachedType = classTypeCache.get(type);
}
return cachedType;
}
private Type handlerParameterizedType(ParameterizedType type, Type[] actualTypeArguments, int actualIndex) {
Class<?> thisClass = this.getClass();
Type rawType = type.getRawType();
Type[] argTypes = type.getActualTypeArguments();
for(int i = 0; i < argTypes.length; ++i) {
if (argTypes[i] instanceof TypeVariable && actualIndex < actualTypeArguments.length) {
argTypes[i] = actualTypeArguments[actualIndex++];
}
// fix for openjdk and android env
if (argTypes[i] instanceof GenericArrayType) {
argTypes[i] = TypeUtils.checkPrimitiveArray(
(GenericArrayType) argTypes[i]);
}
// 如果有多层泛型且该泛型已经注明实现的情况下,判断该泛型下一层是否还有泛型
if(argTypes[i] instanceof ParameterizedType) {
argTypes[i] = handlerParameterizedType((ParameterizedType) argTypes[i], actualTypeArguments, actualIndex);
}
}
Type key = new ParameterizedTypeImpl(argTypes, thisClass, rawType);
return key;
}
/**
* Gets underlying {@code Type} instance.
*/
public Type getType() {
return type;
}
public final static Type LIST_STRING = new TypeReference<List<String>>() {}.getType();
}
package com.alibaba.fastjson.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.CONSTRUCTOR, ElementType.METHOD })
public @interface JSONCreator {
}
/*
* Copyright 1999-2017 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.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializerFeature;
/**
* @author wenshao[szujobs@hotmail.com]
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
public @interface JSONField {
/**
* config encode/decode ordinal
* @since 1.1.42
* @return
*/
int ordinal() default 0;
String name() default "";
String format() default "";
boolean serialize() default true;
boolean deserialize() default true;
SerializerFeature[] serialzeFeatures() default {};
Feature[] parseFeatures() default {};
String label() default "";
/**
* @since 1.2.12
*/
boolean jsonDirect() default false;
/**
* Serializer class to use for serializing associated value.
*
* @since 1.2.16
*/
Class<?> serializeUsing() default Void.class;
/**
* Deserializer class to use for deserializing associated value.
*
* @since 1.2.16
*/
Class<?> deserializeUsing() default Void.class;
/**
* @since 1.2.21
* @return the alternative names of the field when it is deserialized
*/
String[] alternateNames() default {};
/**
* @since 1.2.31
*/
boolean unwrapped() default false;
/**
* Only support Object
*
* @since 1.2.61
*/
String defaultValue() default "";
}
package com.alibaba.fastjson.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* @since 1.2.8
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface JSONPOJOBuilder {
/**
* Property to use for re-defining which zero-argument method
* is considered the actual "build-method": method called after
* all data has been bound, and the actual instance needs to
* be instantiated.
*<p>
* Default value is "build".
*/
String buildMethod() default "build";
/**
* Property used for (re)defining name prefix to use for
* auto-detecting "with-methods": methods that are similar to
* "set-methods" (in that they take an argument), but that
* may also return the new builder instance to use
* (which may be 'this', or a new modified builder instance).
* Note that in addition to this prefix, it is also possible
* to use {@link JSONField}
* annotation to indicate "with-methods".
*<p>
* Default value is "with", so that method named "withValue()"
* would be used for binding JSON property "value" (using type
* indicated by the argument; or one defined with annotations.
*/
String withPrefix() default "with";
}
package com.alibaba.fastjson.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.alibaba.fastjson.PropertyNamingStrategy;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.alibaba.fastjson.serializer.SerializerFeature;
/**
* @author wenshao[szujobs@hotmail.com]
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface JSONType {
boolean asm() default true;
String[] orders() default {};
/**
* @since 1.2.6
*/
String[] includes() default {};
String[] ignores() default {};
SerializerFeature[] serialzeFeatures() default {};
Feature[] parseFeatures() default {};
boolean alphabetic() default true;
Class<?> mappingTo() default Void.class;
Class<?> builder() default Void.class;
/**
* @since 1.2.11
*/
String typeName() default "";
/**
* @since 1.2.32
*/
String typeKey() default "";
/**
* @since 1.2.11
*/
Class<?>[] seeAlso() default{};
/**
* @since 1.2.14
*/
Class<?> serializer() default Void.class;
/**
* @since 1.2.14
*/
Class<?> deserializer() default Void.class;
boolean serializeEnumAsJavaBean() default false;
PropertyNamingStrategy naming() default PropertyNamingStrategy.NeverUseThisValueExceptDefaultValue;
/**
* @since 1.2.49
*/
Class<? extends SerializeFilter>[] serialzeFilters() default {};
/**
* @since 1.2.71
* @return
*/
Class<? extends ParserConfig.AutoTypeCheckHandler> autoTypeCheckHandler() default ParserConfig.AutoTypeCheckHandler.class;
}
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2007 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.alibaba.fastjson.asm;
/**
* A dynamically extensible vector of bytes. This class is roughly equivalent to
* a DataOutputStream on top of a ByteArrayOutputStream, but is more efficient.
*
* @author Eric Bruneton
*/
public class ByteVector {
/**
* The content of this vector.
*/
public byte[] data;
/**
* Actual number of bytes in this vector.
*/
public int length;
/**
* Constructs a new {@link ByteVector ByteVector} with a default initial size.
*/
public ByteVector() {
data = new byte[64];
}
/**
* Constructs a new {@link ByteVector ByteVector} with the given initial size.
*
* @param initialSize the initial size of the byte vector to be constructed.
*/
public ByteVector(final int initialSize) {
data = new byte[initialSize];
}
/**
* Puts a byte into this byte vector. The byte vector is automatically enlarged
* if necessary.
*
* @param b a byte.
* @return this byte vector.
*/
public ByteVector putByte(final int b) {
int length = this.length;
if (length + 1 > data.length) {
enlarge(1);
}
data[length++] = (byte) b;
this.length = length;
return this;
}
/**
* Puts two bytes into this byte vector. The byte vector is automatically
* enlarged if necessary.
*
* @param b1 a byte.
* @param b2 another byte.
* @return this byte vector.
*/
ByteVector put11(final int b1, final int b2) {
int length = this.length;
if (length + 2 > data.length) {
enlarge(2);
}
final byte[] data = this.data;
data[length++] = (byte) b1;
data[length++] = (byte) b2;
this.length = length;
return this;
}
/**
* Puts a short into this byte vector. The byte vector is automatically enlarged
* if necessary.
*
* @param s a short.
* @return this byte vector.
*/
public ByteVector putShort(final int s) {
int length = this.length;
if (length + 2 > data.length) {
enlarge(2);
}
final byte[] data = this.data;
data[length++] = (byte) (s >>> 8);
data[length++] = (byte) s;
this.length = length;
return this;
}
/**
* Puts a byte and a short into this byte vector. The byte vector is
* automatically enlarged if necessary.
*
* @param b a byte.
* @param s a short.
* @return this byte vector.
*/
public ByteVector put12(final int b, final int s) {
int length = this.length;
if (length + 3 > data.length) {
enlarge(3);
}
final byte[] data = this.data;
data[length++] = (byte) b;
data[length++] = (byte) (s >>> 8);
data[length++] = (byte) s;
this.length = length;
return this;
}
/**
* Puts an int into this byte vector. The byte vector is automatically enlarged
* if necessary.
*
* @param i an int.
* @return this byte vector.
*/
public ByteVector putInt(final int i) {
int length = this.length;
if (length + 4 > data.length) {
enlarge(4);
}
final byte[] data = this.data;
data[length++] = (byte) (i >>> 24);
data[length++] = (byte) (i >>> 16);
data[length++] = (byte) (i >>> 8);
data[length++] = (byte) i;
this.length = length;
return this;
}
/**
* Puts an UTF8 string into this byte vector. The byte vector is automatically
* enlarged if necessary.
*
* @param s a String.
* @return this byte vector.
*/
public ByteVector putUTF8(final String s) {
final int charLength = s.length();
int len = length;
if (len + 2 + charLength > data.length) {
enlarge(2 + charLength);
}
final byte[] data = this.data;
// optimistic algorithm: instead of computing the byte length and then
// serializing the string (which requires two loops), we assume the byte
// length is equal to char length (which is the most frequent case), and
// we start serializing the string right away. During the serialization,
// if we find that this assumption is wrong, we continue with the
// general method.
data[len++] = (byte) (charLength >>> 8);
data[len++] = (byte) charLength;
for (int i = 0; i < charLength; ++i) {
final char c = s.charAt(i);
if ((c >= '\001' && c <= '\177') || (c >= '\u4E00' && c <= '\u9FFF')) {
data[len++] = (byte) c;
} else {
throw new UnsupportedOperationException();
}
}
length = len;
return this;
}
/**
* Puts an array of bytes into this byte vector. The byte vector is
* automatically enlarged if necessary.
*
* @param b an array of bytes. May be <tt>null</tt> to put <tt>len</tt> null
* bytes into this byte vector.
* @param off index of the fist byte of b that must be copied.
* @param len number of bytes of b that must be copied.
* @return this byte vector.
*/
public ByteVector putByteArray(final byte[] b, final int off, final int len) {
if (length + len > data.length) {
enlarge(len);
}
if (b != null) {
System.arraycopy(b, off, data, length, len);
}
length += len;
return this;
}
/**
* Enlarge this byte vector so that it can receive n more bytes.
*
* @param size number of additional bytes that this byte vector should be able
* to receive.
*/
private void enlarge(final int size) {
final int length1 = 2 * data.length;
final int length2 = length + size;
final byte[] newData = new byte[length1 > length2 ? length1 : length2];
System.arraycopy(data, 0, newData, 0, length);
data = newData;
}
}
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2007 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.alibaba.fastjson.asm;
/**
* An FieldWriter that generates Java fields in bytecode form.
*
* @author Eric Bruneton
*/
public final class FieldWriter {
FieldWriter next;
/**
* Access flags of this field.
*/
private final int access;
/**
* The index of the constant pool item that contains the name of this method.
*/
private final int name;
/**
* The index of the constant pool item that contains the descriptor of this field.
*/
private final int desc;
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
public FieldWriter(final ClassWriter cw, final int access, final String name, final String desc){
if (cw.firstField == null) {
cw.firstField = this;
} else {
cw.lastField.next = this;
}
cw.lastField = this;
this.access = access;
this.name = cw.newUTF8(name);
this.desc = cw.newUTF8(desc);
}
// ------------------------------------------------------------------------
// Implementation of the FieldVisitor interface
// ------------------------------------------------------------------------
public void visitEnd() {
}
// ------------------------------------------------------------------------
// Utility methods
// ------------------------------------------------------------------------
/**
* Returns the size of this field.
*
* @return the size of this field.
*/
int getSize() {
return 8;
}
/**
* Puts the content of this field into the given byte vector.
*
* @param out where the content of this field must be put.
*/
void put(final ByteVector out) {
final int mask = 393216; // Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / (ClassWriter.ACC_SYNTHETIC_ATTRIBUTE / Opcodes.ACC_SYNTHETIC));
out.putShort(access & ~mask).putShort(name).putShort(desc);
int attributeCount = 0;
out.putShort(attributeCount);
}
}
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2007 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.alibaba.fastjson.asm;
/**
* A constant pool item. Constant pool items can be created with the 'newXXX' methods in the {@link ClassWriter} class.
*
* @author Eric Bruneton
*/
final class Item {
/**
* Index of this item in the constant pool.
*/
int index;
int type;
/**
* Value of this item, for an integer item.
*/
int intVal;
/**
* Value of this item, for a long item.
*/
long longVal;
/**
* First part of the value of this item, for items that do not hold a primitive value.
*/
String strVal1;
/**
* Second part of the value of this item, for items that do not hold a primitive value.
*/
String strVal2;
/**
* Third part of the value of this item, for items that do not hold a primitive value.
*/
String strVal3;
/**
* The hash code value of this constant pool item.
*/
int hashCode;
/**
* Link to another constant pool item, used for collision lists in the constant pool's hash table.
*/
Item next;
/**
* Constructs an uninitialized {@link Item}.
*/
Item(){
}
/**
* Constructs a copy of the given item.
*
* @param index index of the item to be constructed.
* @param i the item that must be copied into the item to be constructed.
*/
Item(final int index, final Item i){
this.index = index;
type = i.type;
intVal = i.intVal;
longVal = i.longVal;
strVal1 = i.strVal1;
strVal2 = i.strVal2;
strVal3 = i.strVal3;
hashCode = i.hashCode;
}
/**
* Sets this item to an item that do not hold a primitive value.
*
* @param type the type of this item.
* @param strVal1 first part of the value of this item.
* @param strVal2 second part of the value of this item.
* @param strVal3 third part of the value of this item.
*/
void set(final int type, final String strVal1, final String strVal2, final String strVal3) {
this.type = type;
this.strVal1 = strVal1;
this.strVal2 = strVal2;
this.strVal3 = strVal3;
switch (type) {
case 1 /* ClassWriter.UTF8 */:
case 8 /* ClassWriter.STR */:
case 7 /* ClassWriter.CLASS */:
case 13 /* ClassWriter.TYPE_NORMAL */:
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
return;
case 12 /* ClassWriter.NAME_TYPE */:
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode());
return;
// ClassWriter.FIELD:
// ClassWriter.METH:
// ClassWriter.IMETH:
default:
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode() * strVal3.hashCode());
}
}
/**
* Sets this item to an integer item.
*
* @param intVal the value of this item.
*/
void set(final int intVal) {
this.type = 3 /* ClassWriter.INT */;
this.intVal = intVal;
this.hashCode = 0x7FFFFFFF & (type + intVal);
}
/**
* Indicates if the given item is equal to this one. <i>This method assumes that the two items have the same
* {@link #type}</i>.
*
* @param i the item to be compared to this one. Both items must have the same {@link #type}.
* @return <tt>true</tt> if the given item if equal to this one, <tt>false</tt> otherwise.
*/
boolean isEqualTo(final Item i) {
switch (type) {
case 1 /* ClassWriter.UTF8 */:
case 8 /* ClassWriter.STR */:
case 7 /* ClassWriter.CLASS */ :
case 13 /* ClassWriter.TYPE_NORMAL */ :
return i.strVal1.equals(strVal1);
case 15 /* ClassWriter.TYPE_MERGED */ :
case 5 /* ClassWriter.LONG */ :
case 6 /* ClassWriter.DOUBLE */:
return i.longVal == longVal;
case 3 /* ClassWriter.INT */ :
case 4 /* ClassWriter.FLOAT */:
return i.intVal == intVal;
case 12 /* ClassWriter.NAME_TYPE */:
return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2);
// case ClassWriter.FIELD:
// case ClassWriter.METH:
// case ClassWriter.IMETH:
default:
return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2) && i.strVal3.equals(strVal3);
}
}
}
package com.alibaba.fastjson.asm;
/**
* Created by wenshao on 05/08/2017.
*/
public class MethodCollector {
private final int paramCount;
private final int ignoreCount;
private int currentParameter;
private final StringBuilder result;
protected boolean debugInfoPresent;
protected MethodCollector(int ignoreCount, int paramCount) {
this.ignoreCount = ignoreCount;
this.paramCount = paramCount;
this.result = new StringBuilder();
this.currentParameter = 0;
// if there are 0 parameters, there is no need for debug info
this.debugInfoPresent = paramCount == 0;
}
protected void visitLocalVariable(String name, int index) {
if (index >= ignoreCount && index < ignoreCount + paramCount) {
if (!name.equals("arg" + currentParameter)) {
debugInfoPresent = true;
}
result.append(',');
result.append(name);
currentParameter++;
}
}
protected String getResult() {
return result.length() != 0 ? result.substring(1) : "";
}
}
\ No newline at end of file
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2007 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.alibaba.fastjson.asm;
/**
*
* @author Eric Bruneton
*/
public interface MethodVisitor {
// -------------------------------------------------------------------------
// Annotations and non standard attributes
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// Normal instructions
// -------------------------------------------------------------------------
/**
* Visits a zero operand instruction.
*
* @param opcode the opcode of the instruction to be visited. This opcode is either NOP, ACONST_NULL, ICONST_M1,
* ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2,
* DCONST_0, DCONST_1, IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, FASTORE,
* DASTORE, AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP, IADD,
* LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM,
* INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D,
* L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN,
* FRETURN, DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, or MONITOREXIT.
*/
void visitInsn(int opcode);
void visitIntInsn(int opcode, int operand);
/**
* Visits a local variable instruction. A local variable instruction is an instruction that loads or stores the
* value of a local variable.
*
* @param opcode the opcode of the local variable instruction to be visited. This opcode is either ILOAD, LLOAD,
* FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
* @param var the operand of the instruction to be visited. This operand is the index of a local variable.
*/
void visitVarInsn(int opcode, int var);
/**
* Visits a type instruction. A type instruction is an instruction that takes the internal name of a class as
* parameter.
*
* @param opcode the opcode of the type instruction to be visited. This opcode is either NEW, ANEWARRAY, CHECKCAST
* or INSTANCEOF.
* @param type the operand of the instruction to be visited. This operand must be the internal name of an object or
* array class (see {@link Type#getInternalName() getInternalName}).
*/
void visitTypeInsn(int opcode, String type);
/**
* Visits a field instruction. A field instruction is an instruction that loads or stores the value of a field of an
* object.
*
* @param opcode the opcode of the type instruction to be visited. This opcode is either GETSTATIC, PUTSTATIC,
* GETFIELD or PUTFIELD.
* @param owner the internal name of the field's owner class (see {@link Type#getInternalName() getInternalName}).
* @param name the field's name.
* @param desc the field's descriptor (see {@link Type Type}).
*/
void visitFieldInsn(int opcode, String owner, String name, String desc);
void visitMethodInsn(int opcode, String owner, String name, String desc);
/**
* Visits a jump instruction. A jump instruction is an instruction that may jump to another instruction.
*
* @param opcode the opcode of the type instruction to be visited. This opcode is either IFEQ, IFNE, IFLT, IFGE,
* IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO, JSR,
* IFNULL or IFNONNULL.
* @param label the operand of the instruction to be visited. This operand is a label that designates the
* instruction to which the jump instruction may jump.
*/
void visitJumpInsn(int opcode, Label label);
/**
* Visits a label. A label designates the instruction that will be visited just after it.
*
* @param label a {@link Label Label} object.
*/
void visitLabel(Label label);
// -------------------------------------------------------------------------
// Special instructions
// -------------------------------------------------------------------------
/**
* Visits a LDC instruction.
*
* @param cst the constant to be loaded on the stack. This parameter must be a non null {@link Integer}, a
* {@link Float}, a {@link Long}, a {@link Double} a {@link String} (or a {@link Type} for <tt>.class</tt>
* constants, for classes whose version is 49.0 or more).
*/
void visitLdcInsn(Object cst);
/**
* Visits an IINC instruction.
*
* @param var index of the local variable to be incremented.
* @param increment amount to increment the local variable by.
*/
void visitIincInsn(int var, int increment);
// -------------------------------------------------------------------------
// Exceptions table entries, debug information, max stack and max locals
// -------------------------------------------------------------------------
/**
* Visits the maximum stack size and the maximum number of local variables of the method.
*
* @param maxStack maximum stack size of the method.
* @param maxLocals maximum number of local variables for the method.
*/
void visitMaxs(int maxStack, int maxLocals);
/**
* Visits the end of the method. This method, which is the last one to be called, is used to inform the visitor that
* all the annotations and attributes of the method have been visited.
*/
void visitEnd();
}
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2007 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.alibaba.fastjson.asm;
/**
* Defines the JVM opcodes, access flags and array type codes. This interface does not define all the JVM opcodes
* because some opcodes are automatically handled. For example, the xLOAD and xSTORE opcodes are automatically replaced
* by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and xSTORE_n opcodes are therefore not defined in this
* interface. Likewise for LDC, automatically replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and JSR_W.
*
* @author Eric Bruneton
* @author Eugene Kuleshov
*/
public interface Opcodes {
int T_INT = 10;
// versions
// int V1_1 = 3 << 16 | 45;
// int V1_2 = 0 << 16 | 46;
// int V1_3 = 0 << 16 | 47;
// int V1_4 = 0 << 16 | 48;
int V1_5 = 0 << 16 | 49;
// int V1_6 = 0 << 16 | 50;
// int V1_7 = 0 << 16 | 51;
// access flags
int ACC_PUBLIC = 0x0001; // class, field, method
int ACC_SUPER = 0x0020; // class
// opcodes // visit method (- = idem)
int ACONST_NULL = 1; // -
int ICONST_0 = 3; // -
int ICONST_1 = 4; // -
int LCONST_0 = 9; // -
int LCONST_1 = 10; // -
int FCONST_0 = 11; // -
int DCONST_0 = 14; // -
int BIPUSH = 16; // visitIntInsn
// int SIPUSH = 17; // -
// int LDC = 18; // visitLdcInsn
// int LDC_W = 19; // -
// int LDC2_W = 20; // -
int ILOAD = 21; // visitVarInsn
int LLOAD = 22; // -
int FLOAD = 23; // -
int DLOAD = 24; // -
int ALOAD = 25; // -
int ISTORE = 54; // visitVarInsn
int LSTORE = 55; // -
int FSTORE = 56; // -
int DSTORE = 57; // -
int ASTORE = 58; // -
int IASTORE = 79; // visitInsn
int POP = 87; // -
// int POP2 = 88; // -
int DUP = 89; // -
int IADD = 96; // -
// int ISUB = 100; // -
int IAND = 126; // -
// int LAND = 127; // -
int IOR = 128; // -
// int LOR = 129; // -
// int IXOR = 130; // -
// int LXOR = 131; // -
// int IINC = 132; // visitIincInsn
int LCMP = 148; // -
int FCMPL = 149; // -
int DCMPL = 151; // -
int IFEQ = 153; // visitJumpInsn
int IFNE = 154; // -
int IFLE = 158; // -
int IF_ICMPEQ = 159; // -
int IF_ICMPNE = 160; // -
int IF_ICMPLT = 161; // -
int IF_ICMPGE = 162; // -
int IF_ICMPGT = 163; // -
int IF_ACMPEQ = 165; // -
int IF_ACMPNE = 166; // -
int GOTO = 167; // -
int RET = 169; // visitVarInsn
int ARETURN = 176; // -
int RETURN = 177; // -
int GETSTATIC = 178; // visitFieldInsn
int GETFIELD = 180; // -
int PUTFIELD = 181; // -
int INVOKEVIRTUAL = 182; // visitMethodInsn
int INVOKESPECIAL = 183; // -
int INVOKESTATIC = 184; // -
int INVOKEINTERFACE = 185; // -
// int INVOKEDYNAMIC = 186; // -
int NEW = 187; // visitTypeInsn
int NEWARRAY = 188; // visitIntInsn
// int ANEWARRAY = 189; // visitTypeInsn
// int ARRAYLENGTH = 190; // visitInsn
// int ATHROW = 191; // -
int CHECKCAST = 192; // visitTypeInsn
int INSTANCEOF = 193;
int IFNULL = 198; // visitJumpInsn
int IFNONNULL = 199; // -
int GOTO_W = 200; // visitJumpInsn
// int JSR_W = 201; // -
}
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2007 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.alibaba.fastjson.asm;
/**
* A Java type. This class can be used to make it easier to manipulate type and method descriptors.
*
* @author Eric Bruneton
* @author Chris Nokleberg
*/
public class Type {
/**
* The <tt>void</tt> type.
*/
public static final Type VOID_TYPE = new Type(0, null, ('V' << 24) | (5 << 16) | (0 << 8) | 0, 1);
/**
* The <tt>boolean</tt> type.
*/
public static final Type BOOLEAN_TYPE = new Type(1, null, ('Z' << 24) | (0 << 16) | (5 << 8) | 1, 1);
/**
* The <tt>char</tt> type.
*/
public static final Type CHAR_TYPE = new Type(2, null, ('C' << 24) | (0 << 16) | (6 << 8) | 1, 1);
/**
* The <tt>byte</tt> type.
*/
public static final Type BYTE_TYPE = new Type(3, null, ('B' << 24) | (0 << 16) | (5 << 8) | 1, 1);
/**
* The <tt>short</tt> type.
*/
public static final Type SHORT_TYPE = new Type(4, null, ('S' << 24) | (0 << 16) | (7 << 8) | 1, 1);
/**
* The <tt>int</tt> type.
*/
public static final Type INT_TYPE = new Type(5, null, ('I' << 24) | (0 << 16) | (0 << 8) | 1, 1);
/**
* The <tt>float</tt> type.
*/
public static final Type FLOAT_TYPE = new Type(6, null, ('F' << 24) | (2 << 16) | (2 << 8) | 1, 1);
/**
* The <tt>long</tt> type.
*/
public static final Type LONG_TYPE = new Type(7, null, ('J' << 24) | (1 << 16) | (1 << 8) | 2, 1);
/**
* The <tt>double</tt> type.
*/
public static final Type DOUBLE_TYPE = new Type(8, null, ('D' << 24) | (3 << 16) | (3 << 8) | 2, 1);
// ------------------------------------------------------------------------
// Fields
// ------------------------------------------------------------------------
/**
* The sort of this Java type.
*/
protected final int sort;
/**
* A buffer containing the internal name of this Java type. This field is only used for reference types.
*/
private final char[] buf;
/**
* The offset of the internal name of this Java type in {@link #buf buf} or, for primitive types, the size,
* descriptor and getOpcode offsets for this type (byte 0 contains the size, byte 1 the descriptor, byte 2 the
* offset for IALOAD or IASTORE, byte 3 the offset for all other instructions).
*/
private final int off;
/**
* The length of the internal name of this Java type.
*/
private final int len;
// ------------------------------------------------------------------------
// Constructors
// ------------------------------------------------------------------------
private Type(final int sort, final char[] buf, final int off, final int len){
this.sort = sort;
this.buf = buf;
this.off = off;
this.len = len;
}
/**
* Returns the Java type corresponding to the given type descriptor.
*
* @param typeDescriptor a type descriptor.
* @return the Java type corresponding to the given type descriptor.
*/
public static Type getType(final String typeDescriptor) {
return getType(typeDescriptor.toCharArray(), 0);
}
public static int getArgumentsAndReturnSizes(final String desc) {
int n = 1;
int c = 1;
while (true) {
char car = desc.charAt(c++);
if (car == ')') {
car = desc.charAt(c);
return n << 2 | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
} else if (car == 'L') {
while (desc.charAt(c++) != ';') {
}
n += 1;
// } else if (car == '[') {
// while ((car = desc.charAt(c)) == '[') {
// ++c;
// }
// if (car == 'D' || car == 'J') {
// n -= 1;
// }
} else if (car == 'D' || car == 'J') {
n += 2;
} else {
n += 1;
}
}
}
/**
* Returns the Java type corresponding to the given type descriptor.
*
* @param buf a buffer containing a type descriptor.
* @param off the offset of this descriptor in the previous buffer.
* @return the Java type corresponding to the given type descriptor.
*/
private static Type getType(final char[] buf, final int off) {
int len;
switch (buf[off]) {
case 'V':
return VOID_TYPE;
case 'Z':
return BOOLEAN_TYPE;
case 'C':
return CHAR_TYPE;
case 'B':
return BYTE_TYPE;
case 'S':
return SHORT_TYPE;
case 'I':
return INT_TYPE;
case 'F':
return FLOAT_TYPE;
case 'J':
return LONG_TYPE;
case 'D':
return DOUBLE_TYPE;
case '[':
len = 1;
while (buf[off + len] == '[') {
++len;
}
if (buf[off + len] == 'L') {
++len;
while (buf[off + len] != ';') {
++len;
}
}
return new Type(9 /*ARRAY*/, buf, off, len + 1);
// case 'L':
default:
len = 1;
while (buf[off + len] != ';') {
++len;
}
return new Type(10/*OBJECT*/, buf, off + 1, len - 1);
}
}
public String getInternalName() {
return new String(buf, off, len);
}
// ------------------------------------------------------------------------
// Conversion to type descriptors
// ------------------------------------------------------------------------
/**
* Returns the descriptor corresponding to this Java type.
*
* @return the descriptor corresponding to this Java type.
*/
String getDescriptor() {
return new String(this.buf, off, len);
}
private int getDimensions() {
int i = 1;
while (buf[off + i] == '[') {
++i;
}
return i;
}
static Type[] getArgumentTypes(final String methodDescriptor) {
char[] buf = methodDescriptor.toCharArray();
int off = 1;
int size = 0;
for (;;) {
char car = buf[off++];
if (car == ')') {
break;
} else if (car == 'L') {
while (buf[off++] != ';') {
}
++size;
} else if (car != '[') {
++size;
}
}
Type[] args = new Type[size];
off = 1;
size = 0;
while (buf[off] != ')') {
args[size] = getType(buf, off);
off += args[size].len + (args[size].sort == 10 /*OBJECT*/ ? 2 : 0);
size += 1;
}
return args;
}
protected String getClassName() {
switch (sort) {
case 0: //VOID:
return "void";
case 1: //BOOLEAN:
return "boolean";
case 2: //CHAR:
return "char";
case 3: //BYTE:
return "byte";
case 4: //SHORT:
return "short";
case 5: //INT:
return "int";
case 6: //FLOAT:
return "float";
case 7: //LONG:
return "long";
case 8: //DOUBLE:
return "double";
case 9: //ARRAY:
Type elementType = getType(buf, off + getDimensions());
StringBuilder b = new StringBuilder(elementType.getClassName());
for (int i = getDimensions(); i > 0; --i) {
b.append("[]");
}
return b.toString();
// case OBJECT:
default:
return new String(buf, off, len).replace('/', '.');
}
}
}
package com.alibaba.fastjson.asm;
import com.alibaba.fastjson.util.ASMUtils;
import java.lang.reflect.Modifier;
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<String, String> primitives = new HashMap<String, String>() {
{
put("int","I");
put("boolean","Z");
put("byte", "B");
put("char","C");
put("short","S");
put("float","F");
put("long","J");
put("double","D");
}
};
private final String methodName;
private final Class<?>[] parameterTypes;
protected MethodCollector collector;
protected boolean jsonType;
public TypeCollector(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);
}
public void visitAnnotation(String desc) {
if (JSONType.equals(desc)) {
jsonType = true;
}
}
private boolean correctTypeName(Type type, String paramTypeName) {
String s = type.getClassName();
// array notation needs cleanup.
StringBuilder braces = new StringBuilder();
while (s.endsWith("[]")) {
braces.append('[');
s = s.substring(0, s.length() - 2);
}
if (braces.length() != 0) {
if (primitives.containsKey(s)) {
s = braces.append(primitives.get(s)).toString();
} else {
s = braces.append('L').append(s).append(';').toString();
}
}
return s.equals(paramTypeName);
}
public String[] getParameterNamesForMethod() {
if (collector == null || !collector.debugInfoPresent) {
return new String[0];
}
return collector.getResult().split(",");
}
public boolean matched() {
return collector != null;
}
public boolean hasJsonType() {
return jsonType;
}
}
\ No newline at end of file
/*
* Copyright 1999-2017 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;
/**
* @author wenshao[szujobs@hotmail.com]
*/
@Deprecated
public class DefaultExtJSONParser extends DefaultJSONParser {
public DefaultExtJSONParser(String input){
this(input, ParserConfig.getGlobalInstance());
}
public DefaultExtJSONParser(String input, ParserConfig mapping){
super(input, mapping);
}
public DefaultExtJSONParser(String input, ParserConfig mapping, int features){
super(input, mapping, features);
}
public DefaultExtJSONParser(char[] input, int length, ParserConfig mapping, int features){
super(input, length, mapping, features);
}
}
/*
* Copyright 1999-2017 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;
/**
* @author wenshao[szujobs@hotmail.com]
*/
public enum Feature {
/**
*
*/
AutoCloseSource,
/**
*
*/
AllowComment,
/**
*
*/
AllowUnQuotedFieldNames,
/**
*
*/
AllowSingleQuotes,
/**
*
*/
InternFieldNames,
/**
*
*/
AllowISO8601DateFormat,
/**
* {"a":1,,,"b":2}
*/
AllowArbitraryCommas,
/**
*
*/
UseBigDecimal,
/**
* @since 1.1.2
*/
IgnoreNotMatch,
/**
* @since 1.1.3
*/
SortFeidFastMatch,
/**
* @since 1.1.3
*/
DisableASM,
/**
* @since 1.1.7
*/
DisableCircularReferenceDetect,
/**
* @since 1.1.10
*/
InitStringFieldAsEmpty,
/**
* @since 1.1.35
*
*/
SupportArrayToBean,
/**
* @since 1.2.3
*
*/
OrderedField,
/**
* @since 1.2.5
*
*/
DisableSpecialKeyDetect,
/**
* @since 1.2.9
*/
UseObjectArray,
/**
* @since 1.2.22, 1.1.54.android
*/
SupportNonPublicField,
/**
* @since 1.2.29
*
* disable autotype key '@type'
*/
IgnoreAutoType,
/**
* @since 1.2.30
*
* disable field smart match, improve performance in some scenarios.
*/
DisableFieldSmartMatch,
/**
* @since 1.2.41, backport to 1.1.66.android
*/
SupportAutoType,
/**
* @since 1.2.42
*/
NonStringKeyAsString,
/**
* @since 1.2.45
*/
CustomMapDeserializer,
/**
* @since 1.2.55
*/
ErrorOnEnumNotMatch,
/**
* @since 1.2.68
*/
SafeMode,
/**
* @since 1.2.72
*/
TrimStringFieldValue,
/**
* @since 1.2.77
* use HashMap instead of JSONObject, ArrayList instead of JSONArray
*/
UseNativeJavaObject
;
Feature(){
mask = (1 << ordinal());
}
public final int mask;
public final int getMask() {
return mask;
}
public static boolean isEnabled(int features, Feature feature) {
return (features & feature.mask) != 0;
}
public static int config(int features, Feature feature, boolean state) {
if (state) {
features |= feature.mask;
} else {
features &= ~feature.mask;
}
return features;
}
public static int of(Feature[] features) {
if (features == null) {
return 0;
}
int value = 0;
for (Feature feature: features) {
value |= feature.mask;
}
return value;
}
}
/*
* Copyright 1999-2019 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 java.math.BigDecimal;
import java.util.Collection;
import java.util.Locale;
import java.util.TimeZone;
public interface JSONLexer {
char EOI = 0x1A;
int NOT_MATCH = -1;
int NOT_MATCH_NAME = -2;
int UNKNOWN = 0;
int OBJECT = 1;
int ARRAY = 2;
int VALUE = 3;
int END = 4;
int VALUE_NULL = 5;
int token();
String tokenName();
void skipWhitespace();
void nextToken();
void nextToken(int expect);
char getCurrent();
char next();
String scanSymbol(final SymbolTable symbolTable);
String scanSymbol(final SymbolTable symbolTable, final char quote);
void resetStringPosition();
void scanNumber();
int pos();
Number integerValue();
BigDecimal decimalValue();
Number decimalValue(boolean decimal);
String scanSymbolUnQuoted(final SymbolTable symbolTable);
String stringVal();
boolean isEnabled(int feature);
boolean isEnabled(Feature feature);
void config(Feature feature, boolean state);
void scanString();
int intValue();
void nextTokenWithColon();
void nextTokenWithColon(int expect);
boolean isBlankInput();
void close();
long longValue();
boolean isRef();
String scanTypeName(SymbolTable symbolTable);
String numberString();
byte[] bytesValue();
float floatValue();
int scanInt(char expectNext);
long scanLong(char expectNextChar);
float scanFloat(char seperator);
double scanDouble(char seperator);
boolean scanBoolean(char expectNext);
BigDecimal scanDecimal(char seperator);
String scanString(char expectNextChar);
Enum<?> scanEnum(Class<?> enumClass, final SymbolTable symbolTable, char serperator);
String scanSymbolWithSeperator(final SymbolTable symbolTable, char serperator);
void scanStringArray(Collection<String> collection, char seperator);
TimeZone getTimeZone();
void setTimeZone(TimeZone timeZone);
Locale getLocale();
void setLocale(Locale locale);
String info();
int getFeatures();
void setFeatures(int features);
}
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* Copyright 1999-2017 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 java.io.CharArrayReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.math.BigDecimal;
import java.math.MathContext;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.util.IOUtils;
//这个类,为了性能优化做了很多特别处理,一切都是为了性能!!!
/**
* @author wenshao[szujobs@hotmail.com]
*/
public final class JSONReaderScanner extends JSONLexerBase {
private final static ThreadLocal<char[]> BUF_LOCAL = new ThreadLocal<char[]>();
private Reader reader;
private char[] buf;
private int bufLength;
public JSONReaderScanner(String input){
this(input, JSON.DEFAULT_PARSER_FEATURE);
}
public JSONReaderScanner(String input, int features){
this(new StringReader(input), features);
}
public JSONReaderScanner(char[] input, int inputLength){
this(input, inputLength, JSON.DEFAULT_PARSER_FEATURE);
}
public JSONReaderScanner(Reader reader){
this(reader, JSON.DEFAULT_PARSER_FEATURE);
}
public JSONReaderScanner(Reader reader, int features){
super(features);
this.reader = reader;
buf = BUF_LOCAL.get();
if (buf != null) {
BUF_LOCAL.set(null);
}
if (buf == null) {
buf = new char[1024 * 16];
}
try {
bufLength = reader.read(buf);
} catch (IOException e) {
throw new JSONException(e.getMessage(), e);
}
bp = -1;
next();
if (ch == 65279) { // utf8 bom
next();
}
}
public JSONReaderScanner(char[] input, int inputLength, int features){
this(new CharArrayReader(input, 0, inputLength), features);
}
public final char charAt(int index) {
if (index >= bufLength) {
if (bufLength == -1) {
if (index < sp) {
return buf[index];
}
return EOI;
}
if (bp == 0) {
char[] buf = new char[(this.buf.length * 3) / 2];
System.arraycopy(this.buf, bp, buf, 0, bufLength);
int rest = buf.length - bufLength;
try {
int len = reader.read(buf, bufLength, rest);
bufLength += len;
this.buf = buf;
} catch (IOException e) {
throw new JSONException(e.getMessage(), e);
}
} else {
int rest = bufLength - bp;
if (rest > 0) {
System.arraycopy(buf, bp, buf, 0, rest);
}
try {
bufLength = reader.read(buf, rest, buf.length - rest);
} catch (IOException e) {
throw new JSONException(e.getMessage(), e);
}
if (bufLength == 0) {
throw new JSONException("illegal state, textLength is zero");
}
if (bufLength == -1) {
return EOI;
}
bufLength += rest;
index -= bp;
np -= bp;
bp = 0;
}
}
return buf[index];
}
public final int indexOf(char ch, int startIndex) {
int offset = startIndex - bp;
for (;; ++offset) {
final int index = bp + offset;
char chLoal = charAt(index);
if (ch == chLoal) {
return offset + bp;
}
if (chLoal == EOI) {
return -1;
}
}
}
public final String addSymbol(int offset, int len, int hash, final SymbolTable symbolTable) {
return symbolTable.addSymbol(buf, offset, len, hash);
}
public final char next() {
int index = ++bp;
if (index >= bufLength) {
if (bufLength == -1) {
return EOI;
}
if (sp > 0) {
int offset;
offset = bufLength - sp;
if (ch == '"' && offset > 0) {
offset--;
}
System.arraycopy(buf, offset, buf, 0, sp);
}
np = -1;
index = bp = sp;
try {
int startPos = bp;
int readLength = buf.length - startPos;
if (readLength == 0) {
char[] newBuf = new char[buf.length * 2];
System.arraycopy(buf, 0, newBuf, 0, buf.length);
buf = newBuf;
readLength = buf.length - startPos;
}
bufLength = reader.read(buf, bp, readLength);
} catch (IOException e) {
throw new JSONException(e.getMessage(), e);
}
if (bufLength == 0) {
throw new JSONException("illegal stat, textLength is zero");
}
if (bufLength == -1) {
return ch = EOI;
}
bufLength += bp;
}
return ch = buf[index];
}
protected final void copyTo(int offset, int count, char[] dest) {
System.arraycopy(buf, offset, dest, 0, count);
}
public final boolean charArrayCompare(char[] chars) {
for (int i = 0; i < chars.length; ++i) {
if (charAt(bp + i) != chars[i]) {
return false;
}
}
return true;
}
public byte[] bytesValue() {
if (token == JSONToken.HEX) {
throw new JSONException("TODO");
}
return IOUtils.decodeBase64(buf, np + 1, sp);
}
protected final void arrayCopy(int srcPos, char[] dest, int destPos, int length) {
System.arraycopy(buf, srcPos, dest, destPos, length);
}
/**
* The value of a literal token, recorded as a string. For integers, leading 0x and 'l' suffixes are suppressed.
*/
public final String stringVal() {
if (!hasSpecial) {
int offset = np + 1;
if (offset < 0) {
throw new IllegalStateException();
}
if (offset > buf.length - sp) {
throw new IllegalStateException();
}
return new String(buf, offset, sp);
// return text.substring(np + 1, np + 1 + sp);
} else {
return new String(sbuf, 0, sp);
}
}
public final String subString(int offset, int count) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
return new String(buf, offset, count);
// return text.substring(offset, offset + count);
}
public final char[] sub_chars(int offset, int count) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset == 0) {
return buf;
}
char[] chars = new char[count];
System.arraycopy(buf, offset, chars, 0, count);
return chars;
}
public final String numberString() {
int offset = np;
if (offset == -1) {
offset = 0;
}
char chLocal = charAt(offset + sp - 1);
int sp = this.sp;
if (chLocal == 'L' || chLocal == 'S' || chLocal == 'B' || chLocal == 'F' || chLocal == 'D') {
sp--;
}
String value = new String(buf, offset, sp);
return value;
}
public final BigDecimal decimalValue() {
int offset = np;
if (offset == -1) {
offset = 0;
}
char chLocal = charAt(offset + sp - 1);
int sp = this.sp;
if (chLocal == 'L' || chLocal == 'S' || chLocal == 'B' || chLocal == 'F' || chLocal == 'D') {
sp--;
}
if (sp > 65535) {
throw new JSONException("decimal overflow");
}
return new BigDecimal(buf, offset, sp, MathContext.UNLIMITED);
}
public void close() {
super.close();
if (buf.length <= 1024 * 64) {
BUF_LOCAL.set(buf);
}
this.buf = null;
IOUtils.close(reader);
}
@Override
public boolean isEOF() {
return bufLength == -1 || bp == buf.length || ch == EOI && bp + 1 >= buf.length;
}
public final boolean isBlankInput() {
for (int i = 0;; ++i) {
char chLocal = buf[i];
if (chLocal == EOI) {
token = JSONToken.EOF;
break;
}
if (!isWhitespace(chLocal)) {
return false;
}
}
return true;
}
}
/*
* Copyright 1999-2017 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;
/**
* @author wenshao[szujobs@hotmail.com]
*/
public class JSONToken {
//
public final static int ERROR = 1;
//
public final static int LITERAL_INT = 2;
//
public final static int LITERAL_FLOAT = 3;
//
public final static int LITERAL_STRING = 4;
//
public final static int LITERAL_ISO8601_DATE = 5;
public final static int TRUE = 6;
//
public final static int FALSE = 7;
//
public final static int NULL = 8;
//
public final static int NEW = 9;
//
public final static int LPAREN = 10; // ("("),
//
public final static int RPAREN = 11; // (")"),
//
public final static int LBRACE = 12; // ("{"),
//
public final static int RBRACE = 13; // ("}"),
//
public final static int LBRACKET = 14; // ("["),
//
public final static int RBRACKET = 15; // ("]"),
//
public final static int COMMA = 16; // (","),
//
public final static int COLON = 17; // (":"),
//
public final static int IDENTIFIER = 18;
//
public final static int FIELD_NAME = 19;
public final static int EOF = 20;
public final static int SET = 21;
public final static int TREE_SET = 22;
public final static int UNDEFINED = 23; // undefined
public final static int SEMI = 24;
public final static int DOT = 25;
public final static int HEX = 26;
public static String name(int value) {
switch (value) {
case ERROR:
return "error";
case LITERAL_INT:
return "int";
case LITERAL_FLOAT:
return "float";
case LITERAL_STRING:
return "string";
case LITERAL_ISO8601_DATE:
return "iso8601";
case TRUE:
return "true";
case FALSE:
return "false";
case NULL:
return "null";
case NEW:
return "new";
case LPAREN:
return "(";
case RPAREN:
return ")";
case LBRACE:
return "{";
case RBRACE:
return "}";
case LBRACKET:
return "[";
case RBRACKET:
return "]";
case COMMA:
return ",";
case COLON:
return ":";
case SEMI:
return ";";
case DOT:
return ".";
case IDENTIFIER:
return "ident";
case FIELD_NAME:
return "fieldName";
case EOF:
return "EOF";
case SET:
return "Set";
case TREE_SET:
return "TreeSet";
case UNDEFINED:
return "undefined";
case HEX:
return "hex";
default:
return "Unknown";
}
}
}
package com.alibaba.fastjson.parser;
import java.lang.reflect.Type;
public class ParseContext {
public Object object;
public final ParseContext parent;
public final Object fieldName;
public final int level;
public Type type;
private transient String path;
public ParseContext(ParseContext parent, Object object, Object fieldName){
this.parent = parent;
this.object = object;
this.fieldName = fieldName;
this.level = parent == null ? 0 : parent.level + 1;
}
public String toString() {
if (path == null) {
if (parent == null) {
path = "$";
} else {
if (fieldName instanceof Integer) {
path = parent.toString() + "[" + fieldName + "]";
} else {
path = parent.toString() + "." + fieldName;
}
}
}
return path;
}
}
/*
* Copyright 1999-2017 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 com.alibaba.fastjson.JSON;
/**
* @author wenshao[szujobs@hotmail.com]
*/
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) {
// search for identical symbol
int hash = hash(buffer, offset, len);
return addSymbol(buffer, offset, len, hash);
}
/**
* Adds the specified symbol to the symbol table and returns a reference to the unique symbol. If the symbol already
* exists, the previous symbol reference is returned instead, in order guarantee that symbol references remain
* unique.
*
* @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.
*/
public String addSymbol(char[] buffer, int offset, int len, 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);
}
}
symbol = new String(buffer, offset, len).intern();
symbols[bucket] = symbol;
return symbol;
}
public String addSymbol(String buffer, int offset, int len, int hash) {
return addSymbol(buffer, offset, len, hash, false);
}
public String addSymbol(String buffer, int offset, int len, 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)) {
return symbol;
}
String str = subString(buffer, offset, len);
if (replace) {
symbols[bucket] = str;
}
return str;
}
symbol = len == buffer.length() //
? buffer //
: subString(buffer, offset, len);
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);
return new String(chars);
}
public static int hash(char[] buffer, int offset, int len) {
int h = 0;
int off = offset;
for (int i = 0; i < len; i++) {
h = 31 * h + buffer[off++];
}
return h;
}
}
\ No newline at end of file
package com.alibaba.fastjson.parser.deserializer;
import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.parser.*;
import com.alibaba.fastjson.util.TypeUtils;
public abstract class AbstractDateDeserializer extends ContextObjectDeserializer implements ObjectDeserializer {
public <T> T deserialze(DefaultJSONParser parser, Type clazz, Object fieldName) {
return deserialze(parser, clazz, fieldName, null, 0);
}
@Override
@SuppressWarnings("unchecked")
public <T> T deserialze(DefaultJSONParser parser, Type clazz, Object fieldName, String format, int features) {
JSONLexer lexer = parser.lexer;
Object val;
if (lexer.token() == JSONToken.LITERAL_INT) {
long millis = lexer.longValue();
lexer.nextToken(JSONToken.COMMA);
if ("unixtime".equals(format)) {
millis *= 1000;
}
val = millis;
} else if (lexer.token() == JSONToken.LITERAL_STRING) {
String strVal = lexer.stringVal();
if (format != null) {
if ("yyyy-MM-dd HH:mm:ss.SSSSSSSSS".equals(format)
&& clazz instanceof Class
&& ((Class) clazz).getName().equals("java.sql.Timestamp")) {
return (T) TypeUtils.castToTimestamp(strVal);
}
SimpleDateFormat simpleDateFormat = null;
try {
simpleDateFormat = new SimpleDateFormat(format, parser.lexer.getLocale());
} catch (IllegalArgumentException ex) {
if (format.contains("T")) {
String fromat2 = format.replaceAll("T", "'T'");
try {
simpleDateFormat = new SimpleDateFormat(fromat2, parser.lexer.getLocale());
} catch (IllegalArgumentException e2) {
throw ex;
}
}
}
if (JSON.defaultTimeZone != null) {
simpleDateFormat.setTimeZone(parser.lexer.getTimeZone());
}
try {
val = simpleDateFormat.parse(strVal);
} catch (ParseException ex) {
val = null;
// skip
}
if (val == null && JSON.defaultLocale == Locale.CHINA) {
try {
simpleDateFormat = new SimpleDateFormat(format, Locale.US);
} catch (IllegalArgumentException ex) {
if (format.contains("T")) {
String fromat2 = format.replaceAll("T", "'T'");
try {
simpleDateFormat = new SimpleDateFormat(fromat2, parser.lexer.getLocale());
} catch (IllegalArgumentException e2) {
throw ex;
}
}
}
simpleDateFormat.setTimeZone(parser.lexer.getTimeZone());
try {
val = simpleDateFormat.parse(strVal);
} catch (ParseException ex) {
val = null;
// skip
}
}
if (val == null) {
if (format.equals("yyyy-MM-dd'T'HH:mm:ss.SSS") //
&& strVal.length() == 19) {
try {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", JSON.defaultLocale);
df.setTimeZone(JSON.defaultTimeZone);
val = df.parse(strVal);
} catch (ParseException ex2) {
// skip
val = null;
}
} else {
// skip
val = null;
}
}
} else {
val = null;
}
if (val == null) {
val = strVal;
lexer.nextToken(JSONToken.COMMA);
if (lexer.isEnabled(Feature.AllowISO8601DateFormat)) {
JSONScanner iso8601Lexer = new JSONScanner(strVal);
if (iso8601Lexer.scanISO8601DateIfMatch()) {
val = iso8601Lexer.getCalendar().getTime();
}
iso8601Lexer.close();
}
}
} else if (lexer.token() == JSONToken.NULL) {
lexer.nextToken();
val = null;
} else if (lexer.token() == JSONToken.LBRACE) {
lexer.nextToken();
String key;
if (lexer.token() == JSONToken.LITERAL_STRING) {
key = lexer.stringVal();
if (JSON.DEFAULT_TYPE_KEY.equals(key)) {
lexer.nextToken();
parser.accept(JSONToken.COLON);
String typeName = lexer.stringVal();
Class<?> type = parser.getConfig().checkAutoType(typeName, null, lexer.getFeatures());
if (type != null) {
clazz = type;
}
parser.accept(JSONToken.LITERAL_STRING);
parser.accept(JSONToken.COMMA);
}
lexer.nextTokenWithColon(JSONToken.LITERAL_INT);
} else {
throw new JSONException("syntax error");
}
long timeMillis;
if (lexer.token() == JSONToken.LITERAL_INT) {
timeMillis = lexer.longValue();
lexer.nextToken();
} else {
throw new JSONException("syntax error : " + lexer.tokenName());
}
val = timeMillis;
parser.accept(JSONToken.RBRACE);
} else if (parser.getResolveStatus() == DefaultJSONParser.TypeNameRedirect) {
parser.setResolveStatus(DefaultJSONParser.NONE);
parser.accept(JSONToken.COMMA);
if (lexer.token() == JSONToken.LITERAL_STRING) {
if (!"val".equals(lexer.stringVal())) {
throw new JSONException("syntax error");
}
lexer.nextToken();
} else {
throw new JSONException("syntax error");
}
parser.accept(JSONToken.COLON);
val = parser.parse();
parser.accept(JSONToken.RBRACE);
} else {
val = parser.parse();
}
return (T) cast(parser, clazz, fieldName, val);
}
protected abstract <T> T cast(DefaultJSONParser parser, Type clazz, Object fieldName, Object value);
}
package com.alibaba.fastjson.parser.deserializer;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.JSONLexer;
import com.alibaba.fastjson.parser.JSONToken;
import com.alibaba.fastjson.parser.ParseContext;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.util.FieldInfo;
import com.alibaba.fastjson.util.ParameterizedTypeImpl;
public class ArrayListTypeFieldDeserializer extends FieldDeserializer {
private final Type itemType;
private int itemFastMatchToken;
private ObjectDeserializer deserializer;
public ArrayListTypeFieldDeserializer(ParserConfig mapping, Class<?> clazz, FieldInfo fieldInfo){
super(clazz, fieldInfo);
Type fieldType = fieldInfo.fieldType;
if (fieldType instanceof ParameterizedType) {
Type argType = ((ParameterizedType) fieldInfo.fieldType).getActualTypeArguments()[0];
if (argType instanceof WildcardType) {
WildcardType wildcardType = (WildcardType) argType;
Type[] upperBounds = wildcardType.getUpperBounds();
if (upperBounds.length == 1) {
argType = upperBounds[0];
}
}
this.itemType = argType;
} else {
this.itemType = Object.class;
}
}
public int getFastMatchToken() {
return JSONToken.LBRACKET;
}
@SuppressWarnings("rawtypes")
@Override
public void parseField(DefaultJSONParser parser, Object object, Type objectType, Map<String, Object> fieldValues) {
JSONLexer lexer = parser.lexer;
final int token = lexer.token();
if (token == JSONToken.NULL
|| (token == JSONToken.LITERAL_STRING && lexer.stringVal().length() == 0)) {
if (object == null) {
fieldValues.put(fieldInfo.name, null);
} else {
setValue(object, null);
}
return;
}
ArrayList list = new ArrayList();
ParseContext context = parser.getContext();
parser.setContext(context, object, fieldInfo.name);
parseArray(parser, objectType, list);
parser.setContext(context);
if (object == null) {
fieldValues.put(fieldInfo.name, list);
} else {
setValue(object, list);
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public final void parseArray(DefaultJSONParser parser, Type objectType, Collection array) {
Type itemType = this.itemType;
ObjectDeserializer itemTypeDeser = this.deserializer;
if (objectType instanceof ParameterizedType) {
if (itemType instanceof TypeVariable) {
TypeVariable typeVar = (TypeVariable) itemType;
ParameterizedType paramType = (ParameterizedType) objectType;
Class<?> objectClass = null;
if (paramType.getRawType() instanceof Class) {
objectClass = (Class<?>) paramType.getRawType();
}
int paramIndex = -1;
if (objectClass != null) {
for (int i = 0, size = objectClass.getTypeParameters().length; i < size; ++i) {
TypeVariable item = objectClass.getTypeParameters()[i];
if (item.getName().equals(typeVar.getName())) {
paramIndex = i;
break;
}
}
}
if (paramIndex != -1) {
itemType = paramType.getActualTypeArguments()[paramIndex];
if (!itemType.equals(this.itemType)) {
itemTypeDeser = parser.getConfig().getDeserializer(itemType);
}
}
} else if (itemType instanceof ParameterizedType) {
ParameterizedType parameterizedItemType = (ParameterizedType) itemType;
Type[] itemActualTypeArgs = parameterizedItemType.getActualTypeArguments();
if (itemActualTypeArgs.length == 1 && itemActualTypeArgs[0] instanceof TypeVariable) {
TypeVariable typeVar = (TypeVariable) itemActualTypeArgs[0];
ParameterizedType paramType = (ParameterizedType) objectType;
Class<?> objectClass = null;
if (paramType.getRawType() instanceof Class) {
objectClass = (Class<?>) paramType.getRawType();
}
int paramIndex = -1;
if (objectClass != null) {
for (int i = 0, size = objectClass.getTypeParameters().length; i < size; ++i) {
TypeVariable item = objectClass.getTypeParameters()[i];
if (item.getName().equals(typeVar.getName())) {
paramIndex = i;
break;
}
}
}
if (paramIndex != -1) {
itemActualTypeArgs[0] = paramType.getActualTypeArguments()[paramIndex];
itemType = TypeReference.intern(
new ParameterizedTypeImpl(itemActualTypeArgs, parameterizedItemType.getOwnerType(), parameterizedItemType.getRawType())
);
}
}
}
} else if (itemType instanceof TypeVariable && objectType instanceof Class) {
Class objectClass = (Class) objectType;
TypeVariable typeVar = (TypeVariable) itemType;
objectClass.getTypeParameters();
for (int i = 0, size = objectClass.getTypeParameters().length; i < size; ++i) {
TypeVariable item = objectClass.getTypeParameters()[i];
if (item.getName().equals(typeVar.getName())) {
Type[] bounds = item.getBounds();
if (bounds.length == 1) {
itemType = bounds[0];
}
break;
}
}
}
final JSONLexer lexer = parser.lexer;
final int token = lexer.token();
if (token == JSONToken.LBRACKET) {
if (itemTypeDeser == null) {
itemTypeDeser = deserializer = parser.getConfig().getDeserializer(itemType);
itemFastMatchToken = deserializer.getFastMatchToken();
}
lexer.nextToken(itemFastMatchToken);
for (int i = 0; ; ++i) {
if (lexer.isEnabled(Feature.AllowArbitraryCommas)) {
while (lexer.token() == JSONToken.COMMA) {
lexer.nextToken();
continue;
}
}
if (lexer.token() == JSONToken.RBRACKET) {
break;
}
Object val = itemTypeDeser.deserialze(parser, itemType, i);
array.add(val);
parser.checkListResolve(array);
if (lexer.token() == JSONToken.COMMA) {
lexer.nextToken(itemFastMatchToken);
continue;
}
}
lexer.nextToken(JSONToken.COMMA);
} else if (token == JSONToken.LITERAL_STRING && fieldInfo.unwrapped) {
String str = lexer.stringVal();
lexer.nextToken();
DefaultJSONParser valueParser = new DefaultJSONParser(str);
valueParser.parseArray(array);
} else {
if (itemTypeDeser == null) {
itemTypeDeser = deserializer = parser.getConfig().getDeserializer(itemType);
}
Object val = itemTypeDeser.deserialze(parser, itemType, 0);
array.add(val);
parser.checkListResolve(array);
}
}
}
package com.alibaba.fastjson.parser.deserializer;
import java.lang.reflect.Type;
import java.util.Set;
public interface AutowiredObjectDeserializer extends ObjectDeserializer{
Set<Type> getAutowiredFor();
}
package com.alibaba.fastjson.parser.deserializer;
import java.lang.reflect.Type;
import com.alibaba.fastjson.parser.DefaultJSONParser;
public abstract class ContextObjectDeserializer implements ObjectDeserializer {
public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
return deserialze(parser, type, fieldName, null, 0);
}
public abstract <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName, String format, int features);
}
package com.alibaba.fastjson.parser.deserializer;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.DefaultJSONParser.ResolveTask;
import com.alibaba.fastjson.parser.JSONToken;
import com.alibaba.fastjson.parser.ParseContext;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.util.FieldInfo;
public class DefaultFieldDeserializer extends FieldDeserializer {
protected ObjectDeserializer fieldValueDeserilizer;
protected boolean customDeserilizer = false;
public DefaultFieldDeserializer(ParserConfig config, Class<?> clazz, FieldInfo fieldInfo){
super(clazz, fieldInfo);
JSONField annotation = fieldInfo.getAnnotation();
if (annotation != null) {
Class<?> deserializeUsing = annotation.deserializeUsing();
customDeserilizer = deserializeUsing != null && deserializeUsing != Void.class;
}
}
public ObjectDeserializer getFieldValueDeserilizer(ParserConfig config) {
if (fieldValueDeserilizer == null) {
JSONField annotation = fieldInfo.getAnnotation();
if (annotation != null && annotation.deserializeUsing() != Void.class) {
Class<?> deserializeUsing = annotation.deserializeUsing();
try {
fieldValueDeserilizer = (ObjectDeserializer) deserializeUsing.newInstance();
} catch (Exception ex) {
throw new JSONException("create deserializeUsing ObjectDeserializer error", ex);
}
} else {
fieldValueDeserilizer = config.getDeserializer(fieldInfo.fieldClass, fieldInfo.fieldType);
}
}
return fieldValueDeserilizer;
}
@Override
public void parseField(DefaultJSONParser parser, Object object, Type objectType, Map<String, Object> fieldValues) {
if (this.fieldValueDeserilizer == null) {
getFieldValueDeserilizer(parser.getConfig());
}
ObjectDeserializer fieldValueDeserilizer = this.fieldValueDeserilizer;
Type fieldType = fieldInfo.fieldType;
if (objectType instanceof ParameterizedType) {
ParseContext objContext = parser.getContext();
if (objContext != null) {
objContext.type = objectType;
}
if (fieldType != objectType) {
fieldType = FieldInfo.getFieldType(this.clazz, objectType, fieldType);
if (fieldValueDeserilizer instanceof JavaObjectDeserializer) {
fieldValueDeserilizer = parser.getConfig().getDeserializer(fieldType);
}
}
}
// ContextObjectDeserializer
Object value;
if (fieldValueDeserilizer instanceof JavaBeanDeserializer && fieldInfo.parserFeatures != 0) {
JavaBeanDeserializer javaBeanDeser = (JavaBeanDeserializer) fieldValueDeserilizer;
value = javaBeanDeser.deserialze(parser, fieldType, fieldInfo.name, fieldInfo.parserFeatures);
} else {
if ((this.fieldInfo.format != null || this.fieldInfo.parserFeatures != 0)
&& fieldValueDeserilizer instanceof ContextObjectDeserializer) {
value = ((ContextObjectDeserializer) fieldValueDeserilizer) //
.deserialze(parser,
fieldType,
fieldInfo.name,
fieldInfo.format,
fieldInfo.parserFeatures);
} else {
value = fieldValueDeserilizer.deserialze(parser, fieldType, fieldInfo.name);
}
}
if (value instanceof byte[]
&& ("gzip".equals(fieldInfo.format) || "gzip,base64".equals(fieldInfo.format))) {
byte[] bytes = (byte[]) value;
GZIPInputStream gzipIn = null;
try {
gzipIn = new GZIPInputStream(new ByteArrayInputStream(bytes));
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
for (;;) {
byte[] buf = new byte[1024];
int len = gzipIn.read(buf);
if (len == -1) {
break;
}
if (len > 0) {
byteOut.write(buf, 0, len);
}
}
value = byteOut.toByteArray();
} catch (IOException ex) {
throw new JSONException("unzip bytes error.", ex);
}
}
if (parser.getResolveStatus() == DefaultJSONParser.NeedToResolve) {
ResolveTask task = parser.getLastResolveTask();
task.fieldDeserializer = this;
task.ownerContext = parser.getContext();
parser.setResolveStatus(DefaultJSONParser.NONE);
} else {
if (object == null) {
fieldValues.put(fieldInfo.name, value);
} else {
setValue(object, value);
}
}
}
public int getFastMatchToken() {
if (fieldValueDeserilizer != null) {
return fieldValueDeserilizer.getFastMatchToken();
}
return JSONToken.LITERAL_INT;
}
public void parseFieldUnwrapped(DefaultJSONParser parser, Object object, Type objectType, Map<String, Object> fieldValues) {
throw new JSONException("TODO");
}
}
package com.alibaba.fastjson.parser.deserializer;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.parser.DefaultJSONParser;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
public class EnumCreatorDeserializer implements ObjectDeserializer {
private final Method creator;
private final Class paramType;
public EnumCreatorDeserializer(Method creator) {
this.creator = creator;
paramType = creator.getParameterTypes()[0];
}
public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
Object arg = parser.parseObject(paramType);
try {
return (T) creator.invoke(null, arg);
} catch (IllegalAccessException e) {
throw new JSONException("parse enum error", e);
} catch (InvocationTargetException e) {
throw new JSONException("parse enum error", e);
}
}
public int getFastMatchToken() {
return 0;
}
}
package com.alibaba.fastjson.parser.deserializer;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.*;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.JSONLexer;
import com.alibaba.fastjson.parser.JSONToken;
import com.alibaba.fastjson.util.TypeUtils;
import static com.alibaba.fastjson.util.TypeUtils.fnv1a_64_magic_hashcode;
import static com.alibaba.fastjson.util.TypeUtils.fnv1a_64_magic_prime;
@SuppressWarnings("rawtypes")
public class EnumDeserializer implements ObjectDeserializer {
protected final Class<?> enumClass;
protected final Enum[] enums;
protected final Enum[] ordinalEnums;
protected long[] enumNameHashCodes;
public EnumDeserializer(Class<?> enumClass){
this.enumClass = enumClass;
ordinalEnums = (Enum[]) enumClass.getEnumConstants();
Map<Long, Enum> enumMap = new HashMap<Long, Enum>();
for (int i = 0; i < ordinalEnums.length; ++i) {
Enum e = ordinalEnums[i];
String name = e.name();
JSONField jsonField = null;
try {
Field field = enumClass.getField(name);
jsonField = TypeUtils.getAnnotation(field, JSONField.class);
if (jsonField != null) {
String jsonFieldName = jsonField.name();
if (jsonFieldName != null && jsonFieldName.length() > 0) {
name = jsonFieldName;
}
}
} catch (Exception ex) {
// skip
}
long hash = fnv1a_64_magic_hashcode;
long hash_lower = fnv1a_64_magic_hashcode;
for (int j = 0; j < name.length(); ++j) {
char ch = name.charAt(j);
hash ^= ch;
hash_lower ^= ((ch >= 'A' && ch <= 'Z') ? (ch + 32) : ch);
hash *= fnv1a_64_magic_prime;
hash_lower *= fnv1a_64_magic_prime;
}
enumMap.put(hash, e);
if (hash != hash_lower) {
enumMap.put(hash_lower, e);
}
if (jsonField != null) {
for (String alterName : jsonField.alternateNames()) {
long alterNameHash = fnv1a_64_magic_hashcode;
for (int j = 0; j < alterName.length(); ++j) {
char ch = alterName.charAt(j);
alterNameHash ^= ch;
alterNameHash *= fnv1a_64_magic_prime;
}
if (alterNameHash != hash && alterNameHash != hash_lower) {
enumMap.put(alterNameHash, e);
}
}
}
}
this.enumNameHashCodes = new long[enumMap.size()];
{
int i = 0;
for (Long h : enumMap.keySet()) {
enumNameHashCodes[i++] = h;
}
Arrays.sort(this.enumNameHashCodes);
}
this.enums = new Enum[enumNameHashCodes.length];
for (int i = 0; i < this.enumNameHashCodes.length; ++i) {
long hash = enumNameHashCodes[i];
Enum e = enumMap.get(hash);
this.enums[i] = e;
}
}
public Enum getEnumByHashCode(long hashCode) {
if (enums == null) {
return null;
}
int enumIndex = Arrays.binarySearch(this.enumNameHashCodes, hashCode);
if (enumIndex < 0) {
return null;
}
return enums[enumIndex];
}
public Enum<?> valueOf(int ordinal) {
return ordinalEnums[ordinal];
}
@SuppressWarnings("unchecked")
public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
try {
Object value;
final JSONLexer lexer = parser.lexer;
final int token = lexer.token();
if (token == JSONToken.LITERAL_INT) {
int intValue = lexer.intValue();
lexer.nextToken(JSONToken.COMMA);
if (intValue < 0 || intValue >= ordinalEnums.length) {
throw new JSONException("parse enum " + enumClass.getName() + " error, value : " + intValue);
}
return (T) ordinalEnums[intValue];
} else if (token == JSONToken.LITERAL_STRING) {
String name = lexer.stringVal();
lexer.nextToken(JSONToken.COMMA);
if (name.length() == 0) {
return (T) null;
}
long hash = fnv1a_64_magic_hashcode;
long hash_lower = fnv1a_64_magic_hashcode;
for (int j = 0; j < name.length(); ++j) {
char ch = name.charAt(j);
hash ^= ch;
hash_lower ^= ((ch >= 'A' && ch <= 'Z') ? (ch + 32) : ch);
hash *= fnv1a_64_magic_prime;
hash_lower *= fnv1a_64_magic_prime;
}
Enum e = getEnumByHashCode(hash);
if (e == null && hash_lower != hash) {
e = getEnumByHashCode(hash_lower);
}
if (e == null && lexer.isEnabled(Feature.ErrorOnEnumNotMatch)) {
throw new JSONException("not match enum value, " + enumClass.getName() + " : " + name);
}
return (T) e;
} else if (token == JSONToken.NULL) {
value = null;
lexer.nextToken(JSONToken.COMMA);
return null;
} else {
value = parser.parse();
}
throw new JSONException("parse enum " + enumClass.getName() + " error, value : " + value);
} catch (JSONException e) {
throw e;
} catch (Exception e) {
throw new JSONException(e.getMessage(), e);
}
}
public int getFastMatchToken() {
return JSONToken.LITERAL_INT;
}
}
package com.alibaba.fastjson.parser.deserializer;
/**
*
* @author wenshao[szujobs@hotmail.com]
* @since 1.2.9
*/
public interface ExtraProcessable {
void processExtra(String key, Object value);
}
package com.alibaba.fastjson.parser.deserializer;
/**
*
* @author wenshao[szujobs@hotmail.com]
* @since 1.1.34
*/
public interface ExtraProcessor extends ParseProcess {
void processExtra(Object object, String key, Object value);
}
package com.alibaba.fastjson.parser.deserializer;
import java.lang.reflect.Type;
/**
* @author wenshao[szujobs@hotmail.com]
* @since 1.1.34
*/
public interface ExtraTypeProvider extends ParseProcess {
Type getExtraType(Object object, String key);
}
package com.alibaba.fastjson.parser.deserializer;
import java.lang.reflect.Type;
public interface FieldTypeResolver extends ParseProcess {
Type resolve(Object object, String fieldName);
}
package com.alibaba.fastjson.parser.deserializer;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONPObject;
import com.alibaba.fastjson.parser.*;
import java.lang.reflect.Type;
/**
* Created by wenshao on 21/02/2017.
*/
public class JSONPDeserializer implements ObjectDeserializer {
public static final JSONPDeserializer instance = new JSONPDeserializer();
public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
JSONLexerBase lexer = (JSONLexerBase) parser.getLexer();
SymbolTable symbolTable = parser.getSymbolTable();
String funcName = lexer.scanSymbolUnQuoted(symbolTable);
lexer.nextToken();
int tok = lexer.token();
if (tok == JSONToken.DOT) {
String name = lexer.scanSymbolUnQuoted(parser.getSymbolTable());
funcName += ".";
funcName += name;
lexer.nextToken();
tok = lexer.token();
}
JSONPObject jsonp = new JSONPObject(funcName);
if (tok != JSONToken.LPAREN) {
throw new JSONException("illegal jsonp : " + lexer.info());
}
lexer.nextToken();
for (;;) {
Object arg = parser.parse();
jsonp.addParameter(arg);
tok = lexer.token();
if (tok == JSONToken.COMMA) {
lexer.nextToken();
} else if (tok == JSONToken.RPAREN) {
lexer.nextToken();
break;
} else {
throw new JSONException("illegal jsonp : " + lexer.info());
}
}
tok = lexer.token();
if (tok == JSONToken.SEMI) {
lexer.nextToken();
}
return (T) jsonp;
}
public int getFastMatchToken() {
return 0;
}
}
package com.alibaba.fastjson.parser.deserializer;
import java.io.Closeable;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.JSONToken;
import com.alibaba.fastjson.util.TypeUtils;
public class JavaObjectDeserializer implements ObjectDeserializer {
public final static JavaObjectDeserializer instance = new JavaObjectDeserializer();
@SuppressWarnings("unchecked")
public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
if (type instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) type).getGenericComponentType();
if (componentType instanceof TypeVariable) {
TypeVariable<?> componentVar = (TypeVariable<?>) componentType;
componentType = componentVar.getBounds()[0];
}
List<Object> list = new ArrayList<Object>();
parser.parseArray(componentType, list);
Class<?> componentClass = TypeUtils.getRawClass(componentType);
Object[] array = (Object[]) Array.newInstance(componentClass, list.size());
list.toArray(array);
return (T) array;
}
if (type instanceof Class
&& type != Object.class
&& type != Serializable.class
&& type != Cloneable.class
&& type != Closeable.class
&& type != Comparable.class) {
return (T) parser.parseObject(type);
}
return (T) parser.parse(fieldName);
}
public int getFastMatchToken() {
return JSONToken.LBRACE;
}
}
package com.alibaba.fastjson.parser.deserializer;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.JSONLexer;
import com.alibaba.fastjson.parser.JSONToken;
import com.alibaba.fastjson.util.TypeUtils;
public class NumberDeserializer implements ObjectDeserializer {
public final static NumberDeserializer instance = new NumberDeserializer();
@SuppressWarnings("unchecked")
public <T> T deserialze(DefaultJSONParser parser, Type clazz, Object fieldName) {
final JSONLexer lexer = parser.lexer;
if (lexer.token() == JSONToken.LITERAL_INT) {
if (clazz == double.class || clazz == Double.class) {
String val = lexer.numberString();
lexer.nextToken(JSONToken.COMMA);
return (T) Double.valueOf(Double.parseDouble(val));
}
long val = lexer.longValue();
lexer.nextToken(JSONToken.COMMA);
if (clazz == short.class || clazz == Short.class) {
if (val > Short.MAX_VALUE || val < Short.MIN_VALUE) {
throw new JSONException("short overflow : " + val);
}
return (T) Short.valueOf((short) val);
}
if (clazz == byte.class || clazz == Byte.class) {
if (val > Byte.MAX_VALUE || val < Byte.MIN_VALUE) {
throw new JSONException("short overflow : " + val);
}
return (T) Byte.valueOf((byte) val);
}
if (val >= Integer.MIN_VALUE && val <= Integer.MAX_VALUE) {
return (T) Integer.valueOf((int) val);
}
return (T) Long.valueOf(val);
}
if (lexer.token() == JSONToken.LITERAL_FLOAT) {
if (clazz == double.class || clazz == Double.class) {
String val = lexer.numberString();
lexer.nextToken(JSONToken.COMMA);
return (T) Double.valueOf(Double.parseDouble(val));
}
if (clazz == short.class || clazz == Short.class) {
BigDecimal val = lexer.decimalValue();
lexer.nextToken(JSONToken.COMMA);
short shortValue = TypeUtils.shortValue(val);
return (T) Short.valueOf(shortValue);
}
if (clazz == byte.class || clazz == Byte.class) {
BigDecimal val = lexer.decimalValue();
lexer.nextToken(JSONToken.COMMA);
byte byteValue = TypeUtils.byteValue(val);
return (T) Byte.valueOf(byteValue);
}
BigDecimal val = lexer.decimalValue();
lexer.nextToken(JSONToken.COMMA);
if (lexer.isEnabled(Feature.UseBigDecimal)) {
return (T) val;
} else {
return (T) Double.valueOf(val.doubleValue());
}
}
if (lexer.token() == JSONToken.IDENTIFIER && "NaN".equals(lexer.stringVal())) {
lexer.nextToken();
Object nan = null;
if (clazz == Double.class) {
nan = Double.NaN;
} else if (clazz == Float.class) {
nan = Float.NaN;
}
return (T) nan;
}
Object value = parser.parse();
if (value == null) {
return null;
}
if (clazz == double.class || clazz == Double.class) {
try {
return (T) TypeUtils.castToDouble(value);
} catch (Exception ex) {
throw new JSONException("parseDouble error, field : " + fieldName, ex);
}
}
if (clazz == short.class || clazz == Short.class) {
try {
return (T) TypeUtils.castToShort(value);
} catch (Exception ex) {
throw new JSONException("parseShort error, field : " + fieldName, ex);
}
}
if (clazz == byte.class || clazz == Byte.class) {
try {
return (T) TypeUtils.castToByte(value);
} catch (Exception ex) {
throw new JSONException("parseByte error, field : " + fieldName, ex);
}
}
return (T) TypeUtils.castToBigDecimal(value);
}
public int getFastMatchToken() {
return JSONToken.LITERAL_INT;
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论