一、问题描述
服务刚启动时调用接口都是正常的,但是运行一段时间后,再调用接口时就会发现以下异常:
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为nullkotlin_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;
}