I. Problem description
When the service is started, the interface is called normally. However, after running for some time, when the interface is called again, the following exceptions will be found:
Method threw 'com.alibaba.fastjson.JSONException' exception: default constructor not found. XXX
Copy the code
See above exception message is the Test classThe default constructor could not be found
After a while, the same problem will occur again. Very weird. The definition of the Test class is as follows:
data class Test(val name: String)
Copy the code
As you can see, the Test class does not have a default constructor. It seems natural to throw the above exception, but there are two problems:
- Why is deserialization normal at first?
- What causes subsequent deserialization to fail?
Second, answer the question
From the above exception information, you can find the code segment that threw the exception, as follows:
Class: com. Alibaba. Fastjson. Util. JavaBeanInfoif(paramNames ! =null&& types.length == paramnames.length) {code omitted here} esle {throw new JSONException("default constructor not found. " + clazz);
}
Copy the code
As can be seen from the above logic, as long asparamNames
fornull
或 types.length ! = paramNames.length
I’m going to throw an exception. Follow up and find it hereparamNames
Where the value is assigned, as shown below:Into theTypeUtils.getKoltinConstructorParameters
This method finds all the returnsnull
After code simplification, the following request:
Class: com. Alibaba. Fastjson. Util. TypeUtilspublicThe static String [] getKoltinConstructorParameters (Class clazz) {code omitted hereif (kotlin_kclass_constructor == null) {return null; } the code is omitted hereif (kotlin_error){
return null;
}
try{code omitted here}catch(Throwable e){
e.printStackTrace();
kotlin_error = true;
}
return null;
}
Copy the code
As you can see from the code above, there are three cases where a path returns NULL:
kotlin_kclass_constructor
fornull
kotlin_error
fortrue
- Return at last when none of the previous normal cases had returned
null
One of the more suspicious bits is kotlin_error, and find its definition
private static volatile boolean kotlin_error;
Copy the code
Kotlin_error is a private static variable!! And once it is set to true, there is no place to change it to false. That’s basically it. The logic in the try above is wrong. It just prints the stack and marks kotlin_error as true. The background all adjustable TypeUtils getKoltinConstructorParameters method will return null. This leads directly to the default constructor not found we initially saw. The exception. Here we find the answers to the above two questions:
- in
kotlin_error
It’s not marked astrue
Is normal kotlin_error
Once marked asfalse
The subsequent deserialization will be abnormal
Why is kotlin_error marked true
So, whykotlin_error
It’s going to be labeledtrue
? We find the log information for printing the stack, as shown below:In the originalTypeUtils.getKoltinConstructorParameters
Method throws an NPE exception. Find the log corresponding to the previous request interface and find that the return value of the interface has a variable assignedUnit
whenUnit
Type this method raises an NPE exception, as shown in the code comment below:
try{
Object constructor = null;
// clazz is class kotlin.unit
Object kclassImpl = kotlin_kclass_constructor.newInstance(clazz);
// Kotlin. Unit has no constructor, so there are no elements in 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;
}
// Since there are no elements in it that have not been assigned to the above for loop, constructor remains null and the invoke method below throws an NPE exception (the following line has the number of lines: 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();
// Kotlin_error is set to true after an NPE exception is raised above
kotlin_error = true;
}
Copy the code