1.简介

FastJson是阿里巴巴开源的Java对象和JSON格式字符串的快速转换的工具库

2.环境搭建

导入fastjson依赖

<dependencies>
  <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.24</version>
  </dependency>
</dependencies>

3.为何fastjson存在代码执行的问题

首先是fatsjson最基础的一个json解析的用处。
image.png
也可以取出某个键对应的某个值image.png
fastjson可以将json字符串解析为javaBean。
首先还是需要一个javaBean

public class Person {
    private int age;
    private String name;
    public Person(){

    }
    public int getAge() {
        System.out.println("getAge");
        return age;
    }

    public String getName() {
        System.out.println("getName");
        return name;
    }

    public void setAge(int age) {
        System.out.println("setAge");
        this.age = age;
    }

    public void setName(String name) {
        System.out.println("setName");
        this.name = name;
    }
}

我们用fastjson对其进行解析为Person对象,并输出。
image.png
也就是说,fastjson通过我们的json字符串,将值传给了set方法。也就是说,他会涉及到一个set方法的invoke.也就是说其实用的set去改的。
fastjson有个特性或者说是trick,它可以根据传入的字符串的不同解析不同的类。
如果我们给他传入的字符串中具有@type这个字段,就相当于指定一个类,让他去解析。
我们可以看到他把初始化,赋值调用全部走了一遍。
image.png
也就是说,fastjson能对字符串的不同,走不同的代码逻辑。
在我们的实际运用中,一般都是客户端传入json,然后交给服务器后端的fastjson那么就可能导致JNDI或者RMI等的远程注入类导致RCE。

4.fastjson的调用流程以及漏洞原理

那我们就从刚刚的parseObject跟进去看看。
这是一个静态方法,可以直接通过类名调用,他接收一个字符串。
通过parse解析类之后放在obj中,之后将其转换为JSONObject.这是一个键值对的map。

public static JSONObject parseObject(String text) {
    Object obj = parse(text);
if (obj instanceof JSONObject) {
    return (JSONObject) obj;
}

return (JSONObject) JSON.toJSON(obj);
}

我们跟进parse方法。这也是一个static方法,也可以直接调用。
但是好多人都还是用parseObject.

public static Object parse(String text) {
    return parse(text, DEFAULT_PARSER_FEATURE);
}

他有多个重载的方法。
继续往里跟进,就到了这个parse
这里会调用一个DefaultJSONParser,一个解析器用于解析。
然后parser.parse进行解析。
features用于接受解析时候的要求,例如能不能用单引号,多个逗号等问题的处理。
具体的features可以看这篇文章里的。
https://developer.aliyun.com/article/862151

public static Object parse(String text, int features) {
    if (text == null) {
        return null;
    }

    DefaultJSONParser parser = new DefaultJSONParser(text, ParserConfig.getGlobalInstance(), features);
    Object value = parser.parse();

    parser.handleResovleTask(value);

    parser.close();

    return value;
}

