+ * @author wenshao[szujobs@hotmail.com]
*/
public interface JSONStreamAware {
diff --git a/src/main/java/com/alibaba/fastjson/JSONStreamContext.java b/src/main/java/com/alibaba/fastjson/JSONStreamContext.java
new file mode 100644
index 0000000000..a0309a1376
--- /dev/null
+++ b/src/main/java/com/alibaba/fastjson/JSONStreamContext.java
@@ -0,0 +1,19 @@
+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;
+ }
+}
diff --git a/src/main/java/com/alibaba/fastjson/JSONWriter.java b/src/main/java/com/alibaba/fastjson/JSONWriter.java
new file mode 100755
index 0000000000..7cb288dd8e
--- /dev/null
+++ b/src/main/java/com/alibaba/fastjson/JSONWriter.java
@@ -0,0 +1,204 @@
+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);
+
+ afterWriter();
+ }
+
+ public void writeObject(Object object) {
+ beforeWrite();
+ serializer.write(object);
+ afterWriter();
+ }
+
+ 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 afterWriter() {
+ 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();
+ }
+}
diff --git a/src/main/java/com/alibaba/fastjson/PropertyNamingStrategy.java b/src/main/java/com/alibaba/fastjson/PropertyNamingStrategy.java
new file mode 100644
index 0000000000..adfa285bbe
--- /dev/null
+++ b/src/main/java/com/alibaba/fastjson/PropertyNamingStrategy.java
@@ -0,0 +1,70 @@
+package com.alibaba.fastjson;
+
+/**
+ * @since 1.2.15
+ */
+public enum PropertyNamingStrategy {
+ CamelCase, //
+ PascalCase, //
+ SnakeCase, //
+ KebabCase;
+
+ 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;
+ }
+ default:
+ return propertyName;
+ }
+ }
+}
diff --git a/src/main/java/com/alibaba/fastjson/TypeReference.java b/src/main/java/com/alibaba/fastjson/TypeReference.java
old mode 100644
new mode 100755
index 7cb7085afd..b2c02928bb
--- a/src/main/java/com/alibaba/fastjson/TypeReference.java
+++ b/src/main/java/com/alibaba/fastjson/TypeReference.java
@@ -1,22 +1,132 @@
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.
+ *
+ * For example, to create a type literal for {@code List}, you can
+ * create an empty anonymous inner class:
+ *
+ *
+ * TypeReference<List<String>> list = new TypeReference<List<String>>() {};
+ *
+ * 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 {
+ static ConcurrentMap classTypeCache
+ = new ConcurrentHashMap(16, 0.75f, 1);
- private final Type type;
+ protected final Type type;
+ /**
+ * Constructs a new type literal. Derives represented class from type
+ * parameter.
+ *
+ * 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 = ((ParameterizedType) superClass).getActualTypeArguments()[0];
+ 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;
+
+ }
+
+ 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) {
+ return 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>() {}.getType();
}
diff --git a/src/main/java/com/alibaba/fastjson/annotation/JSONCreator.java b/src/main/java/com/alibaba/fastjson/annotation/JSONCreator.java
new file mode 100755
index 0000000000..10224689d0
--- /dev/null
+++ b/src/main/java/com/alibaba/fastjson/annotation/JSONCreator.java
@@ -0,0 +1,12 @@
+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 {
+
+}
diff --git a/src/main/java/com/alibaba/fastjson/annotation/JSONField.java b/src/main/java/com/alibaba/fastjson/annotation/JSONField.java
old mode 100644
new mode 100755
index 2078031a6c..9907c9ea86
--- a/src/main/java/com/alibaba/fastjson/annotation/JSONField.java
+++ b/src/main/java/com/alibaba/fastjson/annotation/JSONField.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1999-2101 Alibaba Group.
+ * 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.
@@ -24,11 +24,17 @@
import com.alibaba.fastjson.serializer.SerializerFeature;
/**
- * @author wenshao
+ * @author wenshao[szujobs@hotmail.com]
*/
@Retention(RetentionPolicy.RUNTIME)
-@Target({ ElementType.METHOD, ElementType.FIELD })
+@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 "";
@@ -41,4 +47,36 @@
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;
}
diff --git a/src/main/java/com/alibaba/fastjson/annotation/JSONPOJOBuilder.java b/src/main/java/com/alibaba/fastjson/annotation/JSONPOJOBuilder.java
new file mode 100644
index 0000000000..648065dbc0
--- /dev/null
+++ b/src/main/java/com/alibaba/fastjson/annotation/JSONPOJOBuilder.java
@@ -0,0 +1,42 @@
+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.
+ *
+ * Default value is "build".
+ */
+ public 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 com.alibaba.fastjson.annotation.JSONField}
+ * annotation to indicate "with-methods".
+ *
+ * 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.
+ */
+ public String withPrefix() default "with";
+
+}
diff --git a/src/main/java/com/alibaba/fastjson/annotation/JSONType.java b/src/main/java/com/alibaba/fastjson/annotation/JSONType.java
new file mode 100755
index 0000000000..fd179447e0
--- /dev/null
+++ b/src/main/java/com/alibaba/fastjson/annotation/JSONType.java
@@ -0,0 +1,67 @@
+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.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.CamelCase;
+}
diff --git a/src/main/java/com/alibaba/fastjson/asm/ByteVector.java b/src/main/java/com/alibaba/fastjson/asm/ByteVector.java
old mode 100644
new mode 100755
diff --git a/src/main/java/com/alibaba/fastjson/asm/ClassReader.java b/src/main/java/com/alibaba/fastjson/asm/ClassReader.java
new file mode 100644
index 0000000000..fdab09f1a8
--- /dev/null
+++ b/src/main/java/com/alibaba/fastjson/asm/ClassReader.java
@@ -0,0 +1,299 @@
+package com.alibaba.fastjson.asm;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Created by wenshao on 05/08/2017.
+ */
+public class ClassReader {
+ public final byte[] b;
+ private final int[] items;
+ private final String[] strings;
+ private final int maxStringLength;
+ public final int header;
+
+
+ public ClassReader(final InputStream is) throws IOException {
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ byte[] buf = new byte[1024];
+ for (; ; ) {
+ int len = is.read(buf);
+ if (len == -1) {
+ break;
+ }
+
+ if (len > 0) {
+ out.write(buf, 0, len);
+ }
+ }
+ is.close();
+ this.b = out.toByteArray();
+ }
+
+ // parses the constant pool
+ items = new int[readUnsignedShort(8)];
+ int n = items.length;
+ strings = new String[n];
+ int max = 0;
+ int index = 10;
+ for (int i = 1; i < n; ++i) {
+ items[i] = index + 1;
+ int size;
+ switch (b[index]) {
+ case 9: // FIELD:
+ case 10: // METH:
+ case 11: //IMETH:
+ case 3: //INT:
+ case 4: //FLOAT:
+ case 18: //INVOKEDYN:
+ case 12: //NAME_TYPE:
+ size = 5;
+ break;
+ case 5: //LONG:
+ case 6: //DOUBLE:
+ size = 9;
+ ++i;
+ break;
+ case 15: //MHANDLE:
+ size = 4;
+ break;
+ case 1: //UTF8:
+ size = 3 + readUnsignedShort(index + 1);
+ if (size > max) {
+ max = size;
+ }
+ break;
+ // case HamConstants.CLASS:
+ // case HamConstants.STR:
+ default:
+ size = 3;
+ break;
+ }
+ index += size;
+ }
+ maxStringLength = max;
+ // the class header information starts just after the constant pool
+ header = index;
+ }
+
+ public void accept(final TypeCollector classVisitor) {
+ char[] c = new char[maxStringLength]; // buffer used to read strings
+ int i, j, k; // loop variables
+ int u, v, w; // indexes in b
+
+ String attrName;
+ int anns = 0;
+ int ianns = 0;
+
+ // visits the header
+ u = header;
+ v = items[readUnsignedShort(u + 4)];
+ int len = readUnsignedShort(u + 6);
+ w = 0;
+ u += 8;
+ for (i = 0; i < len; ++i) {
+ u += 2;
+ }
+ v = u;
+ i = readUnsignedShort(v);
+ v += 2;
+ for (; i > 0; --i) {
+ j = readUnsignedShort(v + 6);
+ v += 8;
+ for (; j > 0; --j) {
+ v += 6 + readInt(v + 2);
+ }
+ }
+ i = readUnsignedShort(v);
+ v += 2;
+ for (; i > 0; --i) {
+ j = readUnsignedShort(v + 6);
+ v += 8;
+ for (; j > 0; --j) {
+ v += 6 + readInt(v + 2);
+ }
+ }
+
+ i = readUnsignedShort(v);
+ v += 2;
+ for (; i > 0; --i) {
+ v += 6 + readInt(v + 2);
+ }
+
+ //annotations not needed.
+
+ // visits the fields
+ i = readUnsignedShort(u);
+ u += 2;
+ for (; i > 0; --i) {
+ j = readUnsignedShort(u + 6);
+ u += 8;
+ for (; j > 0; --j) {
+ u += 6 + readInt(u + 2);
+ }
+ }
+
+ // visits the methods
+ i = readUnsignedShort(u);
+ u += 2;
+ for (; i > 0; --i) {
+ // inlined in original ASM source, now a method call
+ u = readMethod(classVisitor, c, u);
+ }
+ }
+
+ private int readMethod(TypeCollector classVisitor, char[] c, int u) {
+ int v;
+ int w;
+ int j;
+ String attrName;
+ int k;
+ int access = readUnsignedShort(u);
+ String name = readUTF8(u + 2, c);
+ String desc = readUTF8(u + 4, c);
+ v = 0;
+ w = 0;
+
+ // looks for Code and Exceptions attributes
+ j = readUnsignedShort(u + 6);
+ u += 8;
+ for (; j > 0; --j) {
+ attrName = readUTF8(u, c);
+ int attrSize = readInt(u + 2);
+ u += 6;
+ // tests are sorted in decreasing frequency order
+ // (based on frequencies observed on typical classes)
+ if (attrName.equals("Code")) {
+ v = u;
+ }
+ u += attrSize;
+ }
+ // reads declared exceptions
+ if (w == 0) {
+ } else {
+ w += 2;
+ for (j = 0; j < readUnsignedShort(w); ++j) {
+ w += 2;
+ }
+ }
+
+ // visits the method's code, if any
+ MethodCollector mv = classVisitor.visitMethod(access, name, desc);
+
+ if (mv != null && v != 0) {
+ int codeLength = readInt(v + 4);
+ v += 8;
+
+ int codeStart = v;
+ int codeEnd = v + codeLength;
+ v = codeEnd;
+
+ j = readUnsignedShort(v);
+ v += 2;
+ for (; j > 0; --j) {
+ v += 8;
+ }
+ // parses the local variable, line number tables, and code
+ // attributes
+ int varTable = 0;
+ int varTypeTable = 0;
+ j = readUnsignedShort(v);
+ v += 2;
+ for (; j > 0; --j) {
+ attrName = readUTF8(v, c);
+ if (attrName.equals("LocalVariableTable")) {
+ varTable = v + 6;
+ } else if (attrName.equals("LocalVariableTypeTable")) {
+ varTypeTable = v + 6;
+ }
+ v += 6 + readInt(v + 2);
+ }
+
+ v = codeStart;
+ // visits the local variable tables
+ if (varTable != 0) {
+ if (varTypeTable != 0) {
+ k = readUnsignedShort(varTypeTable) * 3;
+ w = varTypeTable + 2;
+ int[] typeTable = new int[k];
+ while (k > 0) {
+ typeTable[--k] = w + 6; // signature
+ typeTable[--k] = readUnsignedShort(w + 8); // index
+ typeTable[--k] = readUnsignedShort(w); // start
+ w += 10;
+ }
+ }
+ k = readUnsignedShort(varTable);
+ w = varTable + 2;
+ for (; k > 0; --k) {
+ int index = readUnsignedShort(w + 8);
+ mv.visitLocalVariable(readUTF8(w + 4, c), index);
+ w += 10;
+ }
+ }
+ }
+ return u;
+ }
+
+ private int readUnsignedShort(final int index) {
+ byte[] b = this.b;
+ return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
+ }
+
+ private int readInt(final int index) {
+ byte[] b = this.b;
+ return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16)
+ | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
+ }
+
+ private String readUTF8(int index, final char[] buf) {
+ int item = readUnsignedShort(index);
+ String s = strings[item];
+ if (s != null) {
+ return s;
+ }
+ index = items[item];
+ return strings[item] = readUTF(index + 2, readUnsignedShort(index), buf);
+ }
+
+ private String readUTF(int index, final int utfLen, final char[] buf) {
+ int endIndex = index + utfLen;
+ byte[] b = this.b;
+ int strLen = 0;
+ int c;
+ int st = 0;
+ char cc = 0;
+ while (index < endIndex) {
+ c = b[index++];
+ switch (st) {
+ case 0:
+ c = c & 0xFF;
+ if (c < 0x80) { // 0xxxxxxx
+ buf[strLen++] = (char) c;
+ } else if (c < 0xE0 && c > 0xBF) { // 110x xxxx 10xx xxxx
+ cc = (char) (c & 0x1F);
+ st = 1;
+ } else { // 1110 xxxx 10xx xxxx 10xx xxxx
+ cc = (char) (c & 0x0F);
+ st = 2;
+ }
+ break;
+
+ case 1: // byte 2 of 2-byte char or byte 3 of 3-byte char
+ buf[strLen++] = (char) ((cc << 6) | (c & 0x3F));
+ st = 0;
+ break;
+
+ case 2: // byte 2 of 3-byte char
+ cc = (char) ((cc << 6) | (c & 0x3F));
+ st = 1;
+ break;
+ }
+ }
+ return new String(buf, 0, strLen);
+ }
+
+}
diff --git a/src/main/java/com/alibaba/fastjson/asm/ClassWriter.java b/src/main/java/com/alibaba/fastjson/asm/ClassWriter.java
old mode 100644
new mode 100755
index 08edae65fc..7bcf97bd56
--- a/src/main/java/com/alibaba/fastjson/asm/ClassWriter.java
+++ b/src/main/java/com/alibaba/fastjson/asm/ClassWriter.java
@@ -30,202 +30,10 @@
package com.alibaba.fastjson.asm;
/**
- * A {@link ClassVisitor} that generates classes in bytecode form. More precisely this visitor generates a byte array
- * conforming to the Java class file format. It can be used alone, to generate a Java class "from scratch", or with one
- * or more and adapter class visitor to generate a modified class from one or more existing Java classes.
*
* @author Eric Bruneton
*/
public class ClassWriter {
-
- /**
- * Flag to automatically compute the maximum stack size and the maximum number of local variables of methods. If
- * this flag is set, then the arguments of the {@link MethodVisitor#visitMaxs visitMaxs} method of the
- * {@link MethodVisitor} returned by the {@link #visitMethod visitMethod} method will be ignored, and computed
- * automatically from the signature and the bytecode of each method.
- *
- * @see #ClassWriter(int)
- */
- public static final int COMPUTE_MAXS = 1;
-
- /**
- * Flag to automatically compute the stack map frames of methods from scratch. If this flag is set, then the calls
- * to the {@link MethodVisitor#visitFrame} method are ignored, and the stack map frames are recomputed from the
- * methods bytecode. The arguments of the {@link MethodVisitor#visitMaxs visitMaxs} method are also ignored and
- * recomputed from the bytecode. In other words, computeFrames implies computeMaxs.
- *
- * @see #ClassWriter(int)
- */
- public static final int COMPUTE_FRAMES = 2;
-
- /**
- * Pseudo access flag to distinguish between the synthetic attribute and the synthetic access flag.
- */
- static final int ACC_SYNTHETIC_ATTRIBUTE = 0x40000;
-
- /**
- * The type of instructions without any argument.
- */
- static final int NOARG_INSN = 0;
-
- /**
- * The type of instructions with an signed byte argument.
- */
- static final int SBYTE_INSN = 1;
-
- /**
- * The type of instructions with an signed short argument.
- */
- static final int SHORT_INSN = 2;
-
- /**
- * The type of instructions with a local variable index argument.
- */
- static final int VAR_INSN = 3;
-
- /**
- * The type of instructions with an implicit local variable index argument.
- */
- static final int IMPLVAR_INSN = 4;
-
- /**
- * The type of instructions with a type descriptor argument.
- */
- static final int TYPE_INSN = 5;
-
- /**
- * The type of field and method invocations instructions.
- */
- static final int FIELDORMETH_INSN = 6;
-
- /**
- * The type of the INVOKEINTERFACE/INVOKEDYNAMIC instruction.
- */
- static final int ITFDYNMETH_INSN = 7;
-
- /**
- * The type of instructions with a 2 bytes bytecode offset label.
- */
- static final int LABEL_INSN = 8;
-
- /**
- * The type of instructions with a 4 bytes bytecode offset label.
- */
- static final int LABELW_INSN = 9;
-
- /**
- * The type of the LDC instruction.
- */
- static final int LDC_INSN = 10;
-
- /**
- * The type of the LDC_W and LDC2_W instructions.
- */
- static final int LDCW_INSN = 11;
-
- /**
- * The type of the IINC instruction.
- */
- static final int IINC_INSN = 12;
-
- /**
- * The type of the TABLESWITCH instruction.
- */
- static final int TABL_INSN = 13;
-
- /**
- * The type of the LOOKUPSWITCH instruction.
- */
- static final int LOOK_INSN = 14;
-
- /**
- * The type of the MULTIANEWARRAY instruction.
- */
- static final int MANA_INSN = 15;
-
- /**
- * The type of the WIDE instruction.
- */
- static final int WIDE_INSN = 16;
-
- /**
- * The instruction types of all JVM opcodes.
- */
- static final byte[] TYPE;
-
- /**
- * The type of CONSTANT_Class constant pool items.
- */
- static final int CLASS = 7;
-
- /**
- * The type of CONSTANT_Fieldref constant pool items.
- */
- static final int FIELD = 9;
-
- /**
- * The type of CONSTANT_Methodref constant pool items.
- */
- static final int METH = 10;
-
- /**
- * The type of CONSTANT_InterfaceMethodref constant pool items.
- */
- static final int IMETH = 11;
-
- /**
- * The type of CONSTANT_String constant pool items.
- */
- static final int STR = 8;
-
- /**
- * The type of CONSTANT_Integer constant pool items.
- */
- static final int INT = 3;
-
- /**
- * The type of CONSTANT_Float constant pool items.
- */
- static final int FLOAT = 4;
-
- /**
- * The type of CONSTANT_Long constant pool items.
- */
- static final int LONG = 5;
-
- /**
- * The type of CONSTANT_Double constant pool items.
- */
- static final int DOUBLE = 6;
-
- /**
- * The type of CONSTANT_NameAndType constant pool items.
- */
- static final int NAME_TYPE = 12;
-
- /**
- * The type of CONSTANT_Utf8 constant pool items.
- */
- static final int UTF8 = 1;
-
- /**
- * Normal type Item stored in the ClassWriter {@link ClassWriter#typeTable}, instead of the constant pool, in order
- * to avoid clashes with normal constant pool items in the ClassWriter constant pool's hash table.
- */
- static final int TYPE_NORMAL = 13;
-
- /**
- * Uninitialized type Item stored in the ClassWriter {@link ClassWriter#typeTable}, instead of the constant pool, in
- * order to avoid clashes with normal constant pool items in the ClassWriter constant pool's hash table.
- */
- static final int TYPE_UNINIT = 14;
-
- /**
- * Merged type Item stored in the ClassWriter {@link ClassWriter#typeTable}, instead of the constant pool, in order
- * to avoid clashes with normal constant pool items in the ClassWriter constant pool's hash table.
- */
- static final int TYPE_MERGED = 15;
-
/**
* Minor and major version numbers of the class to be generated.
*/
@@ -331,91 +139,6 @@ public class ClassWriter {
*/
MethodWriter lastMethod;
- // ------------------------------------------------------------------------
- // Static initializer
- // ------------------------------------------------------------------------
-
- /**
- * Computes the instruction types of JVM opcodes.
- */
- static {
- int i;
- byte[] b = new byte[220];
- String s = "AAAAAAAAAAAAAAAABCKLLDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD" + "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAIIIIIIIIIIIIIIIIDNOAA" + "AAAAGGGGGGGHHFBFAAFFAAQPIIJJIIIIIIIIIIIIIIIIII";
- for (i = 0; i < b.length; ++i) {
- b[i] = (byte) (s.charAt(i) - 'A');
- }
- TYPE = b;
-
- // code to generate the above string
- //
- // // SBYTE_INSN instructions
- // b[Constants.NEWARRAY] = SBYTE_INSN;
- // b[Constants.BIPUSH] = SBYTE_INSN;
- //
- // // SHORT_INSN instructions
- // b[Constants.SIPUSH] = SHORT_INSN;
- //
- // // (IMPL)VAR_INSN instructions
- // b[Constants.RET] = VAR_INSN;
- // for (i = Constants.ILOAD; i <= Constants.ALOAD; ++i) {
- // b[i] = VAR_INSN;
- // }
- // for (i = Constants.ISTORE; i <= Constants.ASTORE; ++i) {
- // b[i] = VAR_INSN;
- // }
- // for (i = 26; i <= 45; ++i) { // ILOAD_0 to ALOAD_3
- // b[i] = IMPLVAR_INSN;
- // }
- // for (i = 59; i <= 78; ++i) { // ISTORE_0 to ASTORE_3
- // b[i] = IMPLVAR_INSN;
- // }
- //
- // // TYPE_INSN instructions
- // b[Constants.NEW] = TYPE_INSN;
- // b[Constants.ANEWARRAY] = TYPE_INSN;
- // b[Constants.CHECKCAST] = TYPE_INSN;
- // b[Constants.INSTANCEOF] = TYPE_INSN;
- //
- // // (Set)FIELDORMETH_INSN instructions
- // for (i = Constants.GETSTATIC; i <= Constants.INVOKESTATIC; ++i) {
- // b[i] = FIELDORMETH_INSN;
- // }
- // b[Constants.INVOKEINTERFACE] = ITFDYNMETH_INSN;
- // b[Constants.INVOKEDYNAMIC] = ITFDYNMETH_INSN;
- //
- // // LABEL(W)_INSN instructions
- // for (i = Constants.IFEQ; i <= Constants.JSR; ++i) {
- // b[i] = LABEL_INSN;
- // }
- // b[Constants.IFNULL] = LABEL_INSN;
- // b[Constants.IFNONNULL] = LABEL_INSN;
- // b[200] = LABELW_INSN; // GOTO_W
- // b[201] = LABELW_INSN; // JSR_W
- // // temporary opcodes used internally by ASM - see Label and
- // MethodWriter
- // for (i = 202; i < 220; ++i) {
- // b[i] = LABEL_INSN;
- // }
- //
- // // LDC(_W) instructions
- // b[Constants.LDC] = LDC_INSN;
- // b[19] = LDCW_INSN; // LDC_W
- // b[20] = LDCW_INSN; // LDC2_W
- //
- // // special instructions
- // b[Constants.IINC] = IINC_INSN;
- // b[Constants.TABLESWITCH] = TABL_INSN;
- // b[Constants.LOOKUPSWITCH] = LOOK_INSN;
- // b[Constants.MULTIANEWARRAY] = MANA_INSN;
- // b[196] = WIDE_INSN; // WIDE
- //
- // for (i = 0; i < b.length; ++i) {
- // System.err.print((char)('A' + b[i]));
- // }
- // System.err.println();
- }
-
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
@@ -424,12 +147,6 @@ public ClassWriter(){
this(0);
}
- /**
- * Constructs a new {@link ClassWriter} object.
- *
- * @param flags option flags that can be used to modify the default behavior of this class. See
- * {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}.
- */
private ClassWriter(final int flags){
index = 1;
pool = new ByteVector();
@@ -447,29 +164,18 @@ private ClassWriter(final int flags){
public void visit(final int version, final int access, final String name, final String superName, final String[] interfaces) {
this.version = version;
this.access = access;
- this.name = newClass(name);
+ this.name = newClassItem(name).index;
thisName = name;
- this.superName = superName == null ? 0 : newClass(superName);
+ this.superName = superName == null ? 0 : newClassItem(superName).index;
if (interfaces != null && interfaces.length > 0) {
interfaceCount = interfaces.length;
this.interfaces = new int[interfaceCount];
for (int i = 0; i < interfaceCount; ++i) {
- this.interfaces[i] = newClass(interfaces[i]);
+ this.interfaces[i] = newClassItem(interfaces[i]).index;
}
}
}
- public FieldVisitor visitField(final int access, final String name, final String desc) {
- return new FieldWriter(this, access, name, desc);
- }
-
- public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) {
- return new MethodWriter(this, access, name, desc, signature, exceptions);
- }
-
- public void visitEnd() {
- }
-
// ------------------------------------------------------------------------
// Other public methods
// ------------------------------------------------------------------------
@@ -503,7 +209,7 @@ public byte[] toByteArray() {
ByteVector out = new ByteVector(size);
out.putInt(0xCAFEBABE).putInt(version);
out.putShort(index).putByteArray(pool.data, 0, pool.length);
- int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / (ClassWriter.ACC_SYNTHETIC_ATTRIBUTE / Opcodes.ACC_SYNTHETIC));
+ 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(superName);
out.putShort(interfaceCount);
for (int i = 0; i < interfaceCount; ++i) {
@@ -538,42 +244,49 @@ public byte[] toByteArray() {
* @return a new or already existing constant item with the given value.
*/
Item newConstItem(final Object cst) {
- if (cst instanceof String) {
+ if (cst instanceof Integer) {
+ int val = ((Integer) cst).intValue();
+ // return newInteger(val);
+ key.set(val);
+ Item result = get(key);
+ if (result == null) {
+ pool.putByte(3 /* INT */ ).putInt(val);
+ result = new Item(index++, key);
+ put(result);
+ }
+ return result;
+ } else if (cst instanceof String) {
return newString((String) cst);
} else if (cst instanceof Type) {
Type t = (Type) cst;
- return newClassItem(t.getSort() == Type.OBJECT ? t.getInternalName() : t.getDescriptor());
+ return newClassItem(t.sort == 10 /*Type.OBJECT*/ ? t.getInternalName() : t.getDescriptor());
} else {
throw new IllegalArgumentException("value " + cst);
}
}
public int newUTF8(final String value) {
- key.set(UTF8, value, null, null);
+ key.set(1 /* UTF8 */, value, null, null);
Item result = get(key);
if (result == null) {
- pool.putByte(UTF8).putUTF8(value);
+ pool.putByte(1 /* UTF8 */).putUTF8(value);
result = new Item(index++, key);
put(result);
}
return result.index;
}
- Item newClassItem(final String value) {
- key2.set(CLASS, value, null, null);
+ public Item newClassItem(final String value) {
+ key2.set(7 /* CLASS */, value, null, null);
Item result = get(key2);
if (result == null) {
- pool.put12(CLASS, newUTF8(value));
+ pool.put12(7 /* CLASS */, newUTF8(value));
result = new Item(index++, key2);
put(result);
}
return result;
}
- public int newClass(final String value) {
- return newClassItem(value).index;
- }
-
/**
* Adds a field reference to the constant pool of the class being build. Does nothing if the constant pool already
* contains a similar item.
@@ -584,10 +297,12 @@ public int newClass(final String value) {
* @return a new or already existing field reference item.
*/
Item newFieldItem(final String owner, final String name, final String desc) {
- key3.set(FIELD, owner, name, desc);
+ key3.set(9 /* FIELD */, owner, name, desc);
Item result = get(key3);
if (result == null) {
- put122(FIELD, newClass(owner), newNameType(name, desc));
+ // put122(9 /* FIELD */, newClassItem(owner).index, newNameTypeItem(name, desc).index);
+ int s1 = newClassItem(owner).index, s2 = newNameTypeItem(name, desc).index;
+ pool.put12(9 /* FIELD */, s1).putShort(s2);
result = new Item(index++, key3);
put(result);
}
@@ -605,65 +320,44 @@ Item newFieldItem(final String owner, final String name, final String desc) {
* @return a new or already existing method reference item.
*/
Item newMethodItem(final String owner, final String name, final String desc, final boolean itf) {
- int type = itf ? IMETH : METH;
+ int type = itf ? 11 /* IMETH */ : 10 /* METH */;
key3.set(type, owner, name, desc);
Item result = get(key3);
if (result == null) {
- put122(type, newClass(owner), newNameType(name, desc));
+ // put122(type, newClassItem(owner).index, newNameTypeItem(name, desc).index);
+ int s1 = newClassItem(owner).index, s2 = newNameTypeItem(name, desc).index;
+ pool.put12(type, s1).putShort(s2);
result = new Item(index++, key3);
put(result);
}
return result;
}
- /**
- * Adds a string to the constant pool of the class being build. Does nothing if the constant pool already contains a
- * similar item.
- *
- * @param value the String value.
- * @return a new or already existing string item.
- */
private Item newString(final String value) {
- key2.set(STR, value, null, null);
+ key2.set(8 /* STR */, value, null, null);
Item result = get(key2);
if (result == null) {
- pool.put12(STR, newUTF8(value));
+ pool.put12(8 /*STR*/, newUTF8(value));
result = new Item(index++, key2);
put(result);
}
return result;
}
- public int newNameType(final String name, final String desc) {
- return newNameTypeItem(name, desc).index;
- }
-
- /**
- * Adds a name and type to the constant pool of the class being build. Does nothing if the constant pool already
- * contains a similar item.
- *
- * @param name a name.
- * @param desc a type descriptor.
- * @return a new or already existing name and type item.
- */
- Item newNameTypeItem(final String name, final String desc) {
- key2.set(NAME_TYPE, name, desc, null);
+ public Item newNameTypeItem(final String name, final String desc) {
+ key2.set(12 /* NAME_TYPE */, name, desc, null);
Item result = get(key2);
if (result == null) {
- put122(NAME_TYPE, newUTF8(name), newUTF8(desc));
+ //put122(12 /* NAME_TYPE */, newUTF8(name), newUTF8(desc));
+ int s1 = newUTF8(name), s2 = newUTF8(desc);
+ pool.put12(12 /* NAME_TYPE */, s1).putShort(s2);
result = new Item(index++, key2);
put(result);
}
return result;
}
- /**
- * Returns the constant pool's hash table item which is equal to the given item.
- *
- * @param key a constant pool item.
- * @return the constant pool's hash table item which is equal to the given item, or null if there is no
- * such item.
- */
+
private Item get(final Item key) {
Item i = items[key.hashCode % items.length];
while (i != null && (i.type != key.type || !key.isEqualTo(i))) {
@@ -672,11 +366,6 @@ private Item get(final Item key) {
return i;
}
- /**
- * Puts the given item in the constant pool's hash table. The hash table must not already contains this item.
- *
- * @param i the item to be added to the constant pool's hash table.
- */
private void put(final Item i) {
if (index > threshold) {
int ll = items.length;
@@ -699,15 +388,4 @@ private void put(final Item i) {
i.next = items[index];
items[index] = i;
}
-
- /**
- * Puts one byte and two shorts into the constant pool.
- *
- * @param b a byte.
- * @param s1 a short.
- * @param s2 another short.
- */
- private void put122(final int b, final int s1, final int s2) {
- pool.put12(b, s1).putShort(s2);
- }
}
diff --git a/src/main/java/com/alibaba/fastjson/asm/FieldVisitor.java b/src/main/java/com/alibaba/fastjson/asm/FieldVisitor.java
deleted file mode 100644
index e14ff77c17..0000000000
--- a/src/main/java/com/alibaba/fastjson/asm/FieldVisitor.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/***
- * 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 visitor to visit a Java field. The methods of this interface must be called in the following order: (
- * visitAnnotation | visitAttribute )* visitEnd.
- *
- * @author Eric Bruneton
- */
-public interface FieldVisitor {
-
- /**
- * Visits the end of the field. This method, which is the last one to be called, is used to inform the visitor that
- * all the annotations and attributes of the field have been visited.
- */
- void visitEnd();
-}
diff --git a/src/main/java/com/alibaba/fastjson/asm/FieldWriter.java b/src/main/java/com/alibaba/fastjson/asm/FieldWriter.java
old mode 100644
new mode 100755
index 2a75dbf683..4a93009e4a
--- a/src/main/java/com/alibaba/fastjson/asm/FieldWriter.java
+++ b/src/main/java/com/alibaba/fastjson/asm/FieldWriter.java
@@ -30,15 +30,12 @@
package com.alibaba.fastjson.asm;
/**
- * An {@link FieldVisitor} that generates Java fields in bytecode form.
+ * An FieldWriter that generates Java fields in bytecode form.
*
* @author Eric Bruneton
*/
-final class FieldWriter implements FieldVisitor {
+public final class FieldWriter {
- /**
- * Next field writer (see {@link ClassWriter#firstField firstField}).
- */
FieldWriter next;
/**
@@ -60,17 +57,7 @@ final class FieldWriter implements FieldVisitor {
// Constructor
// ------------------------------------------------------------------------
- /**
- * Constructs a new {@link FieldWriter}.
- *
- * @param cw the class writer to which this field must be added.
- * @param access the field's access flags (see {@link Opcodes}).
- * @param name the field's name.
- * @param desc the field's descriptor (see {@link Type}).
- * @param signature the field's signature. May be null.
- * @param value the field's constant value. May be null.
- */
- FieldWriter(final ClassWriter cw, final int access, final String name, final String desc){
+ public FieldWriter(final ClassWriter cw, final int access, final String name, final String desc){
if (cw.firstField == null) {
cw.firstField = this;
} else {
@@ -108,7 +95,7 @@ int getSize() {
* @param out where the content of this field must be put.
*/
void put(final ByteVector out) {
- int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / (ClassWriter.ACC_SYNTHETIC_ATTRIBUTE / Opcodes.ACC_SYNTHETIC));
+ 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);
diff --git a/src/main/java/com/alibaba/fastjson/asm/Item.java b/src/main/java/com/alibaba/fastjson/asm/Item.java
old mode 100644
new mode 100755
index 1b1a559892..d941c41b47
--- a/src/main/java/com/alibaba/fastjson/asm/Item.java
+++ b/src/main/java/com/alibaba/fastjson/asm/Item.java
@@ -41,16 +41,6 @@ final class Item {
*/
int index;
- /**
- * Type of this constant pool item. A single class is used to represent all constant pool item types, in order to
- * minimize the bytecode size of this package. The value of this field is one of {@link ClassWriter#INT},
- * {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT}, {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8},
- * {@link ClassWriter#STR}, {@link ClassWriter#CLASS}, {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD},
- * {@link ClassWriter#METH}, {@link ClassWriter#IMETH}. Special Item types are used for Items that are stored in the
- * ClassWriter {@link ClassWriter#typeTable}, instead of the constant pool, in order to avoid clashes with normal
- * constant pool items in the ClassWriter constant pool's hash table. These special item types are
- * {@link ClassWriter#TYPE_NORMAL}, {@link ClassWriter#TYPE_UNINIT} and {@link ClassWriter#TYPE_MERGED}.
- */
int type;
/**
@@ -125,13 +115,13 @@ void set(final int type, final String strVal1, final String strVal2, final Strin
this.strVal2 = strVal2;
this.strVal3 = strVal3;
switch (type) {
- case ClassWriter.UTF8:
- case ClassWriter.STR:
- case ClassWriter.CLASS:
- case ClassWriter.TYPE_NORMAL:
+ case 1 /* ClassWriter.UTF8 */:
+ case 8 /* ClassWriter.STR */:
+ case 7 /* ClassWriter.CLASS */:
+ case 13 /* ClassWriter.TYPE_NORMAL */:
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
return;
- case ClassWriter.NAME_TYPE:
+ case 12 /* ClassWriter.NAME_TYPE */:
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode());
return;
// ClassWriter.FIELD:
@@ -141,6 +131,17 @@ void set(final int type, final String strVal1, final String strVal2, final Strin
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. This method assumes that the two items have the same
@@ -151,21 +152,19 @@ void set(final int type, final String strVal1, final String strVal2, final Strin
*/
boolean isEqualTo(final Item i) {
switch (type) {
- case ClassWriter.UTF8:
- case ClassWriter.STR:
- case ClassWriter.CLASS:
- case ClassWriter.TYPE_NORMAL:
+ case 1 /* ClassWriter.UTF8 */:
+ case 8 /* ClassWriter.STR */:
+ case 7 /* ClassWriter.CLASS */ :
+ case 13 /* ClassWriter.TYPE_NORMAL */ :
return i.strVal1.equals(strVal1);
- case ClassWriter.TYPE_MERGED:
- case ClassWriter.LONG:
- case ClassWriter.DOUBLE:
+ case 15 /* ClassWriter.TYPE_MERGED */ :
+ case 5 /* ClassWriter.LONG */ :
+ case 6 /* ClassWriter.DOUBLE */:
return i.longVal == longVal;
- case ClassWriter.INT:
- case ClassWriter.FLOAT:
+ case 3 /* ClassWriter.INT */ :
+ case 4 /* ClassWriter.FLOAT */:
return i.intVal == intVal;
- case ClassWriter.TYPE_UNINIT:
- return i.intVal == intVal && i.strVal1.equals(strVal1);
- case ClassWriter.NAME_TYPE:
+ case 12 /* ClassWriter.NAME_TYPE */:
return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2);
// case ClassWriter.FIELD:
// case ClassWriter.METH:
diff --git a/src/main/java/com/alibaba/fastjson/asm/Label.java b/src/main/java/com/alibaba/fastjson/asm/Label.java
old mode 100644
new mode 100755
index 5adbd03e1c..f37786b623
--- a/src/main/java/com/alibaba/fastjson/asm/Label.java
+++ b/src/main/java/com/alibaba/fastjson/asm/Label.java
@@ -38,26 +38,8 @@
* @author Eric Bruneton
*/
public class Label {
-
- /**
- * Indicates if the position of this label is known.
- */
- static final int RESOLVED = 2;
-
- /**
- * Field used to associate user information to a label. Warning: this field is used by the ASM tree package. In
- * order to use it with the ASM tree package you must override the
- * {@link com.alibaba.fastjson.asm.tree.MethodNode#getLabelNode} method.
- */
- public Object info;
-
int status;
- /**
- * The line number corresponding to this label, if known.
- */
- int line;
-
/**
* The position of this label in the code, if known.
*/
@@ -74,7 +56,7 @@ public class Label {
* reference, while the second is the position of the first byte of the forward reference itself. In fact the sign
* of the first integer indicates if this reference uses 2 or 4 bytes, and its absolute value gives the position of
* the bytecode instruction. This array is also used as a bitset to store the subroutines to which a basic block
- * belongs. This information is needed in {@linked MethodWriter#visitMaxs}, after all forward references have been
+ * belongs. This information is needed in MethodWriter#visitMaxs, after all forward references have been
* resolved. Hence the same array can be used for both purposes without problems.
*/
private int[] srcAndRefPositions;
@@ -90,7 +72,7 @@ public class Label {
* stack map frames are similar and use two steps. The first step, during the visit of each instruction, builds
* information about the state of the local variables and the operand stack at the end of each basic block, called
* the "output frame", relatively to the frame state at the beginning of the basic block, which is called the
- * "input frame", and which is unknown during this step. The second step, in {@link MethodWriter#visitMaxs},
+ * "input frame", and which is unknown during this step. The second step, in link MethodWriter#visitMaxs,
* is a fix point algorithm that computes information about the input frame of each basic block, from the input
* state of the first basic block (known from the method signature), and by the using the previously computed
* relative output frames. The algorithm used to compute the maximum stack size only computes the relative output
@@ -117,7 +99,7 @@ public class Label {
/**
* The successor of this label, in the order they are visited. This linked list does not include labels used for
- * debug info only. If {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it does not contain
+ * debug info only. If ClassWriter#COMPUTE_FRAMES option is used then, in addition, it does not contain
* successive labels that denote the same bytecode position (in this case only the first label appears in this
* list).
*/
@@ -159,7 +141,7 @@ public Label(){
* @throws IllegalArgumentException if this label has not been created by the given code writer.
*/
void put(final MethodWriter owner, final ByteVector out, final int source) {
- if ((status & RESOLVED) == 0) {
+ if ((status & 2 /* RESOLVED */ ) == 0) {
addReference(source, out.length);
out.putShort(-1);
} else {
@@ -204,45 +186,18 @@ private void addReference(final int sourcePosition, final int referencePosition)
* @throws IllegalArgumentException if this label has already been resolved, or if it has not been created by the
* given code writer.
*/
- boolean resolve(final MethodWriter owner, final int position, final byte[] data) {
- boolean needUpdate = false;
- this.status |= RESOLVED;
+ void resolve(final MethodWriter owner, final int position, final byte[] data) {
+ this.status |= 2 /* RESOLVED */ ;
this.position = position;
int i = 0;
while (i < referenceCount) {
int source = srcAndRefPositions[i++];
int reference = srcAndRefPositions[i++];
- int offset;
- if (source >= 0) {
- offset = position - source;
- if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) {
- /*
- * changes the opcode of the jump instruction, in order to be able to find it later (see
- * resizeInstructions in MethodWriter). These temporary opcodes are similar to jump instruction
- * opcodes, except that the 2 bytes offset is unsigned (and can therefore represent values from 0 to
- * 65535, which is sufficient since the size of a method is limited to 65535 bytes).
- */
- int opcode = data[reference - 1] & 0xFF;
- if (opcode <= Opcodes.JSR) {
- // changes IFEQ ... JSR to opcodes 202 to 217
- data[reference - 1] = (byte) (opcode + 49);
- } else {
- // changes IFNULL and IFNONNULL to opcodes 218 and 219
- data[reference - 1] = (byte) (opcode + 20);
- }
- needUpdate = true;
- }
- data[reference++] = (byte) (offset >>> 8);
- data[reference] = (byte) offset;
- } else {
- offset = position + source + 1;
- data[reference++] = (byte) (offset >>> 24);
- data[reference++] = (byte) (offset >>> 16);
- data[reference++] = (byte) (offset >>> 8);
- data[reference] = (byte) offset;
- }
+ int offset = position - source;
+ data[reference++] = (byte) (offset >>> 8);
+ data[reference] = (byte) offset;
+
}
- return needUpdate;
}
}
diff --git a/src/main/java/com/alibaba/fastjson/asm/MethodCollector.java b/src/main/java/com/alibaba/fastjson/asm/MethodCollector.java
new file mode 100644
index 0000000000..4af294edf0
--- /dev/null
+++ b/src/main/java/com/alibaba/fastjson/asm/MethodCollector.java
@@ -0,0 +1,41 @@
+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 StringBuffer result;
+
+ protected boolean debugInfoPresent;
+
+ protected MethodCollector(int ignoreCount, int paramCount) {
+ this.ignoreCount = ignoreCount;
+ this.paramCount = paramCount;
+ this.result = new StringBuffer();
+ 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
diff --git a/src/main/java/com/alibaba/fastjson/asm/MethodVisitor.java b/src/main/java/com/alibaba/fastjson/asm/MethodVisitor.java
old mode 100644
new mode 100755
index 1c916ddd16..e32a216de6
--- a/src/main/java/com/alibaba/fastjson/asm/MethodVisitor.java
+++ b/src/main/java/com/alibaba/fastjson/asm/MethodVisitor.java
@@ -30,15 +30,6 @@
package com.alibaba.fastjson.asm;
/**
- * A visitor to visit a Java method. The methods of this interface must be called in the following order: [
- * visitAnnotationDefault ] ( visitAnnotation | visitParameterAnnotation |
- * visitAttribute )* [ visitCode ( visitFrame | visitXInsn |
- * visitLabel | visitTryCatchBlock | visitLocalVariable | visitLineNumber)*
- * visitMaxs ] visitEnd. In addition, the visitXInsn and visitLabel
- * methods must be called in the sequential order of the bytecode instructions of the visited code,
- * visitTryCatchBlock must be called before the labels passed as arguments have been visited, and the
- * visitLocalVariable and visitLineNumber methods must be called after the labels passed as
- * arguments have been visited.
*
* @author Eric Bruneton
*/
@@ -66,17 +57,6 @@ public interface MethodVisitor {
*/
void visitInsn(int opcode);
- /**
- * Visits an instruction with a single int operand.
- *
- * @param opcode the opcode of the instruction to be visited. This opcode is either BIPUSH, SIPUSH or NEWARRAY.
- * @param operand the operand of the instruction to be visited.
- * When opcode is BIPUSH, operand value should be between Byte.MIN_VALUE and Byte.MAX_VALUE.
- * When opcode is SIPUSH, operand value should be between Short.MIN_VALUE and Short.MAX_VALUE.
- * When opcode is NEWARRAY, operand value should be one of {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR},
- * {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT},
- * {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}.
- */
void visitIntInsn(int opcode, int operand);
/**
@@ -112,16 +92,6 @@ public interface MethodVisitor {
*/
void visitFieldInsn(int opcode, String owner, String name, String desc);
- /**
- * Visits a method instruction. A method instruction is an instruction that invokes a method.
- *
- * @param opcode the opcode of the type instruction to be visited. This opcode is either INVOKEVIRTUAL,
- * INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE or INVOKEDYNAMIC.
- * @param owner the internal name of the method's owner class (see {@link Type#getInternalName() getInternalName})
- * or {@link com.alibaba.fastjson.asm.Opcodes#INVOKEDYNAMIC_OWNER}.
- * @param name the method's name.
- * @param desc the method's descriptor (see {@link Type Type}).
- */
void visitMethodInsn(int opcode, String owner, String name, String desc);
/**
diff --git a/src/main/java/com/alibaba/fastjson/asm/MethodWriter.java b/src/main/java/com/alibaba/fastjson/asm/MethodWriter.java
old mode 100644
new mode 100755
index 4ec9776ce0..1cd633d2e0
--- a/src/main/java/com/alibaba/fastjson/asm/MethodWriter.java
+++ b/src/main/java/com/alibaba/fastjson/asm/MethodWriter.java
@@ -30,62 +30,10 @@
package com.alibaba.fastjson.asm;
/**
- * A {@link MethodVisitor} that generates methods in bytecode form. Each visit method of this class appends the bytecode
- * corresponding to the visited instruction to a byte vector, in the order these methods are called.
- *
* @author Eric Bruneton
* @author Eugene Kuleshov
*/
-class MethodWriter implements MethodVisitor {
-
- /**
- * Pseudo access flag used to denote constructors.
- */
- static final int ACC_CONSTRUCTOR = 262144;
-
- /**
- * Frame has exactly the same locals as the previous stack map frame and number of stack items is zero.
- */
- static final int SAME_FRAME = 0; // to 63 (0-3f)
-
- /**
- * Frame has exactly the same locals as the previous stack map frame and number of stack items is 1
- */
- static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 (40-7f)
-
- /**
- * Reserved for future use
- */
- static final int RESERVED = 128;
-
- /**
- * Frame has exactly the same locals as the previous stack map frame and number of stack items is 1. Offset is
- * bigger then 63;
- */
- static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7
-
- /**
- * Frame where current locals are the same as the locals in the previous frame, except that the k last locals are
- * absent. The value of k is given by the formula 251-frame_type.
- */
- static final int CHOP_FRAME = 248; // to 250 (f8-fA)
-
- /**
- * Frame has exactly the same locals as the previous stack map frame and number of stack items is zero. Offset is
- * bigger then 63;
- */
- static final int SAME_FRAME_EXTENDED = 251; // fb
-
- /**
- * Frame where current locals are the same as the locals in the previous frame, except that k additional locals are
- * defined. The value of k is given by the formula frame_type-251.
- */
- static final int APPEND_FRAME = 252; // to 254 // fc-fe
-
- /**
- * Full frame
- */
- static final int FULL_FRAME = 255; // ff
+public class MethodWriter implements MethodVisitor {
/**
* Next method writer (see {@link ClassWriter#firstMethod firstMethod}).
@@ -112,12 +60,6 @@ class MethodWriter implements MethodVisitor {
*/
private final int desc;
- /**
- * If not zero, indicates that the code of this method must be copied from the ClassReader associated to this writer
- * in cw.cr
. More precisely, this field gives the number of bytes to copied from cw.cr.b
.
- */
- int classReaderLength;
-
/**
* Number of exceptions that can be thrown by this method.
*/
@@ -144,11 +86,6 @@ class MethodWriter implements MethodVisitor {
*/
private int maxLocals;
- /**
- * Indicates if some jump instructions are too small and need to be resized.
- */
- private boolean resize;
-
// ------------------------------------------------------------------------
/*
@@ -162,20 +99,7 @@ class MethodWriter implements MethodVisitor {
// Constructor
// ------------------------------------------------------------------------
- /**
- * Constructs a new {@link MethodWriter}.
- *
- * @param cw the class writer in which the method must be added.
- * @param access the method's access flags (see {@link Opcodes}).
- * @param name the method's name.
- * @param desc the method's descriptor (see {@link Type}).
- * @param signature the method's signature. May be null.
- * @param exceptions the internal names of the method's exceptions. May be null.
- * @param computeMaxs true if the maximum stack size and number of local variables must be automatically
- * computed.
- * @param computeFrames true if the stack map tables must be recomputed from scratch.
- */
- MethodWriter(final ClassWriter cw, final int access, final String name, final String desc, final String signature, final String[] exceptions){
+ public MethodWriter(final ClassWriter cw, final int access, final String name, final String desc, final String signature, final String[] exceptions){
if (cw.firstMethod == null) {
cw.firstMethod = this;
} else {
@@ -191,7 +115,7 @@ class MethodWriter implements MethodVisitor {
exceptionCount = exceptions.length;
this.exceptions = new int[exceptionCount];
for (int i = 0; i < exceptionCount; ++i) {
- this.exceptions[i] = cw.newClass(exceptions[i]);
+ this.exceptions[i] = cw.newClassItem(exceptions[i]).index;
}
}
}
@@ -271,7 +195,7 @@ public void visitMethodInsn(final int opcode, final String owner, final String n
public void visitJumpInsn(final int opcode, final Label label) {
// Label currentBlock = this.currentBlock;
// adds the instruction to the bytecode of the method
- if ((label.status & Label.RESOLVED) != 0 && label.position - code.length < Short.MIN_VALUE) {
+ if ((label.status & 2 /* Label.RESOLVED */ ) != 0 && label.position - code.length < Short.MIN_VALUE) {
throw new UnsupportedOperationException();
} else {
/*
@@ -286,7 +210,7 @@ public void visitJumpInsn(final int opcode, final Label label) {
public void visitLabel(final Label label) {
// resolves previous forward references to label, if any
- resize |= label.resolve(this, code.length, code.data);
+ label.resolve(this, code.length, code.data);
}
public void visitLdcInsn(final Object cst) {
@@ -294,22 +218,22 @@ public void visitLdcInsn(final Object cst) {
// Label currentBlock = this.currentBlock;
// adds the instruction to the bytecode of the method
int index = i.index;
- if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
+ if (i.type == 5 /* ClassWriter.LONG */ || i.type == 6 /* ClassWriter.DOUBLE */) {
code.put12(20 /* LDC2_W */, index);
} else if (index >= 256) {
code.put12(19 /* LDC_W */, index);
} else {
- code.put11(Opcodes.LDC, index);
+ code.put11(18 /*Opcodes.LDC*/, index);
}
}
public void visitIincInsn(final int var, final int increment) {
// adds the instruction to the bytecode of the method
- if ((var > 255) || (increment > 127) || (increment < -128)) {
- code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var).putShort(increment);
- } else {
- code.putByte(Opcodes.IINC).put11(var, increment);
- }
+// if ((var > 255) || (increment > 127) || (increment < -128)) {
+// code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var).putShort(increment);
+// } else {
+ code.putByte(132 /* Opcodes.IINC*/ ).put11(var, increment);
+// }
}
public void visitMaxs(final int maxStack, final int maxLocals) {
@@ -338,10 +262,6 @@ public void visitEnd() {
* @return the size of the bytecode of this method.
*/
final int getSize() {
- if (resize) {
- // replaces the temporary jump opcodes introduced by Label.resolve.
- throw new UnsupportedOperationException();
- }
int size = 8;
if (code.length > 0) {
cw.newUTF8("Code");
@@ -360,7 +280,7 @@ final int getSize() {
* @param out the byte vector into which the bytecode of this method must be copied.
*/
final void put(final ByteVector out) {
- int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / (ClassWriter.ACC_SYNTHETIC_ATTRIBUTE / Opcodes.ACC_SYNTHETIC));
+ 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;
if (code.length > 0) {
diff --git a/src/main/java/com/alibaba/fastjson/asm/Opcodes.java b/src/main/java/com/alibaba/fastjson/asm/Opcodes.java
old mode 100644
new mode 100755
index cc9e9b6ac5..3440da9804
--- a/src/main/java/com/alibaba/fastjson/asm/Opcodes.java
+++ b/src/main/java/com/alibaba/fastjson/asm/Opcodes.java
@@ -39,6 +39,7 @@
* @author Eugene Kuleshov
*/
public interface Opcodes {
+ int T_INT = 10;
// versions
@@ -53,59 +54,20 @@ public interface Opcodes {
// access flags
int ACC_PUBLIC = 0x0001; // class, field, method
- int ACC_PRIVATE = 0x0002; // class, field, method
int ACC_SUPER = 0x0020; // class
- int ACC_SYNTHETIC = 0x1000; // class, field, method
-
- // ASM specific pseudo access flags
-
- int ACC_DEPRECATED = 0x20000; // class, field, method
-
- // types for NEWARRAY
-
- int T_BOOLEAN = 4;
- int T_CHAR = 5;
- int T_FLOAT = 6;
- int T_DOUBLE = 7;
- int T_BYTE = 8;
- int T_SHORT = 9;
- int T_INT = 10;
- int T_LONG = 11;
-
- // Integer TOP = new Integer(0);
- // Integer INTEGER = new Integer(1);
- // Integer FLOAT = new Integer(2);
- // Integer DOUBLE = new Integer(3);
- // Integer LONG = new Integer(4);
- // Integer NULL = new Integer(5);
- // Integer UNINITIALIZED_THIS = new Integer(6);
-
- /**
- * Represents a owner of an invokedynamic call.
- */
- String INVOKEDYNAMIC_OWNER = "java/lang/dyn/Dynamic";
// opcodes // visit method (- = idem)
- int NOP = 0; // visitInsn
int ACONST_NULL = 1; // -
- int ICONST_M1 = 2; // -
int ICONST_0 = 3; // -
int ICONST_1 = 4; // -
- int ICONST_2 = 5; // -
- int ICONST_3 = 6; // -
- int ICONST_4 = 7; // -
- int ICONST_5 = 8; // -
int LCONST_0 = 9; // -
int LCONST_1 = 10; // -
int FCONST_0 = 11; // -
- int FCONST_1 = 12; // -
- int FCONST_2 = 13; // -
int DCONST_0 = 14; // -
- int DCONST_1 = 15; // -
int BIPUSH = 16; // visitIntInsn
-// int SIPUSH = 17; // -
- int LDC = 18; // visitLdcInsn
+ // int SIPUSH = 17; // -
+// int LDC = 18; // visitLdcInsn
// int LDC_W = 19; // -
// int LDC2_W = 20; // -
int ILOAD = 21; // visitVarInsn
@@ -113,160 +75,48 @@ public interface Opcodes {
int FLOAD = 23; // -
int DLOAD = 24; // -
int ALOAD = 25; // -
- // int ILOAD_0 = 26; // -
- // int ILOAD_1 = 27; // -
- // int ILOAD_2 = 28; // -
- // int ILOAD_3 = 29; // -
- // int LLOAD_0 = 30; // -
- // int LLOAD_1 = 31; // -
- // int LLOAD_2 = 32; // -
- // int LLOAD_3 = 33; // -
- // int FLOAD_0 = 34; // -
- // int FLOAD_1 = 35; // -
- // int FLOAD_2 = 36; // -
- // int FLOAD_3 = 37; // -
- // int DLOAD_0 = 38; // -
- // int DLOAD_1 = 39; // -
- // int DLOAD_2 = 40; // -
- // int DLOAD_3 = 41; // -
- // int ALOAD_0 = 42; // -
- // int ALOAD_1 = 43; // -
- // int ALOAD_2 = 44; // -
- // int ALOAD_3 = 45; // -
- int IALOAD = 46; // visitInsn
- int LALOAD = 47; // -
- int FALOAD = 48; // -
- int DALOAD = 49; // -
- int AALOAD = 50; // -
- int BALOAD = 51; // -
- int CALOAD = 52; // -
- int SALOAD = 53; // -
+
int ISTORE = 54; // visitVarInsn
int LSTORE = 55; // -
int FSTORE = 56; // -
int DSTORE = 57; // -
int ASTORE = 58; // -
- // int ISTORE_0 = 59; // -
- // int ISTORE_1 = 60; // -
- // int ISTORE_2 = 61; // -
- // int ISTORE_3 = 62; // -
- // int LSTORE_0 = 63; // -
- // int LSTORE_1 = 64; // -
- // int LSTORE_2 = 65; // -
- // int LSTORE_3 = 66; // -
- // int FSTORE_0 = 67; // -
- // int FSTORE_1 = 68; // -
- // int FSTORE_2 = 69; // -
- // int FSTORE_3 = 70; // -
- // int DSTORE_0 = 71; // -
- // int DSTORE_1 = 72; // -
- // int DSTORE_2 = 73; // -
- // int DSTORE_3 = 74; // -
- // int ASTORE_0 = 75; // -
- // int ASTORE_1 = 76; // -
- // int ASTORE_2 = 77; // -
- // int ASTORE_3 = 78; // -
- // int IASTORE = 79; // visitInsn
- // int LASTORE = 80; // -
- // int FASTORE = 81; // -
- // int DASTORE = 82; // -
- // int AASTORE = 83; // -
- // int BASTORE = 84; // -
- // int CASTORE = 85; // -
- // int SASTORE = 86; // -
+ int IASTORE = 79; // visitInsn
+
int POP = 87; // -
- int POP2 = 88; // -
+// int POP2 = 88; // -
int DUP = 89; // -
-// int DUP_X1 = 90; // -
-// int DUP_X2 = 91; // -
-// int DUP2 = 92; // -
-// int DUP2_X1 = 93; // -
-// int DUP2_X2 = 94; // -
-// int SWAP = 95; // -
+
int IADD = 96; // -
- int LADD = 97; // -
-// int FADD = 98; // -
-// int DADD = 99; // -
- int ISUB = 100; // -
-// int LSUB = 101; // -
-// int FSUB = 102; // -
-// int DSUB = 103; // -
-// int IMUL = 104; // -
-// int LMUL = 105; // -
-// int FMUL = 106; // -
-// int DMUL = 107; // -
-// int IDIV = 108; // -
-// int LDIV = 109; // -
-// int FDIV = 110; // -
-// int DDIV = 111; // -
-// int IREM = 112; // -
-// int LREM = 113; // -
-// int FREM = 114; // -
-// int DREM = 115; // -
-// int INEG = 116; // -
-// int LNEG = 117; // -
-// int FNEG = 118; // -
-// int DNEG = 119; // -
-// int ISHL = 120; // -
-// int LSHL = 121; // -
-// int ISHR = 122; // -
-// int LSHR = 123; // -
-// int IUSHR = 124; // -
-// int LUSHR = 125; // -
-// int IAND = 126; // -
-// int LAND = 127; // -
-// int IOR = 128; // -
-// int LOR = 129; // -
-// int IXOR = 130; // -
-// int LXOR = 131; // -
- int IINC = 132; // visitIincInsn
-// int I2L = 133; // visitInsn
-// int I2F = 134; // -
-// int I2D = 135; // -
-// int L2I = 136; // -
-// int L2F = 137; // -
-// int L2D = 138; // -
-// int F2I = 139; // -
-// int F2L = 140; // -
-// int F2D = 141; // -
-// int D2I = 142; // -
-// int D2L = 143; // -
-// int D2F = 144; // -
- int I2B = 145; // -
- int I2C = 146; // -
- int I2S = 147; // -
+
+// 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 FCMPG = 150; // -
int DCMPL = 151; // -
- int DCMPG = 152; // -
int IFEQ = 153; // visitJumpInsn
int IFNE = 154; // -
- int IFLT = 155; // -
- int IFGE = 156; // -
- int IFGT = 157; // -
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_ICMPLE = 164; // -
int IF_ACMPEQ = 165; // -
int IF_ACMPNE = 166; // -
int GOTO = 167; // -
- int JSR = 168; // -
int RET = 169; // visitVarInsn
-// int TABLESWITCH = 170; // visiTableSwitchInsn
-// int LOOKUPSWITCH = 171; // visitLookupSwitch
- int IRETURN = 172; // visitInsn
-// int LRETURN = 173; // -
-// int FRETURN = 174; // -
-// int DRETURN = 175; // -
int ARETURN = 176; // -
int RETURN = 177; // -
int GETSTATIC = 178; // visitFieldInsn
- int PUTSTATIC = 179; // -
int GETFIELD = 180; // -
int PUTFIELD = 181; // -
int INVOKEVIRTUAL = 182; // visitMethodInsn
@@ -275,16 +125,13 @@ public interface Opcodes {
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 NEWARRAY = 188; // visitIntInsn
+ // int ANEWARRAY = 189; // visitTypeInsn
+ // int ARRAYLENGTH = 190; // visitInsn
+ // int ATHROW = 191; // -
int CHECKCAST = 192; // visitTypeInsn
- int INSTANCEOF = 193; // -
-// int MONITORENTER = 194; // visitInsn
-// int MONITOREXIT = 195; // -
- // int WIDE = 196; // NOT VISITED
-// int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn
+ int INSTANCEOF = 193;
+
int IFNULL = 198; // visitJumpInsn
int IFNONNULL = 199; // -
// int GOTO_W = 200; // -
diff --git a/src/main/java/com/alibaba/fastjson/asm/Type.java b/src/main/java/com/alibaba/fastjson/asm/Type.java
old mode 100644
new mode 100755
index cfc0751724..4a5da99996
--- a/src/main/java/com/alibaba/fastjson/asm/Type.java
+++ b/src/main/java/com/alibaba/fastjson/asm/Type.java
@@ -36,106 +36,50 @@
* @author Chris Nokleberg
*/
public class Type {
-
- /**
- * The sort of the void type. See {@link #getSort getSort}.
- */
- public static final int VOID = 0;
-
- /**
- * The sort of the boolean type. See {@link #getSort getSort}.
- */
- public static final int BOOLEAN = 1;
-
- /**
- * The sort of the char type. See {@link #getSort getSort}.
- */
- public static final int CHAR = 2;
-
- /**
- * The sort of the byte type. See {@link #getSort getSort}.
- */
- public static final int BYTE = 3;
-
- /**
- * The sort of the short type. See {@link #getSort getSort}.
- */
- public static final int SHORT = 4;
-
- /**
- * The sort of the int type. See {@link #getSort getSort}.
- */
- public static final int INT = 5;
-
- /**
- * The sort of the float type. See {@link #getSort getSort}.
- */
- public static final int FLOAT = 6;
-
- /**
- * The sort of the long type. See {@link #getSort getSort}.
- */
- public static final int LONG = 7;
-
- /**
- * The sort of the double type. See {@link #getSort getSort}.
- */
- public static final int DOUBLE = 8;
-
- /**
- * The sort of array reference types. See {@link #getSort getSort}.
- */
- public static final int ARRAY = 9;
-
- /**
- * The sort of object reference type. See {@link #getSort getSort}.
- */
- public static final int OBJECT = 10;
-
/**
* The void type.
*/
- public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24) | (5 << 16) | (0 << 8) | 0, 1);
+ public static final Type VOID_TYPE = new Type(0, null, ('V' << 24) | (5 << 16) | (0 << 8) | 0, 1);
/**
* The boolean type.
*/
- public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24) | (0 << 16) | (5 << 8) | 1, 1);
+ public static final Type BOOLEAN_TYPE = new Type(1, null, ('Z' << 24) | (0 << 16) | (5 << 8) | 1, 1);
/**
* The char type.
*/
- public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24) | (0 << 16) | (6 << 8) | 1, 1);
+ public static final Type CHAR_TYPE = new Type(2, null, ('C' << 24) | (0 << 16) | (6 << 8) | 1, 1);
/**
* The byte type.
*/
- public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24) | (0 << 16) | (5 << 8) | 1, 1);
+ public static final Type BYTE_TYPE = new Type(3, null, ('B' << 24) | (0 << 16) | (5 << 8) | 1, 1);
/**
* The short type.
*/
- public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24) | (0 << 16) | (7 << 8) | 1, 1);
+ public static final Type SHORT_TYPE = new Type(4, null, ('S' << 24) | (0 << 16) | (7 << 8) | 1, 1);
/**
* The int type.
*/
- public static final Type INT_TYPE = new Type(INT, null, ('I' << 24) | (0 << 16) | (0 << 8) | 1, 1);
+ public static final Type INT_TYPE = new Type(5, null, ('I' << 24) | (0 << 16) | (0 << 8) | 1, 1);
/**
* The float type.
*/
- public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24) | (2 << 16) | (2 << 8) | 1, 1);
+ public static final Type FLOAT_TYPE = new Type(6, null, ('F' << 24) | (2 << 16) | (2 << 8) | 1, 1);
/**
* The long type.
*/
- public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24) | (1 << 16) | (1 << 8) | 2, 1);
+ public static final Type LONG_TYPE = new Type(7, null, ('J' << 24) | (1 << 16) | (1 << 8) | 2, 1);
/**
* The double type.
*/
- public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24) | (3 << 16) | (3 << 8) | 2, 1);
+ public static final Type DOUBLE_TYPE = new Type(8, null, ('D' << 24) | (3 << 16) | (3 << 8) | 2, 1);
// ------------------------------------------------------------------------
// Fields
@@ -144,7 +88,7 @@ public class Type {
/**
* The sort of this Java type.
*/
- private final int sort;
+ protected final int sort;
/**
* A buffer containing the internal name of this Java type. This field is only used for reference types.
@@ -167,14 +111,6 @@ public class Type {
// Constructors
// ------------------------------------------------------------------------
- /**
- * Constructs a reference type.
- *
- * @param sort the sort of the reference type to be constructed.
- * @param buf a buffer containing the descriptor of the previous type.
- * @param off the offset of this descriptor in the previous buffer.
- * @param len the length of this descriptor.
- */
private Type(final int sort, final char[] buf, final int off, final int len){
this.sort = sort;
this.buf = buf;
@@ -192,14 +128,6 @@ public static Type getType(final String typeDescriptor) {
return getType(typeDescriptor.toCharArray(), 0);
}
- /**
- * Computes the size of the arguments and of the return value of a method.
- *
- * @param desc the descriptor of a method.
- * @return the size of the arguments of the method (plus one for the implicit this argument), argSize, and the size
- * of its return value, retSize, packed into a single int i = (argSize << 2) | retSize (argSize is
- * therefore equal to i >> 2, and retSize to i & 0x03).
- */
public static int getArgumentsAndReturnSizes(final String desc) {
int n = 1;
int c = 1;
@@ -212,13 +140,13 @@ public static int getArgumentsAndReturnSizes(final String desc) {
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 == '[') {
+// while ((car = desc.charAt(c)) == '[') {
+// ++c;
+// }
+// if (car == 'D' || car == 'J') {
+// n -= 1;
+// }
} else if (car == 'D' || car == 'J') {
n += 2;
} else {
@@ -266,39 +194,17 @@ private static Type getType(final char[] buf, final int off) {
++len;
}
}
- return new Type(ARRAY, buf, off, len + 1);
+ return new Type(9 /*ARRAY*/, buf, off, len + 1);
// case 'L':
default:
len = 1;
while (buf[off + len] != ';') {
++len;
}
- return new Type(OBJECT, buf, off + 1, len - 1);
+ return new Type(10/*OBJECT*/, buf, off + 1, len - 1);
}
}
- // ------------------------------------------------------------------------
- // Accessors
- // ------------------------------------------------------------------------
-
- /**
- * Returns the sort of this Java type.
- *
- * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, {@link #CHAR CHAR}, {@link #BYTE BYTE}, {@link #SHORT
- * SHORT}, {@link #INT INT}, {@link #FLOAT FLOAT}, {@link #LONG LONG}, {@link #DOUBLE DOUBLE}, {@link #ARRAY ARRAY}
- * or {@link #OBJECT OBJECT}.
- */
- public int getSort() {
- return sort;
- }
-
- /**
- * Returns the internal name of the class corresponding to this object or array type. The internal name of a class
- * is its fully qualified name (as returned by Class.getName(), where '.' are replaced by '/'. This method should
- * only be used for an object or array type.
- *
- * @return the internal name of the class corresponding to this object type.
- */
public String getInternalName() {
return new String(buf, off, len);
}
@@ -309,23 +215,79 @@ public String getInternalName() {
/**
* Returns the descriptor corresponding to this Java type.
- *
+ *
* @return the descriptor corresponding to this Java type.
*/
- public String getDescriptor() {
- StringBuffer buf = new StringBuffer();
+ String getDescriptor() {
+ return new String(this.buf, off, len);
+ }
- if (this.buf == null) {
- // descriptor is in byte 3 of 'off' for primitive types (buf == null)
- buf.append((char) ((off & 0xFF000000) >>> 24));
- } else if (sort == ARRAY) {
- buf.append(this.buf, off, len);
- } else { // sort == OBJECT
- buf.append('L');
- buf.append(this.buf, off, len);
- buf.append(';');
+ private int getDimensions() {
+ int i = 1;
+ while (buf[off + i] == '[') {
+ ++i;
}
+ return i;
+ }
- return buf.toString();
+ 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());
+ StringBuffer b = new StringBuffer(elementType.getClassName());
+ for (int i = getDimensions(); i > 0; --i) {
+ b.append("[]");
+ }
+ return b.toString();
+ // case OBJECT:
+ default:
+ return new String(buf, off, len).replace('/', '.');
+ }
}
}
diff --git a/src/main/java/com/alibaba/fastjson/asm/TypeCollector.java b/src/main/java/com/alibaba/fastjson/asm/TypeCollector.java
new file mode 100644
index 0000000000..32f82b94d4
--- /dev/null
+++ b/src/main/java/com/alibaba/fastjson/asm/TypeCollector.java
@@ -0,0 +1,89 @@
+package com.alibaba.fastjson.asm;
+
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Map;
+
+public class TypeCollector {
+ private static final Map primitives = new HashMap() {
+ {
+ 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;
+
+ 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);
+ }
+
+ private boolean correctTypeName(Type type, String paramTypeName) {
+ String s = type.getClassName();
+ // array notation needs cleanup.
+ String braces = "";
+ while (s.endsWith("[]")) {
+ braces = braces + "[";
+ s = s.substring(0, s.length() - 2);
+ }
+ if (!braces.equals("")) {
+ if (primitives.containsKey(s)) {
+ s = braces + primitives.get(s);
+ } else {
+ s = braces + "L" + s + ";";
+ }
+ }
+ return s.equals(paramTypeName);
+ }
+
+ public String[] getParameterNamesForMethod() {
+ if (collector == null || !collector.debugInfoPresent) {
+ return new String[0];
+ }
+ return collector.getResult().split(",");
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/alibaba/fastjson/asm/package.html b/src/main/java/com/alibaba/fastjson/asm/package.html
deleted file mode 100644
index fd6caf73f6..0000000000
--- a/src/main/java/com/alibaba/fastjson/asm/package.html
+++ /dev/null
@@ -1,83 +0,0 @@
-
-
-
- Provides a small and fast bytecode manipulation framework.
-
-
- The ASM framework is
- organized around the {@link org.objectweb.asm.ClassVisitor
- ClassVisitor}, {@link org.objectweb.asm.FieldVisitor FieldVisitor} and
- {@link org.objectweb.asm.MethodVisitor MethodVisitor} interfaces,
- which allow one to visit the fields and methods of a class, including
- the bytecode instructions of each method.
-
In addition to these main interfaces, ASM provides a {@link
- org.objectweb.asm.ClassReader ClassReader} class, that can parse an
- existing class and make a given visitor visit it. ASM also provides a
- {@link org.objectweb.asm.ClassWriter ClassWriter} class, which is a
- visitor that generates Java class files.
-
- In order to generate a class from scratch, only the {@link
- org.objectweb.asm.ClassWriter ClassWriter} class is necessary. Indeed,
- in order to generate a class, one must just call its visitXXX
- methods with the appropriate arguments to generate the desired fields
- and methods. See the "helloworld" example in the ASM distribution for
- more details about class generation.
-
In order to modify existing classes, one must use a {@link
- org.objectweb.asm.ClassReader ClassReader} class to analyze the
- original class, a class modifier, and a {@link
- org.objectweb.asm.ClassWriter ClassWriter} to construct the modified
- class. The class modifier is just a {@link
- org.objectweb.asm.ClassVisitor ClassVisitor} that delegates most of
- the work to another {@link org.objectweb.asm.ClassVisitor
- ClassVisitor}, but that sometimes changes some parameter values, or
- call additional methods, in order to implement the desired
- modification process. In order to make it easier to implement such
- class modifiers, ASM provides the {@link
- org.objectweb.asm.ClassAdapter ClassAdapter} and {@link
- org.objectweb.asm.MethodAdapter MethodAdapter} classes, which
- implement the {@link org.objectweb.asm.ClassVisitor ClassVisitor} and
- {@link org.objectweb.asm.MethodVisitor MethodVisitor} interfaces by
- delegating all work to other visitors. See the "adapt" example in the
- ASM distribution for more details about class modification.
-
- The size of the core ASM library,
- asm.jar
- , is only 42KB, which is much smaller than the size of the BCEL library (504KB), and
- than the size of the SERP
- library (150KB). ASM is also much faster than these tools. Indeed the
- overhead of a load time class transformation process is of the order
- of 60% with ASM, 700% or more with BCEL, and 1100% or more with SERP
- (see the
- test/perf
- directory in the ASM distribution)! @since ASM 1.3
-
-
diff --git a/src/main/java/com/alibaba/fastjson/parser/AbstractJSONParser.java b/src/main/java/com/alibaba/fastjson/parser/AbstractJSONParser.java
deleted file mode 100644
index e6e084653a..0000000000
--- a/src/main/java/com/alibaba/fastjson/parser/AbstractJSONParser.java
+++ /dev/null
@@ -1,224 +0,0 @@
-package com.alibaba.fastjson.parser;
-
-import static com.alibaba.fastjson.parser.JSONToken.EOF;
-import static com.alibaba.fastjson.parser.JSONToken.FALSE;
-import static com.alibaba.fastjson.parser.JSONToken.LBRACE;
-import static com.alibaba.fastjson.parser.JSONToken.LBRACKET;
-import static com.alibaba.fastjson.parser.JSONToken.LITERAL_FLOAT;
-import static com.alibaba.fastjson.parser.JSONToken.LITERAL_INT;
-import static com.alibaba.fastjson.parser.JSONToken.LITERAL_STRING;
-import static com.alibaba.fastjson.parser.JSONToken.NEW;
-import static com.alibaba.fastjson.parser.JSONToken.NULL;
-import static com.alibaba.fastjson.parser.JSONToken.RBRACKET;
-import static com.alibaba.fastjson.parser.JSONToken.TRUE;
-
-import java.util.Collection;
-import java.util.Date;
-import java.util.Map;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONException;
-import com.alibaba.fastjson.JSONObject;
-
-public abstract class AbstractJSONParser {
-
- @SuppressWarnings("rawtypes")
- public abstract void parseObject(final Map object);
-
- public JSONObject parseObject() {
- JSONObject object = new JSONObject();
- parseObject(object);
- return object;
- }
-
- @SuppressWarnings({ "unchecked", "rawtypes" })
- public final void parseArray(final Collection array) {
- final JSONLexer lexer = getLexer();
-
- if (lexer.token() != JSONToken.LBRACKET) {
- throw new JSONException("syntax error, expect [, actual "
- + JSONToken.name(lexer.token()));
- }
-
- lexer.nextToken(JSONToken.LITERAL_STRING);
-
- for (;;) {
- if (isEnabled(Feature.AllowArbitraryCommas)) {
- while (lexer.token() == JSONToken.COMMA) {
- lexer.nextToken();
- continue;
- }
- }
-
- Object value;
- switch (lexer.token()) {
- case LITERAL_INT:
- value = lexer.integerValue();
- lexer.nextToken(JSONToken.COMMA);
- break;
- case LITERAL_FLOAT:
- if (lexer.isEnabled(Feature.UseBigDecimal)) {
- value = lexer.decimalValue();
- } else {
- value = lexer.doubleValue();
- }
- lexer.nextToken(JSONToken.COMMA);
- break;
- case LITERAL_STRING:
- String stringLiteral = lexer.stringVal();
- lexer.nextToken(JSONToken.COMMA);
-
- if (lexer.isEnabled(Feature.AllowISO8601DateFormat)) {
- JSONScanner iso8601Lexer = new JSONScanner(stringLiteral);
- if (iso8601Lexer.scanISO8601DateIfMatch()) {
- value = iso8601Lexer.getCalendar().getTime();
- } else {
- value = stringLiteral;
- }
- } else {
- value = stringLiteral;
- }
-
- break;
- case TRUE:
- value = Boolean.TRUE;
- lexer.nextToken(JSONToken.COMMA);
- break;
- case FALSE:
- value = Boolean.FALSE;
- lexer.nextToken(JSONToken.COMMA);
- break;
- case LBRACE:
- JSONObject object = new JSONObject();
- parseObject(object);
- value = object;
- break;
- case LBRACKET:
- Collection items = new JSONArray();
- parseArray(items);
- value = items;
- break;
- case NULL:
- value = null;
- lexer.nextToken(JSONToken.LITERAL_STRING);
- break;
- case RBRACKET:
- lexer.nextToken(JSONToken.COMMA);
- return;
- default:
- value = parse();
- break;
- }
-
- array.add(value);
-
- if (lexer.token() == JSONToken.COMMA) {
- lexer.nextToken(JSONToken.LITERAL_STRING);
- continue;
- }
- }
- }
-
- public Object parse() {
- final JSONLexer lexer = getLexer();
- switch (lexer.token()) {
- case LBRACKET:
- JSONArray array = new JSONArray();
- parseArray(array);
- return array;
- case LBRACE:
- JSONObject object = new JSONObject();
- parseObject(object);
- return object;
- case LITERAL_INT:
- Number intValue = lexer.integerValue();
- lexer.nextToken();
- return intValue;
- case LITERAL_FLOAT:
-
- Object value;
- if (isEnabled(Feature.UseBigDecimal)) {
- value = lexer.decimalValue();
- } else {
- value = lexer.doubleValue();
- }
- lexer.nextToken();
- return value;
- case LITERAL_STRING:
- String stringLiteral = lexer.stringVal();
- lexer.nextToken(JSONToken.COMMA);
-
- if (lexer.isEnabled(Feature.AllowISO8601DateFormat)) {
- JSONScanner iso8601Lexer = new JSONScanner(stringLiteral);
- if (iso8601Lexer.scanISO8601DateIfMatch()) {
- return iso8601Lexer.getCalendar().getTime();
- }
- }
-
- return stringLiteral;
- case NULL:
- lexer.nextToken();
- return null;
- case TRUE:
- lexer.nextToken();
- return Boolean.TRUE;
- case FALSE:
- lexer.nextToken();
- return Boolean.FALSE;
- case NEW:
- lexer.nextToken(JSONToken.IDENTIFIER);
-
- if (lexer.token() != JSONToken.IDENTIFIER) {
- throw new JSONException("syntax error");
- }
- lexer.nextToken(JSONToken.LPAREN);
-
- accept(JSONToken.LPAREN);
- long time = ((Number) lexer.integerValue()).longValue();
- accept(JSONToken.LITERAL_INT);
-
- accept(JSONToken.RPAREN);
-
- return new Date(time);
- case EOF:
- if (lexer.isBlankInput()) {
- return null;
- }
- default:
- throw new JSONException("TODO " + JSONToken.name(lexer.token())
- + " " + lexer.stringVal());
- }
- }
-
- public void config(Feature feature, boolean state) {
- getLexer().config(feature, state);
- }
-
- public boolean isEnabled(Feature feature) {
- return getLexer().isEnabled(feature);
- }
-
- public abstract JSONLexer getLexer();
-
- public final void accept(final int token) {
- final JSONLexer lexer = getLexer();
- if (lexer.token() == token) {
- lexer.nextToken();
- } else {
- throw new JSONException("syntax error, expect "
- + JSONToken.name(token) + ", actual "
- + JSONToken.name(lexer.token()));
- }
- }
-
- public void close() {
- final JSONLexer lexer = getLexer();
-
- if (isEnabled(Feature.AutoCloseSource)) {
- if (!lexer.isEOF()) {
- throw new JSONException("not close json text, token : "
- + JSONToken.name(lexer.token()));
- }
- }
- }
-}
diff --git a/src/main/java/com/alibaba/fastjson/parser/CharTypes.java b/src/main/java/com/alibaba/fastjson/parser/CharTypes.java
deleted file mode 100644
index c3ab3df2b2..0000000000
--- a/src/main/java/com/alibaba/fastjson/parser/CharTypes.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 1999-2101 Alibaba Group.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.alibaba.fastjson.parser;
-
-/**
- * @author wenshao
- */
-public final class CharTypes {
-
- public final static boolean[] firstIdentifierFlags = new boolean[256];
- static {
- for (char c = 0; c < firstIdentifierFlags.length; ++c) {
- if (c >= 'A' && c <= 'Z') {
- firstIdentifierFlags[c] = true;
- } else if (c >= 'a' && c <= 'z') {
- firstIdentifierFlags[c] = true;
- } else if (c == '_') {
- firstIdentifierFlags[c] = true;
- }
- }
- }
-
- public final static boolean[] identifierFlags = new boolean[256];
-
- static {
- for (char c = 0; c < identifierFlags.length; ++c) {
- if (c >= 'A' && c <= 'Z') {
- identifierFlags[c] = true;
- } else if (c >= 'a' && c <= 'z') {
- identifierFlags[c] = true;
- } else if (c == '_') {
- identifierFlags[c] = true;
- } else if (c >= '0' && c <= '9') {
- identifierFlags[c] = true;
- }
- }
- }
-
- public final static boolean[] specicalFlags_doubleQuotes = new boolean[((int) '\\' + 1)];
- public final static boolean[] specicalFlags_singleQuotes = new boolean[((int) '\\' + 1)];
-
- public static boolean isSpecial_doubleQuotes(char ch) {
- return ch < specicalFlags_doubleQuotes.length && specicalFlags_doubleQuotes[ch];
- }
-
- public final static char[] replaceChars = new char[((int) '\\' + 1)];
- static {
- specicalFlags_doubleQuotes['\b'] = true;
- specicalFlags_doubleQuotes['\n'] = true;
- specicalFlags_doubleQuotes['\f'] = true;
- specicalFlags_doubleQuotes['\r'] = true;
- specicalFlags_doubleQuotes['\"'] = true;
- specicalFlags_doubleQuotes['\\'] = true;
-
- specicalFlags_singleQuotes['\b'] = true;
- specicalFlags_singleQuotes['\n'] = true;
- specicalFlags_singleQuotes['\f'] = true;
- specicalFlags_singleQuotes['\r'] = true;
- specicalFlags_singleQuotes['\''] = true;
- specicalFlags_singleQuotes['\\'] = true;
-
- replaceChars['\b'] = 'b';
- replaceChars['\n'] = 'n';
- replaceChars['\f'] = 'f';
- replaceChars['\r'] = 'r';
- replaceChars['\"'] = '"';
- replaceChars['\''] = '\'';
- replaceChars['\\'] = '\\';
- replaceChars['\t'] = 't';
- }
-
-}
diff --git a/src/main/java/com/alibaba/fastjson/parser/DefaultExtJSONParser.java b/src/main/java/com/alibaba/fastjson/parser/DefaultExtJSONParser.java
index 35dc417784..cbfcac7508 100644
--- a/src/main/java/com/alibaba/fastjson/parser/DefaultExtJSONParser.java
+++ b/src/main/java/com/alibaba/fastjson/parser/DefaultExtJSONParser.java
@@ -1,372 +1,42 @@
-/*
- * Copyright 1999-2101 Alibaba Group.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.alibaba.fastjson.parser;
-
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
-import java.lang.reflect.WildcardType;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import com.alibaba.fastjson.JSONException;
-import com.alibaba.fastjson.parser.deserializer.DefaultObjectDeserializer;
-import com.alibaba.fastjson.parser.deserializer.IntegerDeserializer;
-import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
-import com.alibaba.fastjson.parser.deserializer.StringDeserializer;
-import com.alibaba.fastjson.util.TypeUtils;
-
-/**
- * @author wenshao
- */
-@SuppressWarnings("rawtypes")
-public class DefaultExtJSONParser extends DefaultJSONParser {
-
- private DefaultObjectDeserializer derializer = new DefaultObjectDeserializer();
-
- private final static Set> primitiveClasses = new HashSet>();
- static {
- primitiveClasses.add(boolean.class);
- primitiveClasses.add(byte.class);
- primitiveClasses.add(short.class);
- primitiveClasses.add(int.class);
- primitiveClasses.add(long.class);
- primitiveClasses.add(float.class);
- primitiveClasses.add(double.class);
-
- primitiveClasses.add(Boolean.class);
- primitiveClasses.add(Byte.class);
- primitiveClasses.add(Short.class);
- primitiveClasses.add(Integer.class);
- primitiveClasses.add(Long.class);
- primitiveClasses.add(Float.class);
- primitiveClasses.add(Double.class);
-
- primitiveClasses.add(BigInteger.class);
- primitiveClasses.add(BigDecimal.class);
- primitiveClasses.add(String.class);
- }
-
- public 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);
- }
-
- public ParserConfig getConfig() {
- return config;
- }
-
- public void setConfig(ParserConfig config) {
- this.config = config;
- }
-
- // compatible
- @SuppressWarnings("unchecked")
- public T parseObject(Class clazz) {
- return (T) parseObject((Type) clazz);
- }
-
- @SuppressWarnings("unchecked")
- public T parseObject(Type type) {
- if (lexer.token() == JSONToken.NULL) {
- lexer.nextToken();
- return null;
- }
-
- ObjectDeserializer derializer = config.getDeserializer(type);
-
- try {
- return (T) derializer.deserialze(this, type);
- } catch (JSONException e) {
- throw e;
- } catch (Throwable e) {
- throw new JSONException(e.getMessage(), e);
- }
- }
-
- public List parseArray(Class clazz) {
- List array = new ArrayList();
- parseArray(clazz, array);
- return array;
- }
-
- public void parseArray(Class> clazz, Collection array) {
- parseArray((Type) clazz, array);
- }
-
- @SuppressWarnings({ "unchecked" })
- public void parseArray(Type type, Collection array) {
- if (lexer.token() != JSONToken.LBRACKET) {
- throw new JSONException("exepct '[', but " + JSONToken.name(lexer.token()));
- }
-
- ObjectDeserializer deserializer = null;
- if (int.class == type) {
- deserializer = IntegerDeserializer.instance;
- lexer.nextToken(JSONToken.LITERAL_INT);
- } else if (String.class == type) {
- deserializer = StringDeserializer.instance;
- lexer.nextToken(JSONToken.LITERAL_STRING);
- } else {
- deserializer = config.getDeserializer(type);
- lexer.nextToken(deserializer.getFastMatchToken());
- }
-
- for (;;) {
- if (isEnabled(Feature.AllowArbitraryCommas)) {
- while (lexer.token() == JSONToken.COMMA) {
- lexer.nextToken();
- continue;
- }
- }
-
- if (lexer.token() == JSONToken.RBRACKET) {
- break;
- }
-
- if (int.class == type) {
- Object val = IntegerDeserializer.deserialze(this);
- array.add(val);
- } else if (String.class == type) {
- String value;
- if (lexer.token() == JSONToken.LITERAL_STRING) {
- value = lexer.stringVal();
- lexer.nextToken(JSONToken.COMMA);
- } else {
- Object obj = this.parse();
- if (obj == null) {
- value = null;
- } else {
- value = obj.toString();
- }
- }
-
- array.add(value);
- } else {
- Object val = deserializer.deserialze(this, type);
- array.add(val);
- }
-
- if (lexer.token() == JSONToken.COMMA) {
- lexer.nextToken(deserializer.getFastMatchToken());
- continue;
- }
- }
-
- lexer.nextToken(JSONToken.COMMA);
- }
-
- public Object[] parseArray(Type[] types) {
-
- if (lexer.token() != JSONToken.LBRACKET) {
- throw new JSONException("syntax error");
- }
-
- Object[] list = new Object[types.length];
- if (types.length == 0) {
- lexer.nextToken(JSONToken.RBRACKET);
-
- if (lexer.token() != JSONToken.RBRACKET) {
- throw new JSONException("syntax error");
- }
-
- lexer.nextToken(JSONToken.COMMA);
- return new Object[0];
- }
-
- lexer.nextToken(JSONToken.LITERAL_INT);
-
- for (int i = 0; i < types.length; ++i) {
- Object value;
-
- if (lexer.token() == JSONToken.NULL) {
- value = null;
- lexer.nextToken(JSONToken.COMMA);
- } else {
- Type type = types[i];
- if (type == int.class || type == Integer.class) {
- if (lexer.token() == JSONToken.LITERAL_INT) {
- value = Integer.valueOf(lexer.intValue());
- lexer.nextToken(JSONToken.COMMA);
- } else {
- value = this.parse();
- value = TypeUtils.cast(value, type, config);
- }
- } else if (type == String.class) {
- if (lexer.token() == JSONToken.LITERAL_STRING) {
- value = lexer.stringVal();
- lexer.nextToken(JSONToken.COMMA);
- } else {
- value = this.parse();
- value = TypeUtils.cast(value, type, config);
- }
- } else {
- boolean isArray = false;
- Class> componentType = null;
- if (i == types.length - 1) {
- if (type instanceof Class) {
- Class> clazz = (Class>) type;
- isArray = clazz.isArray();
- componentType = clazz.getComponentType();
- }
- }
-
- // support varArgs
- if (isArray && lexer.token() != JSONToken.LBRACKET) {
- List