一、问题描述
服务刚启动时调用接口都是正常的,但是运行一段时间后,再调用接口时就会发现以下异常:
Method threw 'com.alibaba.fastjson.JSONException' exception: default constructor not found. XXX
看到上面异常信息是Test类
找不到默认构造函数
,再重启服务一切又正常了,过一段时间又会出现同样的问题,非常诡异,Test类的定义如下:
data class Test(val name: String)
可以看到Test类确实是没有默认构造函数,抛出上面的异常貌似是理所当然的,但是有两个疑问点:
- 为什么刚开始反序列化是正常的?
- 是什么原因导致后面反序列化一直失败?
二、疑点解答
通过上面的异常信息,找到抛出异常的代码段,精简后如下所示:
类:com.alibaba.fastjson.util.JavaBeanInfo
if (paramNames != null && types.length == paramNames.length) {
此处代码省略
} esle {
throw new JSONException("default constructor not found. " + clazz);
}
由上面的判断逻辑可以看到,只要paramNames
为null
或 types.length != paramNames.length
就会抛异常了。再往前跟进找到给paramNames
赋值的地方,如下图所示:
进到
TypeUtils.getKoltinConstructorParameters
这个方法,找到所有返回null
的路径,代码精简后如下所求:
类:com.alibaba.fastjson.util.TypeUtils
public static String[] getKoltinConstructorParameters(Class clazz){
此处代码省略
if (kotlin_kclass_constructor == null){
return null;
}
此处代码省略
if (kotlin_error){
return null;
}
try{
此处代码省略
} catch(Throwable e){
e.printStackTrace();
kotlin_error = true;
}
return null;
}
由上面的代码可以看到,返回null
的路径有三种情况:
kotlin_kclass_constructor
为null
kotlin_error
为true
- 之前所有的正常情况都没有返回的情况下,最后返回
null
其中比较可疑的是kotlin_error
这个标记位,再找到它的定义
private static volatile boolean kotlin_error;
kotlin_error
是一个私有的静态变量
!!!而且一旦设置为true
,再也没有地方将其更改变为false
。这样就基本确定了,应该是上面的try所包含的逻辑出现了问题,它只打印了一下堆栈信息,就把kotlin_error
标记成了true
,后台所有调TypeUtils.getKoltinConstructorParameters
方法都会返回null
。这样就会直接导致我们最初看到的default constructor not found.
异常。到此我们就找到上面两个疑问点的答案:
- 在
kotlin_error
没有被标记为true
时都是正常的 kotlin_error
一旦被标记为false
后面的反序列化就会异常
三、kotlin_error 为什么会被标记为 true 呢
那么,至于为什么kotlin_error
会被标记为true
呢?我们找到打印堆栈的日志信息,如下图所示:
原来在
TypeUtils.getKoltinConstructorParameters
的方法中抛了一个NPE的异常。找到日志对应之前的请求接口,发现接口的返回值中有一个变量被赋值成了Unit
,当Unit
类型执行此方法就会抛出NPE的异常,详见下面代码注释:
try{
Object constructor = null;
// 此时 clazz 为 class kotlin.Unit
Object kclassImpl = kotlin_kclass_constructor.newInstance(clazz);
// kotlin.Unit 没有构造函数,所以 it 中没有元素
Iterable it = (Iterable) kotlin_kclass_getConstructors.invoke(kclassImpl);
for(Iterator iterator = it.iterator(); iterator.hasNext(); iterator.hasNext()){
Object item = iterator.next();
List parameters = (List) kotlin_kfunction_getParameters.invoke(item);
if (constructor != null && parameters.size() == 0) {
continue;
}
constructor = item;
}
// 因为 it 中没有元素没有进入上面的for循环中赋值,所以constructor还是为null,在下面invoke方法就会抛出NPE的异常(下面这一行的行数为:2862)
List parameters = (List) kotlin_kfunction_getParameters.invoke(constructor);
String[] names = new String[parameters.size()];
for(int i = 0; i < parameters.size(); i++){
Object param = parameters.get(i);
names[i] = (String) kotlin_kparameter_getName.invoke(param);
}
return names;
} catch(Throwable e){
e.printStackTrace();
//上面抛出NPE异常后,就会将kotlin_error设置为true
kotlin_error = true;
}