跟进parser.parse
switch用于判断当前第一个的字符是啥
我们这边第一个字符是{,对应LBRACE
image.png
这里的代码被我删掉了一些,主要关注这一段。
。我们也知道左花括号也就是说是一个完整的json对象,那么就会将其作为一个对象解析。

public Object parse(Object fieldName) {
    final JSONLexer lexer = this.lexer;
switch (lexer.token()) {
    case LBRACE:
        JSONObject object = new JSONObject(lexer.isEnabled(Feature.OrderedField));
        return parseObject(object, fieldName);
}

这里跟进parseObject
在parseObject中会将我们传入的字符串解析成一个对象。
DefaultJSONParser.parseObject的代码有点长,拿关键信息.
上面就是边界值的一些判断,核心就是一个try catch。

try {
    boolean setContextFlag = false;
    for (;;) {
        lexer.skipWhitespace();
        char ch = lexer.getCurrent();
        if (lexer.isEnabled(Feature.AllowArbitraryCommas)) {
            while (ch == ',') {
                lexer.next();
                lexer.skipWhitespace();
                ch = lexer.getCurrent();
            }
        }

        boolean isObjectKey = false;
        Object key;
        if (ch == '"') {
            key = lexer.scanSymbol(symbolTable, '"');
            lexer.skipWhitespace();
            ch = lexer.getCurrent();
            if (ch != ':') {
                throw new JSONException("expect ':' at " + lexer.pos() + ", name " + key);
            }
        } else if (ch == '}') {
            lexer.next();
            lexer.resetStringPosition();
            lexer.nextToken();

            if (!setContextFlag) {
                if (this.context != null && fieldName == this.context.fieldName && object == this.context.object) {
                    context = this.context;
                } else {
                    ParseContext contextR = setContext(object, fieldName);
                    if (context == null) {
                        context = contextR;
                    }
                    setContextFlag = true;
                }
            }

            return object;
        } else if (ch == '\'') {
            if (!lexer.isEnabled(Feature.AllowSingleQuotes)) {
                throw new JSONException("syntax error");
            }

            key = lexer.scanSymbol(symbolTable, '\'');
            lexer.skipWhitespace();
            ch = lexer.getCurrent();
            if (ch != ':') {
                throw new JSONException("expect ':' at " + lexer.pos());
            }
        } else if (ch == EOI) {
            throw new JSONException("syntax error");
        } else if (ch == ',') {
            throw new JSONException("syntax error");
        } else if ((ch >= '0' && ch <= '9') || ch == '-') {
            lexer.resetStringPosition();
            lexer.scanNumber();
            try {
                if (lexer.token() == JSONToken.LITERAL_INT) {
                    key = lexer.integerValue();
                } else {
                    key = lexer.decimalValue(true);
                }
            } catch (NumberFormatException e) {
                throw new JSONException("parse number key error" + lexer.info());
            }
            ch = lexer.getCurrent();
            if (ch != ':') {
                throw new JSONException("parse number key error" + lexer.info());
        }
        } else if (ch == '{' || ch == '[') {
            lexer.nextToken();
            key = parse();
            isObjectKey = true;
        } else {
            if (!lexer.isEnabled(Feature.AllowUnQuotedFieldNames)) {
            throw new JSONException("syntax error");
        }

            key = lexer.scanSymbolUnQuoted(symbolTable);
            lexer.skipWhitespace();
            ch = lexer.getCurrent();
            if (ch != ':') {
            throw new JSONException("expect ':' at " + lexer.pos() + ", actual " + ch);
        }
        }

            if (!isObjectKey) {
            lexer.next();
            lexer.skipWhitespace();
        }

            ch = lexer.getCurrent();

            lexer.resetStringPosition();

            if (key == JSON.DEFAULT_TYPE_KEY && !lexer.isEnabled(Feature.DisableSpecialKeyDetect)) {
            String typeName = lexer.scanSymbol(symbolTable, '"');
            Class<?> clazz = TypeUtils.loadClass(typeName, config.getDefaultClassLoader());

            if (clazz == null) {
            object.put(JSON.DEFAULT_TYPE_KEY, typeName);
            continue;
        }

            lexer.nextToken(JSONToken.COMMA);
            if (lexer.token() == JSONToken.RBRACE) {
            lexer.nextToken(JSONToken.COMMA);
            try {
            Object instance = null;
            ObjectDeserializer deserializer = this.config.getDeserializer(clazz);
            if (deserializer instanceof JavaBeanDeserializer) {
            instance = ((JavaBeanDeserializer) deserializer).createInstance(this, clazz);
        }

            if (instance == null) {
            if (clazz == Cloneable.class) {
            instance = new HashMap();
        } else if ("java.util.Collections$EmptyMap".equals(typeName)) {
            instance = Collections.emptyMap();
        } else {
            instance = clazz.newInstance();
        }
        }

            return instance;
        } catch (Exception e) {
            throw new JSONException("create instance error", e);
        }
        }

            this.setResolveStatus(TypeNameRedirect);

            if (this.context != null && !(fieldName instanceof Integer)) {
            this.popContext();
        }

            if (object.size() > 0) {
            Object newObj = TypeUtils.cast(object, clazz, this.config);
            this.parseObject(newObj);
            return newObj;
        }

            ObjectDeserializer deserializer = config.getDeserializer(clazz);
            return deserializer.deserialze(this, clazz, fieldName);
        }

            if (key == "$ref" && !lexer.isEnabled(Feature.DisableSpecialKeyDetect)) {
            lexer.nextToken(JSONToken.LITERAL_STRING);
            if (lexer.token() == JSONToken.LITERAL_STRING) {
            String ref = lexer.stringVal();
            lexer.nextToken(JSONToken.RBRACE);

            Object refValue = null;
            if ("@".equals(ref)) {
            if (this.context != null) {
            ParseContext thisContext = this.context;
            Object thisObj = thisContext.object;
            if (thisObj instanceof Object[] || thisObj instanceof Collection<?>) {
            refValue = thisObj;
        } else if (thisContext.parent != null) {
            refValue = thisContext.parent.object;
        }
        }
        } else if ("..".equals(ref)) {
            if (context.object != null) {
            refValue = context.object;
        } else {
            addResolveTask(new ResolveTask(context, ref));
            setResolveStatus(DefaultJSONParser.NeedToResolve);
        }
        } else if ("$".equals(ref)) {
            ParseContext rootContext = context;
            while (rootContext.parent != null) {
            rootContext = rootContext.parent;
        }

            if (rootContext.object != null) {
            refValue = rootContext.object;
        } else {
            addResolveTask(new ResolveTask(rootContext, ref));
            setResolveStatus(DefaultJSONParser.NeedToResolve);
        }
        } else {
            addResolveTask(new ResolveTask(context, ref));
            setResolveStatus(DefaultJSONParser.NeedToResolve);
        }

            if (lexer.token() != JSONToken.RBRACE) {
            throw new JSONException("syntax error");
        }
            lexer.nextToken(JSONToken.COMMA);

            return refValue;
        } else {
            throw new JSONException("illegal ref, " + JSONToken.name(lexer.token()));
        }
        }

            if (!setContextFlag) {
            if (this.context != null && fieldName == this.context.fieldName && object == this.context.object) {
            context = this.context;
        } else {
            ParseContext contextR = setContext(object, fieldName);
            if (context == null) {
            context = contextR;
        }
            setContextFlag = true;
        }
        }

            if (object.getClass() == JSONObject.class) {
            key = (key == null) ? "null" : key.toString();
        }

            Object value;
            if (ch == '"') {
            lexer.scanString();
            String strValue = lexer.stringVal();
            value = strValue;

            if (lexer.isEnabled(Feature.AllowISO8601DateFormat)) {
            JSONScanner iso8601Lexer = new JSONScanner(strValue);
            if (iso8601Lexer.scanISO8601DateIfMatch()) {
            value = iso8601Lexer.getCalendar().getTime();
        }
            iso8601Lexer.close();
        }

            object.put(key, value);
        } else if (ch >= '0' && ch <= '9' || ch == '-') {
            lexer.scanNumber();
            if (lexer.token() == JSONToken.LITERAL_INT) {
            value = lexer.integerValue();
        } else {
            value = lexer.decimalValue(lexer.isEnabled(Feature.UseBigDecimal));
        }

            object.put(key, value);
        } else if (ch == '[') { // 减少嵌套,兼容android
            lexer.nextToken();

            JSONArray list = new JSONArray();

            final boolean parentIsArray = fieldName != null && fieldName.getClass() == Integer.class;
            //                    if (!parentIsArray) {
            //                        this.setContext(context);
            //                    }
            if (fieldName == null) {
            this.setContext(context);
        }

            this.parseArray(list, key);

            if (lexer.isEnabled(Feature.UseObjectArray)) {
            value = list.toArray();
        } else {
            value = list;
        }
            object.put(key, value);

            if (lexer.token() == JSONToken.RBRACE) {
            lexer.nextToken();
            return object;
        } else if (lexer.token() == JSONToken.COMMA) {
            continue;
        } else {
            throw new JSONException("syntax error");
        }
        } else if (ch == '{') { // 减少嵌套,兼容android
            lexer.nextToken();

            final boolean parentIsArray = fieldName != null && fieldName.getClass() == Integer.class;

            JSONObject input = new JSONObject(lexer.isEnabled(Feature.OrderedField));
            ParseContext ctxLocal = null;

            if (!parentIsArray) {
            ctxLocal = setContext(context, input, key);
        }

            Object obj = null;
            boolean objParsed = false;
            if (fieldTypeResolver != null) {
            String resolveFieldName = key != null ? key.toString() : null;
            Type fieldType = fieldTypeResolver.resolve(object, resolveFieldName);
            if (fieldType != null) {
            ObjectDeserializer fieldDeser = config.getDeserializer(fieldType);
            obj = fieldDeser.deserialze(this, fieldType, key);
            objParsed = true;
        }
        }
            if (!objParsed) {
            obj = this.parseObject(input, key);
        }

            if (ctxLocal != null && input != obj) {
            ctxLocal.object = object;
        }

            checkMapResolve(object, key.toString());

            if (object.getClass() == JSONObject.class) {
            object.put(key.toString(), obj);
        } else {
            object.put(key, obj);
        }

            if (parentIsArray) {
            //setContext(context, obj, key);
            setContext(obj, key);
        }

            if (lexer.token() == JSONToken.RBRACE) {
            lexer.nextToken();

            setContext(context);
            return object;
        } else if (lexer.token() == JSONToken.COMMA) {
            if (parentIsArray) {
            this.popContext();
        } else {
            this.setContext(context);
        }
            continue;
        } else {
            throw new JSONException("syntax error, " + lexer.tokenName());
        }
        } else {
            lexer.nextToken();
            value = parse();

            if (object.getClass() == JSONObject.class) {
            key = key.toString();
        }
            object.put(key, value);

            if (lexer.token() == JSONToken.RBRACE) {
            lexer.nextToken();
            return object;
        } else if (lexer.token() == JSONToken.COMMA) {
            continue;
        } else {
            throw new JSONException("syntax error, position at " + lexer.pos() + ", name " + key);
        }
        }

            lexer.skipWhitespace();
            ch = lexer.getCurrent();
            if (ch == ',') {
            lexer.next();
            continue;
        } else if (ch == '}') {
            lexer.next();
            lexer.resetStringPosition();
            lexer.nextToken();

            // this.setContext(object, fieldName);
            this.setContext(value, key);

            return object;
        } else {
            throw new JSONException("syntax error, position at " + lexer.pos() + ", name " + key);
        }

        }
        } finally {
            this.setContext(context);
        }

在上述的代码中,我们接下来会进行一段一段的拆分。这样虽然冗余,但是便于理解。
看上述的代码,我们就能发现,是对我们{的下一位进行匹配,也就是说,在我们代码里面是双引号。所以我就截取了下述的代码。
使用lexer.scanSymbol,读到了我们的两个双引号之间的@Ttype

Object key;
if (ch == '"') {
    key = lexer.scanSymbol(symbolTable, '"');
    lexer.skipWhitespace();
    ch = lexer.getCurrent();
    if (ch != ':') {
        throw new JSONException("expect ':' at " + lexer.pos() + ", name " + key);
    }
}

image.png
然后我们继续往下走。
可以看到下述截取代码中对其进行了一个key 的if的判断。
JSON.DEFAULT_TYPE_KEY就是@type
image.png先用String typeName = lexer.scanSymbol(symbolTable, '"');截取类的路径和名称。然后使用loadClass去加载类,存入clazz。
在加载完成之后。

if (key == JSON.DEFAULT_TYPE_KEY && !lexer.isEnabled(Feature.DisableSpecialKeyDetect)) {
    String typeName = lexer.scanSymbol(symbolTable, '"');
    Class<?> clazz = TypeUtils.loadClass(typeName, config.getDefaultClassLoader());

    if (clazz == null) {
        object.put(JSON.DEFAULT_TYPE_KEY, typeName);
        continue;
    }

    lexer.nextToken(JSONToken.COMMA);
    if (lexer.token() == JSONToken.RBRACE) {
        lexer.nextToken(JSONToken.COMMA);
        try {
            Object instance = null;
            ObjectDeserializer deserializer = this.config.getDeserializer(clazz);
            if (deserializer instanceof JavaBeanDeserializer) {
                instance = ((JavaBeanDeserializer) deserializer).createInstance(this, clazz);
            }

            if (instance == null) {
                if (clazz == Cloneable.class) {
                    instance = new HashMap();
                } else if ("java.util.Collections$EmptyMap".equals(typeName)) {
                    instance = Collections.emptyMap();
                } else {
                    instance = clazz.newInstance();
                }
            }

            return instance;
        } catch (Exception e) {
            throw new JSONException("create instance error", e);
        }
    }

    this.setResolveStatus(TypeNameRedirect);

    if (this.context != null && !(fieldName instanceof Integer)) {
        this.popContext();
    }

    if (object.size() > 0) {//每加载完一轮key和value就往空的JSONObject中放
        Object newObj = TypeUtils.cast(object, clazz, this.config);
        this.parseObject(newObj);
        return newObj;
    }

    ObjectDeserializer deserializer = config.getDeserializer(clazz);
    return deserializer.deserialze(this, clazz, fieldName);
}

关键在于ObjectDeserializer deserializer和deserializer.deserialze
先获取反序列化器,然后对其进行反序列化。49行跑完,回来的就是Person.
所以48行跟进getDeserializer
derializers就是一个缓存表,他也用空间换时间。如果缓存表内有这个类,就直接调。但是我们的是Person类,并不可能会有对应的反序列化器,所以我们就继续往下走。往下走就会进入到
return getDeserializer((Class<?>) type, type);.所以继续跟进

public ObjectDeserializer getDeserializer(Type type) {
    ObjectDeserializer derializer = this.derializers.get(type);
if (derializer != null) {
    return derializer;
}

if (type instanceof Class<?>) {
    return getDeserializer((Class<?>) type, type);
}

if (type instanceof ParameterizedType) {
    Type rawType = ((ParameterizedType) type).getRawType();
    if (rawType instanceof Class<?>) {
        return getDeserializer((Class<?>) rawType, type);
    } else {
        return getDeserializer(rawType);
    }
}

return JavaObjectDeserializer.instance;
}

故跟进getDeserializer

public ObjectDeserializer getDeserializer(Class<?> clazz, Type type) {
    ObjectDeserializer derializer = derializers.get(type);
    if (derializer != null) {
        return derializer;
    }

    if (type == null) {
        type = clazz;
    }

    derializer = derializers.get(type);
    if (derializer != null) {
        return derializer;
    }

    {
        JSONType annotation = clazz.getAnnotation(JSONType.class);//这里是获取注解没多大意义。
        if (annotation != null) {
            Class<?> mappingTo = annotation.mappingTo();
            if (mappingTo != Void.class) {
                return getDeserializer(mappingTo, mappingTo);
            }
        }
    }

    if (type instanceof WildcardType || type instanceof TypeVariable || type instanceof ParameterizedType) {
        derializer = derializers.get(clazz);
    }

    if (derializer != null) {
        return derializer;
    }

    String className = clazz.getName();
    className = className.replace('$', '.');
    for (int i = 0; i < denyList.length; ++i) {
        String deny = denyList[i];
        if (className.startsWith(deny)) {
            throw new JSONException("parser deny : " + className);
        }
    }

    if (className.startsWith("java.awt.") //
        && AwtCodec.support(clazz)) {
        if (!awtError) {
            try {
                derializers.put(Class.forName("java.awt.Point"), AwtCodec.instance);
                derializers.put(Class.forName("java.awt.Font"), AwtCodec.instance);
                derializers.put(Class.forName("java.awt.Rectangle"), AwtCodec.instance);
                derializers.put(Class.forName("java.awt.Color"), AwtCodec.instance);
            } catch (Throwable e) {
                // skip
                awtError = true;
            }

            derializer = AwtCodec.instance;
        }
    }

    if (!jdk8Error) {
        try {
            if (className.startsWith("java.time.")) {

                derializers.put(Class.forName("java.time.LocalDateTime"), Jdk8DateCodec.instance);
                derializers.put(Class.forName("java.time.LocalDate"), Jdk8DateCodec.instance);
                derializers.put(Class.forName("java.time.LocalTime"), Jdk8DateCodec.instance);
                derializers.put(Class.forName("java.time.ZonedDateTime"), Jdk8DateCodec.instance);
                derializers.put(Class.forName("java.time.OffsetDateTime"), Jdk8DateCodec.instance);
                derializers.put(Class.forName("java.time.OffsetTime"), Jdk8DateCodec.instance);
                derializers.put(Class.forName("java.time.ZoneOffset"), Jdk8DateCodec.instance);
                derializers.put(Class.forName("java.time.ZoneRegion"), Jdk8DateCodec.instance);
                derializers.put(Class.forName("java.time.ZoneId"), Jdk8DateCodec.instance);
                derializers.put(Class.forName("java.time.Period"), Jdk8DateCodec.instance);
                derializers.put(Class.forName("java.time.Duration"), Jdk8DateCodec.instance);
                derializers.put(Class.forName("java.time.Instant"), Jdk8DateCodec.instance);

                    derializer = derializers.get(clazz);
                    } else if (className.startsWith("java.util.Optional")) {

                    derializers.put(Class.forName("java.util.Optional"), OptionalCodec.instance);
                    derializers.put(Class.forName("java.util.OptionalDouble"), OptionalCodec.instance);
                    derializers.put(Class.forName("java.util.OptionalInt"), OptionalCodec.instance);
                    derializers.put(Class.forName("java.util.OptionalLong"), OptionalCodec.instance);

                    derializer = derializers.get(clazz);
                    }
                    } catch (Throwable e) {
                    // skip
                    jdk8Error = true;
                    }
                    }

                    if (className.equals("java.nio.file.Path")) {
                    derializers.put(clazz, MiscCodec.instance);
                    }

                    if (clazz == Map.Entry.class) {
                    derializers.put(clazz, MiscCodec.instance);
                    }

                    final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
                    try {
                    for (AutowiredObjectDeserializer autowired : ServiceLoader.load(AutowiredObjectDeserializer.class,
                    classLoader)) {
                    for (Type forType : autowired.getAutowiredFor()) {
                    derializers.put(forType, autowired);
                    }
                    }
                    } catch (Exception ex) {
                    // skip
                    }

                    if (derializer == null) {
                    derializer = derializers.get(type);
                    }

                    if (derializer != null) {
                    return derializer;
                    }

                    if (clazz.isEnum()) {
                    derializer = new EnumDeserializer(clazz);
                    } else if (clazz.isArray()) {
                    derializer = ObjectArrayCodec.instance;
                    } else if (clazz == Set.class || clazz == HashSet.class || clazz == Collection.class || clazz == List.class
                    || clazz == ArrayList.class) {
                    derializer = CollectionCodec.instance;
                    } else if (Collection.class.isAssignableFrom(clazz)) {
                    derializer = CollectionCodec.instance;
                    } else if (Map.class.isAssignableFrom(clazz)) {
                    derializer = MapDeserializer.instance;
                    } else if (Throwable.class.isAssignableFrom(clazz)) {
                    derializer = new ThrowableDeserializer(this, clazz);
                    } else {
                    derializer = createJavaBeanDeserializer(clazz, type);
                    }

                    putDeserializer(type, derializer);

                    return derializer;
                    }

在上述的代码中我们需要关注的有两个点
1.denyList(黑名单)在这个版本的denyList并没有一些安全性的考虑。

for (int i = 0; i < denyList.length; ++i) {
    String deny = denyList[i];
    if (className.startsWith(deny)) {
        throw new JSONException("parser deny : " + className);
    }
}

往下走就是各种匹配,各种不同的包下,使用不同的反序列化器。
然后再往下,还是各种匹配,如果是map就用map对应的解释器,如果是collection就用collection对应的解释器。最后我们都不是,所以就只能走到创建的解析器。就抛出了我们的第二点。
2.derializer = createJavaBeanDeserializer(clazz, type)
ASMEnable算是debug中比较重要的一个点(但对我们实际的漏洞流程没有什么太大的影响,只是为了方便debug)。后续需要关注一下。这边其实不需要太过于关注ASM的相关技术。ASMEnable默认为true,所以第一个if会进去。
这个ASM的开关在某个情况下会不支持。
这里的关键在于javaBeanInfo.build

public ObjectDeserializer createJavaBeanDeserializer(Class<?> clazz, Type type) {
        boolean asmEnable = this.asmEnable;
        if (asmEnable) {
            JSONType jsonType = clazz.getAnnotation(JSONType.class);

            if (jsonType != null) {
                Class<?> deserializerClass = jsonType.deserializer();
                if (deserializerClass != Void.class) {
                    try {
                        Object deseralizer = deserializerClass.newInstance();
                        if (deseralizer instanceof ObjectDeserializer) {
                            return (ObjectDeserializer) deseralizer;
                        }
                    } catch (Throwable e) {
                        // skip
                    }
                }
                
                asmEnable = jsonType.asm();
            }

            if (asmEnable) {
                Class<?> superClass = JavaBeanInfo.getBuilderClass(jsonType);
                if (superClass == null) {
                    superClass = clazz;
                }

                for (;;) {
                    if (!Modifier.isPublic(superClass.getModifiers())) {
                        asmEnable = false;
                        break;
                    }

                    superClass = superClass.getSuperclass();
                    if (superClass == Object.class || superClass == null) {
                        break;
                    }
                }
            }
        }

        if (clazz.getTypeParameters().length != 0) {
            asmEnable = false;
        }

        if (asmEnable && asmFactory != null && asmFactory.classLoader.isExternalClass(clazz)) {
            asmEnable = false;
        }

        if (asmEnable) {
            asmEnable = ASMUtils.checkName(clazz.getSimpleName());
        }

        if (asmEnable) {
            if (clazz.isInterface()) {
                asmEnable = false;
            }
            JavaBeanInfo beanInfo = JavaBeanInfo.build(clazz, type, propertyNamingStrategy);

            if (asmEnable && beanInfo.fields.length > 200) {
                asmEnable = false;
            }

            Constructor<?> defaultConstructor = beanInfo.defaultConstructor;
            if (asmEnable && defaultConstructor == null && !clazz.isInterface()) {
                asmEnable = false;
            }

            for (FieldInfo fieldInfo : beanInfo.fields) {
                if (fieldInfo.getOnly) {
                    asmEnable = false;
                    break;
                }

                Class<?> fieldClass = fieldInfo.fieldClass;
                if (!Modifier.isPublic(fieldClass.getModifiers())) {
                    asmEnable = false;
                    break;
                }

                if (fieldClass.isMemberClass() && !Modifier.isStatic(fieldClass.getModifiers())) {
                    asmEnable = false;
                    break;
                }

                if (fieldInfo.getMember() != null //
                    && !ASMUtils.checkName(fieldInfo.getMember().getName())) {
                    asmEnable = false;
                    break;
                }

                JSONField annotation = fieldInfo.getAnnotation();
                if (annotation != null //
                    && ((!ASMUtils.checkName(annotation.name())) //
                        || annotation.format().length() != 0 //
                        || annotation.deserializeUsing() != Void.class)) {
                    asmEnable = false;
                    break;
                }

                if (fieldClass.isEnum()) { // EnumDeserializer
                    ObjectDeserializer fieldDeser = this.getDeserializer(fieldClass);
                    if (!(fieldDeser instanceof EnumDeserializer)) {
                        asmEnable = false;
                        break;
                    }
                }
            }
        }

        if (asmEnable) {
            if (clazz.isMemberClass() && !Modifier.isStatic(clazz.getModifiers())) {
                asmEnable = false;
            }
        }

        if (!asmEnable) {
            return new JavaBeanDeserializer(this, clazz, type);
        }

        JavaBeanInfo beanInfo = JavaBeanInfo.build(clazz, type, propertyNamingStrategy);
        try {
            return asmFactory.createJavaBeanDeserializer(this, beanInfo);
            // } catch (VerifyError e) {
            // e.printStackTrace();
            // return new JavaBeanDeserializer(this, clazz, type);
        } catch (NoSuchMethodException ex) {
            return new JavaBeanDeserializer(this, clazz, type);
        } catch (JSONException asmError) {
            return new JavaBeanDeserializer(this, beanInfo);
        } catch (Exception e) {
            throw new JSONException("create asm deserializer error, " + clazz.getName(), e);
        }
    }

跟进JavaBeanInfo.build,这个方法很关键,很关键。
这个方法主要是为了把你类里面的东西都全部了解。组成一个javaBeanInfo

Field[] declaredFields = clazz.getDeclaredFields();//获取所有的字段。
Method[] methods = clazz.getMethods();//获取所有方法
Constructor<?> defaultConstructor = getDefaultConstructor(builderClass == null ? clazz : builderClass);//获取默认构造方法
        if (defaultConstructor != null) {
            TypeUtils.setAccessible(defaultConstructor);//默认构造方法允许访问
        }

我们可以截图看一下三个for循环。
image.png
我们第一个for循环的这几个if,第一个if,方法名称需要大于四个字符。第二个if,方法不能为static,第三个if,返回值要为void。第四个if就是参数要唯一,如果不唯一的话,也不行,然后再往下就是注解的判断,我们不用管,继续往下。在if (!methodName.startsWith("set"))中,表示必须为set开头。
往下就是转小写的操作,然后后面对一些特殊情况下的处理。再往下对我们的复现就没有啥帮助的,直到最后的add。

for (Method method : methods) { //
            int ordinal = 0, serialzeFeatures = 0, parserFeatures = 0;
            String methodName = method.getName();
            if (methodName.length() < 4) {
                continue;
            }

            if (Modifier.isStatic(method.getModifiers())) {
                continue;
            }

            // support builder set
            if (!(method.getReturnType().equals(Void.TYPE) || method.getReturnType().equals(method.getDeclaringClass()))) {
                continue;
            }
            Class<?>[] types = method.getParameterTypes();
            if (types.length != 1) {
                continue;
            }

            JSONField annotation = method.getAnnotation(JSONField.class);

            if (annotation == null) {
                annotation = TypeUtils.getSuperMethodAnnotation(clazz, method);
            }

            if (annotation != null) {
                if (!annotation.deserialize()) {
                    continue;
                }

                ordinal = annotation.ordinal();
                serialzeFeatures = SerializerFeature.of(annotation.serialzeFeatures());
                parserFeatures = Feature.of(annotation.parseFeatures());

                if (annotation.name().length() != 0) {
                    String propertyName = annotation.name();
                    add(fieldList, new FieldInfo(propertyName, method, null, clazz, type, ordinal, serialzeFeatures, parserFeatures, 
                                                 annotation, null, null));
                    continue;
                }
            }

            if (!methodName.startsWith("set")) { // TODO "set"的判断放在 JSONField 注解后面,意思是允许非 setter 方法标记 JSONField 注解?
                continue;
            }

            char c3 = methodName.charAt(3);

            String propertyName;
            if (Character.isUpperCase(c3) //
                || c3 > 512 // for unicode method name
            ) {
                if (TypeUtils.compatibleWithJavaBean) {
                    propertyName = TypeUtils.decapitalize(methodName.substring(3));
                } else {
                    propertyName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
                }
            } else if (c3 == '_') {
                propertyName = methodName.substring(4);
            } else if (c3 == 'f') {
                propertyName = methodName.substring(3);
            } else if (methodName.length() >= 5 && Character.isUpperCase(methodName.charAt(4))) {
                propertyName = TypeUtils.decapitalize(methodName.substring(3));
            } else {
                continue;
            }

            Field field = TypeUtils.getField(clazz, propertyName, declaredFields);
            if (field == null && types[0] == boolean.class) {
                String isFieldName = "is" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
                field = TypeUtils.getField(clazz, isFieldName, declaredFields);
            }

            JSONField fieldAnnotation = null;
            if (field != null) {
                fieldAnnotation = field.getAnnotation(JSONField.class);

                if (fieldAnnotation != null) {
                    if (!fieldAnnotation.deserialize()) {
                        continue;
                    }
                    
                    ordinal = fieldAnnotation.ordinal();
                    serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures());
                    parserFeatures = Feature.of(fieldAnnotation.parseFeatures());

                    if (fieldAnnotation.name().length() != 0) {
                        propertyName = fieldAnnotation.name();
                        add(fieldList, new FieldInfo(propertyName, method, field, clazz, type, ordinal,
                                                     serialzeFeatures, parserFeatures, annotation, fieldAnnotation, null));
                        continue;
                    }
                }

            }
            
            if (propertyNamingStrategy != null) {
                propertyName = propertyNamingStrategy.translate(propertyName);
            }

            add(fieldList, new FieldInfo(propertyName, method, field, clazz, type, ordinal, serialzeFeatures, parserFeatures,
                                         annotation, fieldAnnotation, null));
        }

在add之前,会创建一个FieldInfo将我们遍历的一个方法名,对应的类名称等等的东西存入进去,然后放入list。

public FieldInfo(String name, // 
                 Method method, // 
                 Field field, // 
                 Class<?> clazz, // 
                 Type type, // 
                 int ordinal, // 
                 int serialzeFeatures, // 
                 int parserFeatures, //
                 JSONField fieldAnnotation, // 
                 JSONField methodAnnotation, //
                 String label){
    boolean getOnly = false;
}

然后上面代码中的add,其实是将new的FieldInfo放入到一个list当中。
为什么把这个getOnly也放在这里呢,因为他在后面debug 的时候对修改ASMEnable有作用。
那我们来总结一下,第一个for循环的要求。
1.方法名称需要大于四个字符。
2.方法不能为static,
3.返回值要为void,或者为当前类。
4.参数要唯一。
5.必须为set开头。
6.第四位要为大写,不然就做特殊处理
然后接下来看第二个for循环
第二个for循环是获取所有的public字段。因为我们的字段都是private,所以getFields获取不到。他最后也会new一个FieldInfo,然后存入到List.
所以第二个for循环的总结就是只能获取所有的public字段。

for (Field field : clazz.getFields()) { // public static fields
    int modifiers = field.getModifiers();
    if ((modifiers & Modifier.STATIC) != 0) {
        continue;
    }

    if((modifiers & Modifier.FINAL) != 0) {
        Class<?> fieldType = field.getType();
        boolean supportReadOnly = Map.class.isAssignableFrom(fieldType) 
            || Collection.class.isAssignableFrom(fieldType)
            || AtomicLong.class.equals(fieldType) //
            || AtomicInteger.class.equals(fieldType) //
            || AtomicBoolean.class.equals(fieldType);
        if (!supportReadOnly) {
            continue;
        }
    }

    boolean contains = false;
    for (FieldInfo item : fieldList) {
        if (item.name.equals(field.getName())) {
            contains = true;
            break; // 已经是 contains = true,无需继续遍历
        }
    }

    if (contains) {
        continue;
    }

    int ordinal = 0, serialzeFeatures = 0, parserFeatures = 0;
    String propertyName = field.getName();

    JSONField fieldAnnotation = field.getAnnotation(JSONField.class);

    if (fieldAnnotation != null) {
        if (!fieldAnnotation.deserialize()) {
            continue;
        }

        ordinal = fieldAnnotation.ordinal();
        serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures());
        parserFeatures = Feature.of(fieldAnnotation.parseFeatures());

        if (fieldAnnotation.name().length() != 0) {
            propertyName = fieldAnnotation.name();
        }
    }

    if (propertyNamingStrategy != null) {
        propertyName = propertyNamingStrategy.translate(propertyName);
    }

    add(fieldList, new FieldInfo(propertyName, null, field, clazz, type, ordinal, serialzeFeatures, parserFeatures, null,
                                 fieldAnnotation, null));
}

然后就是第三个for循环,用于遍历所有的get方法。
我们看这几个if。
第一个if表示,方法长度大于4.
第二个if表示,不能为静态方法
第三个if表示必须以get开头且第四个字母为大写。
if里面还有一个if,表示没有传入参数,get肯定就不需要有传入参数
第五个if表示,如果你的返回值为Collection Map等这些
在往下的这个if中,if (fieldInfo != null) {continue;}表示只有get没有set。
那么就能直接new一个FieldInfo,存入list中。

for (Method method : clazz.getMethods()) { // getter methods
    String methodName = method.getName();
    if (methodName.length() < 4) {
        continue;
    }

    if (Modifier.isStatic(method.getModifiers())) {
        continue;
    }

    if (methodName.startsWith("get") && Character.isUpperCase(methodName.charAt(3))) {
        if (method.getParameterTypes().length != 0) {
            continue;
        }

        if (Collection.class.isAssignableFrom(method.getReturnType()) //
            || Map.class.isAssignableFrom(method.getReturnType()) //
            || AtomicBoolean.class == method.getReturnType() //
            || AtomicInteger.class == method.getReturnType() //
            || AtomicLong.class == method.getReturnType() //
           ) {
            String propertyName;

            JSONField annotation = method.getAnnotation(JSONField.class);
            if (annotation != null && annotation.deserialize()) {
                continue;
            }

            if (annotation != null && annotation.name().length() > 0) {
                propertyName = annotation.name();
            } else {
                propertyName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
            }

            FieldInfo fieldInfo = getField(fieldList, propertyName);
            if (fieldInfo != null) {
                continue;
            }

            if (propertyNamingStrategy != null) {
                propertyName = propertyNamingStrategy.translate(propertyName);
            }

            add(fieldList, new FieldInfo(propertyName, method, null, clazz, type, 0, 0, 0, annotation, null, null));
        }
    }
}
return new JavaBeanInfo(clazz, builderClass, defaultConstructor, null, null, buildMethod, jsonType, fieldList);

然后最后用return将所有遍历的结果返回出来,存储到PaserConfig中的beanInfo中(里面只有set没有get)因为反序列化的过程就是赋值,一般用不到get。
image.png
继续往下看ParserConfig.createJavaBeanDeserializer中有一个开关,叫做asmEnable。
我们可以看一下关于asmEnable的判断。如果asmEnable为false,就会调用它的默认反序列化器。不然他就使用asmFactory.createJavaBeanDeserializer,临时创建一个反序列化器

if (!asmEnable) {
    return new JavaBeanDeserializer(this, clazz, type);
}

JavaBeanInfo beanInfo = JavaBeanInfo.build(clazz, type, propertyNamingStrategy);
try {
    return asmFactory.createJavaBeanDeserializer(this, beanInfo);
    // } catch (VerifyError e) {
    // e.printStackTrace();
    // return new JavaBeanDeserializer(this, clazz, type);
} catch (NoSuchMethodException ex) {
    return new JavaBeanDeserializer(this, clazz, type);
} catch (JSONException asmError) {
    return new JavaBeanDeserializer(this, beanInfo);
} catch (Exception e) {
    throw new JSONException("create asm deserializer error, " + clazz.getName(), e);
}

因为临时反序列化器我们无法进行debug,所以我们就要想办法去调用他默认的反序列化器。也就是说要让asmEnable为false.

for (FieldInfo fieldInfo : beanInfo.fields) {
    if (fieldInfo.getOnly) {
        asmEnable = false;
        break;
    }

    Class<?> fieldClass = fieldInfo.fieldClass;
    if (!Modifier.isPublic(fieldClass.getModifiers())) {
        asmEnable = false;
        break;
    }

    if (fieldClass.isMemberClass() && !Modifier.isStatic(fieldClass.getModifiers())) {
        asmEnable = false;
        break;
    }

    if (fieldInfo.getMember() != null //
        && !ASMUtils.checkName(fieldInfo.getMember().getName())) {
        asmEnable = false;
        break;
    }

    JSONField annotation = fieldInfo.getAnnotation();
    if (annotation != null //
        && ((!ASMUtils.checkName(annotation.name())) //
            || annotation.format().length() != 0 //
            || annotation.deserializeUsing() != Void.class)) {
        asmEnable = false;
        break;
    }

    if (fieldClass.isEnum()) { // EnumDeserializer
        ObjectDeserializer fieldDeser = this.getDeserializer(fieldClass);
        if (!(fieldDeser instanceof EnumDeserializer)) {
            asmEnable = false;
            break;
        }
    }
}

在这里我们选择上文中这个getOnly,只要getOnly为true,那么asmEnable就为false.
我们看下面的代码,只要方法的参数值不为1,那么就会进入到else。

if (method != null) {
    Class<?>[] types;
    if ((types = method.getParameterTypes()).length == 1) {
        fieldClass = types[0];
        fieldType = method.getGenericParameterTypes()[0];
    } else {
        fieldClass = method.getReturnType();
        fieldType = method.getGenericReturnType();
        getOnly = true;
    }
    this.declaringClass = method.getDeclaringClass();
} else {
    fieldClass = field.getType();
    fieldType = field.getGenericType();
    this.declaringClass = field.getDeclaringClass();
    getOnly = Modifier.isFinal(field.getModifiers());
}

我们前面说过第一个for循环是拿set方法,我们看到如果他set方法的参数不唯一就会直接退出,所以set方法没戏。

Class<?>[] types = method.getParameterTypes();
if (types.length != 1) {
    continue;
}

所以只能为get方法的for循环,如果需要从get进去的话,就需要返回值为Map或者Collection这一些。

if (Collection.class.isAssignableFrom(method.getReturnType()) //
    || Map.class.isAssignableFrom(method.getReturnType()) //
    || AtomicBoolean.class == method.getReturnType() //
    || AtomicInteger.class == method.getReturnType() //
    || AtomicLong.class == method.getReturnType() //
   ) {
    String propertyName;

    JSONField annotation = method.getAnnotation(JSONField.class);
    if (annotation != null && annotation.deserialize()) {
        continue;
    }

    if (annotation != null && annotation.name().length() > 0) {
        propertyName = annotation.name();
    } else {
        propertyName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
    }

    FieldInfo fieldInfo = getField(fieldList, propertyName);
    if (fieldInfo != null) {
        continue;
    }

    if (propertyNamingStrategy != null) {
        propertyName = propertyNamingStrategy.translate(propertyName);
    }

    add(fieldList, new FieldInfo(propertyName, method, null, clazz, type, 0, 0, 0, annotation, null, null));
}

好,关于get的一些要求,我们上述也有讲到。
方法名长度大于4. 非静态方法,以get开头,且第四个字母为大写,无传入参数。返回值是Collection Map .
然后就能newFieldInfo,然后将getOnly改为true,所以我们在我们自己的代码中加入一个Map返回值的getMap方法。
image.png
我们再来调试一遍。这时候asmEnable为false。然后调用到了默认的反序列化器.
到这里,我们捋一遍基础的思路.就是说先按照字符串解析,然后发现有@type就按java对象解析,如果要对java对象解析的话,需要一个反序列化器.我们刚才就是为了拿到他原生的反序列化器.
我们跟进JavaBeanDeserializer看看反序列化流程。
在进行反序列化的过程里面调用了构造方法,调了set.

protected <T> T deserialze(DefaultJSONParser parser, // 
                           Type type, // 
                           Object fieldName, // 
                           Object object, //
                           int features) {
    if (type == JSON.class || type == JSONObject.class) {
        return (T) parser.parse();
    }

    final JSONLexerBase lexer = (JSONLexerBase) parser.lexer; // xxx

    int token = lexer.token();
    if (token == JSONToken.NULL) {
        lexer.nextToken(JSONToken.COMMA);
        return null;
    }

    ParseContext context = parser.getContext();
    if (object != null && context != null) {
        context = context.parent;
    }
    ParseContext childContext = null;

    try {
        Map<String, Object> fieldValues = null;

        if (token == JSONToken.RBRACE) {
            lexer.nextToken(JSONToken.COMMA);
            if (object == null) {
                object = createInstance(parser, type);
            }
            return (T) object;
        }

        if (token == JSONToken.LBRACKET) {
            final int mask = Feature.SupportArrayToBean.mask;
            boolean isSupportArrayToBean = (beanInfo.parserFeatures & mask) != 0 //
                || lexer.isEnabled(Feature.SupportArrayToBean) //
                || (features & mask) != 0
                ;
            if (isSupportArrayToBean) {
                return deserialzeArrayMapping(parser, type, fieldName, object);
            }
        }

        if (token != JSONToken.LBRACE && token != JSONToken.COMMA) {
            if (lexer.isBlankInput()) {
                return null;
            }

            if (token == JSONToken.LITERAL_STRING) {
                String strVal = lexer.stringVal();
                if (strVal.length() == 0) {
                    lexer.nextToken();
                    return null;
                }
            }

            if (token == JSONToken.LBRACKET && lexer.getCurrent() == ']') {
                lexer.next();
                lexer.nextToken();
                return null;
            }

            StringBuffer buf = (new StringBuffer()) //
                .append("syntax error, expect {, actual ") //
                .append(lexer.tokenName()) //
                .append(", pos ") //
                .append(lexer.pos()) //
                ;
            if (fieldName instanceof String) {
                buf //
                    .append(", fieldName ") //
                    .append(fieldName);
            }

            throw new JSONException(buf.toString());
        }

        if (parser.resolveStatus == DefaultJSONParser.TypeNameRedirect) {
            parser.resolveStatus = DefaultJSONParser.NONE;
        }

        for (int fieldIndex = 0;; fieldIndex++) {
            String key = null;
        FieldDeserializer fieldDeser = null;
        FieldInfo fieldInfo = null;
        Class<?> fieldClass = null;
        JSONField feildAnnotation = null;
        if (fieldIndex < sortedFieldDeserializers.length) {
        fieldDeser = sortedFieldDeserializers[fieldIndex];
        fieldInfo = fieldDeser.fieldInfo;
        fieldClass = fieldInfo.fieldClass;
        feildAnnotation = fieldInfo.getAnnotation();
    }

        boolean matchField = false;
        boolean valueParsed = false;

        Object fieldValue = null;
        if (fieldDeser != null) {
        char[] name_chars = fieldInfo.name_chars;
        if (fieldClass == int.class || fieldClass == Integer.class) {
        fieldValue = lexer.scanFieldInt(name_chars);

        if (lexer.matchStat > 0) {
        matchField = true;
        valueParsed = true;
    } else if (lexer.matchStat == JSONLexer.NOT_MATCH_NAME) {
        continue;  
    }
    } else if (fieldClass == long.class || fieldClass == Long.class) {
        fieldValue = lexer.scanFieldLong(name_chars);

        if (lexer.matchStat > 0) {
        matchField = true;
        valueParsed = true;
    } else if (lexer.matchStat == JSONLexer.NOT_MATCH_NAME) {
        continue;  
    }
    } else if (fieldClass == String.class) {
        fieldValue = lexer.scanFieldString(name_chars);

        if (lexer.matchStat > 0) {
        matchField = true;
        valueParsed = true;
    } else if (lexer.matchStat == JSONLexer.NOT_MATCH_NAME) {
        continue;  
    }
    } else if (fieldClass == boolean.class || fieldClass == Boolean.class) {
        fieldValue = lexer.scanFieldBoolean(name_chars);

        if (lexer.matchStat > 0) {
        matchField = true;
        valueParsed = true;
    } else if (lexer.matchStat == JSONLexer.NOT_MATCH_NAME) {
        continue;  
    }
    } else if (fieldClass == float.class || fieldClass == Float.class) {
        fieldValue = lexer.scanFieldFloat(name_chars);

        if (lexer.matchStat > 0) {
        matchField = true;
        valueParsed = true;
    } else if (lexer.matchStat == JSONLexer.NOT_MATCH_NAME) {
        continue;  
    }
    } else if (fieldClass == double.class || fieldClass == Double.class) {
        fieldValue = lexer.scanFieldDouble(name_chars);

        if (lexer.matchStat > 0) {
        matchField = true;
        valueParsed = true;
    } else if (lexer.matchStat == JSONLexer.NOT_MATCH_NAME) {
        continue;  
    }
    } else if (fieldClass.isEnum() // 
        && parser.getConfig().getDeserializer(fieldClass) instanceof EnumDeserializer
        && (feildAnnotation == null || feildAnnotation.deserializeUsing() == Void.class)
        ) {
        if (fieldDeser instanceof DefaultFieldDeserializer) {
        ObjectDeserializer fieldValueDeserilizer = ((DefaultFieldDeserializer) fieldDeser).fieldValueDeserilizer;
        fieldValue = this.scanEnum(lexer, name_chars, fieldValueDeserilizer);

        if (lexer.matchStat > 0) {
        matchField = true;
        valueParsed = true;
    } else if (lexer.matchStat == JSONLexer.NOT_MATCH_NAME) {
        continue;
    }
    }
    } else if (fieldClass == int[].class) {
        fieldValue = lexer.scanFieldIntArray(name_chars);

        if (lexer.matchStat > 0) {
        matchField = true;
        valueParsed = true;
    } else if (lexer.matchStat == JSONLexer.NOT_MATCH_NAME) {
        continue;
    }
    } else if (fieldClass == float[].class) {
        fieldValue = lexer.scanFieldFloatArray(name_chars);

        if (lexer.matchStat > 0) {
        matchField = true;
        valueParsed = true;
    } else if (lexer.matchStat == JSONLexer.NOT_MATCH_NAME) {
        continue;
    }
    } else if (fieldClass == float[][].class) {
        fieldValue = lexer.scanFieldFloatArray2(name_chars);

        if (lexer.matchStat > 0) {
        matchField = true;
        valueParsed = true;
    } else if (lexer.matchStat == JSONLexer.NOT_MATCH_NAME) {
        continue;
    }
    } else if (lexer.matchField(name_chars)) {
        matchField = true;
    } else {
        continue;
    }
    }

        if (!matchField) {
        key = lexer.scanSymbol(parser.symbolTable);

        if (key == null) {
        token = lexer.token();
        if (token == JSONToken.RBRACE) {
        lexer.nextToken(JSONToken.COMMA);
        break;
    }
        if (token == JSONToken.COMMA) {
        if (lexer.isEnabled(Feature.AllowArbitraryCommas)) {
        continue;
    }
    }
    }

        if ("$ref" == key) {
        lexer.nextTokenWithColon(JSONToken.LITERAL_STRING);
        token = lexer.token();
        if (token == JSONToken.LITERAL_STRING) {
        String ref = lexer.stringVal();
        if ("@".equals(ref)) {
        object = context.object;
    } else if ("..".equals(ref)) {
        ParseContext parentContext = context.parent;
        if (parentContext.object != null) {
        object = parentContext.object;
    } else {
        parser.addResolveTask(new ResolveTask(parentContext, ref));
        parser.resolveStatus = DefaultJSONParser.NeedToResolve;
    }
    } else if ("$".equals(ref)) {
        ParseContext rootContext = context;
        while (rootContext.parent != null) {
        rootContext = rootContext.parent;
    }

        if (rootContext.object != null) {
        object = rootContext.object;
    } else {
        parser.addResolveTask(new ResolveTask(rootContext, ref));
        parser.resolveStatus = DefaultJSONParser.NeedToResolve;
    }
    } else {
        parser.addResolveTask(new ResolveTask(context, ref));
        parser.resolveStatus = DefaultJSONParser.NeedToResolve;
    }
    } else {
        throw new JSONException("illegal ref, " + JSONToken.name(token));
    }

        lexer.nextToken(JSONToken.RBRACE);
        if (lexer.token() != JSONToken.RBRACE) {
        throw new JSONException("illegal ref");
    }
        lexer.nextToken(JSONToken.COMMA);

        parser.setContext(context, object, fieldName);

        return (T) object;
    }

        if (JSON.DEFAULT_TYPE_KEY == key) {
        lexer.nextTokenWithColon(JSONToken.LITERAL_STRING);
        if (lexer.token() == JSONToken.LITERAL_STRING) {
        String typeName = lexer.stringVal();
        lexer.nextToken(JSONToken.COMMA);

        if (typeName.equals(beanInfo.typeName)) {
        if (lexer.token() == JSONToken.RBRACE) {
        lexer.nextToken();
        break;
    }
        continue;
    }

        ParserConfig config = parser.getConfig();
        ObjectDeserializer deserizer = getSeeAlso(config, this.beanInfo, typeName);
        Class<?> userType = null;
        if (deserizer == null) {
        userType = TypeUtils.loadClass(typeName, config.getDefaultClassLoader());

        Class<?> expectClass = TypeUtils.getClass(type);
        if (expectClass == null || 
        (userType != null && expectClass.isAssignableFrom(userType))) {
        deserizer = parser.getConfig().getDeserializer(userType);                                        
    } else {
        throw new JSONException("type not match");
    }
    }

        return (T) deserizer.deserialze(parser, userType, fieldName);
    } else {
        throw new JSONException("syntax error");
    }
    }
    }

        if (object == null && fieldValues == null) {
        object = createInstance(parser, type);
        if (object == null) {
        fieldValues = new HashMap<String, Object>(this.fieldDeserializers.length);
    }
        childContext = parser.setContext(context, object, fieldName);
    }

        if (matchField) {
        if (!valueParsed) {
        fieldDeser.parseField(parser, object, type, fieldValues);
    } else {
        if (object == null) {
        fieldValues.put(fieldInfo.name, fieldValue);
    } else if (fieldValue == null) {
        if (fieldClass != int.class //
        && fieldClass != long.class //
        && fieldClass != float.class //
        && fieldClass != double.class //
        && fieldClass != boolean.class //
        ) {
        fieldDeser.setValue(object, fieldValue);
    }
    } else {
        fieldDeser.setValue(object, fieldValue);
    }
        if (lexer.matchStat == JSONLexer.END) {
        break;
    }
    }
    } else {
        boolean match = parseField(parser, key, object, type, fieldValues);
        if (!match) {
        if (lexer.token() == JSONToken.RBRACE) {
        lexer.nextToken();
        break;
    }

        continue;
    } else if (lexer.token() == JSONToken.COLON) {
        throw new JSONException("syntax error, unexpect token ':'");
    }
    }

        if (lexer.token() == JSONToken.COMMA) {
        continue;
    }

        if (lexer.token() == JSONToken.RBRACE) {
        lexer.nextToken(JSONToken.COMMA);
        break;
    }

        if (lexer.token() == JSONToken.IDENTIFIER || lexer.token() == JSONToken.ERROR) {
        throw new JSONException("syntax error, unexpect token " + JSONToken.name(lexer.token()));
    }
    }

        if (object == null) {
        if (fieldValues == null) {
        object = createInstance(parser, type);
        if (childContext == null) {
        childContext = parser.setContext(context, object, fieldName);
    }
        return (T) object;
    }

        FieldInfo[] fieldInfoList = beanInfo.fields;
        int size = fieldInfoList.length;
        Object[] params = new Object[size];
        for (int i = 0; i < size; ++i) {
        FieldInfo fieldInfo = fieldInfoList[i];
        Object param = fieldValues.get(fieldInfo.name);
        if (param == null) {
        Type fieldType = fieldInfo.fieldType;
        if (fieldType == byte.class) {
        param = (byte) 0;
    } else if (fieldType == short.class) {
        param = (short) 0;
    } else if (fieldType == int.class) {
        param = 0;
    } else if (fieldType == long.class) {
        param = 0L;
    } else if (fieldType == float.class) {
        param = 0F;
    } else if (fieldType == double.class) {
        param = 0D;
    } else if (fieldType == boolean.class) {
        param = Boolean.FALSE;
    }
    }
        params[i] = param;
    }

        if (beanInfo.creatorConstructor != null) {
        try {
        object = beanInfo.creatorConstructor.newInstance(params);
    } catch (Exception e) {
        throw new JSONException("create instance error, "
        + beanInfo.creatorConstructor.toGenericString(), e);
    }
    } else if (beanInfo.factoryMethod != null) {
        try {
        object = beanInfo.factoryMethod.invoke(null, params);
    } catch (Exception e) {
        throw new JSONException("create factory method error, " + beanInfo.factoryMethod.toString(), e);
    }
    }
    }

        Method buildMethod = beanInfo.buildMethod;
        if (buildMethod == null) {
        return (T) object;
    }


        Object builtObj;
        try {
        builtObj = buildMethod.invoke(object);
    } catch (Exception e) {
        throw new JSONException("build object error", e);
    }

        return (T) builtObj;
    } finally {
        if (childContext != null) {
        childContext.object = object;
    }
        parser.setContext(context);
    }
    }

下面对这个方法进行拆分.
首先在这里创建了一个实例.调用构造函数.

if (object == null && fieldValues == null) {
    object = createInstance(parser, type);
    if (object == null) {
        fieldValues = new HashMap<String, Object>(this.fieldDeserializers.length);
    }
    childContext = parser.setContext(context, object, fieldName);
}

这步之后,构造函数就会被触发.
然后往后就是赋值.

f (matchField) {
    if (!valueParsed) {
        fieldDeser.parseField(parser, object, type, fieldValues);
    } else {
        if (object == null) {
            fieldValues.put(fieldInfo.name, fieldValue);
        } else if (fieldValue == null) {
            if (fieldClass != int.class //
                && fieldClass != long.class //
                && fieldClass != float.class //
                && fieldClass != double.class //
                && fieldClass != boolean.class //
               ) {
                fieldDeser.setValue(object, fieldValue);
            }
        } else {
            fieldDeser.setValue(object, fieldValue);
        }
        if (lexer.matchStat == JSONLexer.END) {
            break;
        }
    }
}

我们可以跟进setValue.
可以看到最后有一个method.invoke
image.png
method就是我们的方法,然后Object就是我们的类,value就是需要的值.
这时候就会进行一个触发.导致任意方法执行.
注意在get方法也会执行,也就是说,get方法其实是在set方法执行完的下边有一个JSON.toJSON
image.png
最后会调用到这个get,导致RCE。
image.png