Prerequisites
Please check the FAQ, and search existing issues for similar questions before creating a new issue.YOU MAY DELETE THIS PREREQUISITES SECTION.
What version of pinpoint are you using?
v3.0.3
Describe the bug
When the Java service is started, the error message "ClassFormatError: Duplicate method name "_$PINPOINT$_getAsyncContext" with signature "()Lcom.navercorp.pinpoint.bootstrap.context.AsyncContext;" in class file xxx/xxxTask$$SpringCGLIB$$0" is displayed. As a result, the service fails to be started.
Additional context
I analyzed the cause of this error:
The scenario is as follows:
AClazz implements Callable/Runnable/Supplier
BClazz extends AClazz
BClazz is proxied by CGLIB.
In this scenario, the error is reported. The root cause is that Pinpoint injects method collection asynchronous calls to the classes that implement the Callable, Runnable, and Supplier interfaces. When BClazz is proxied by CGLIB, the methods in BClazz are copied, including the injected _$PINPOINT$_getAsyncContext. The class generated by CGLIB is injected by Pinpoint again. As a result, the xxxTask$$SpringCGLIB$$0 class contains two methods with the same signature. As a result, an error is reported during class compliance check.
Currently, the reason for the following scenario is unknown:
AClazz implements Callable/Runnable/Supplier
When AClazz is proxied by CGLIB, no error is reported. According to the debug information, the AClazz proxy class generated by CGLIB does not have the method injected by Pinpoint. However, in the scenario where BClazz is inherited, the method already exists in the BClazz proxy class generated by CGLIB before the Pinpoint injection logic is executed.
Modification Method
The place where the $PINPOINT$_getAsyncContext method is injected is in the addField method of ASMClass. I modified the addMethodNode0 method in the ASMClassNodeAdapter class to check whether a methodNode with the same name already exists in the existing class before adding a new methodNode.
private void addMethodNode0(MethodNode methodNode) {
if (this.classNode.methods == null) {
this.classNode.methods = new ArrayList<>();
}
if (hasMethodNode(methodNode)) {
return;
}
this.classNode.methods.add(methodNode);
}
private boolean hasMethodNode(MethodNode methodNode) {
for (MethodNode method : this.classNode.methods) {
if (method.name.equals(methodNode.name) && method.desc.equals(methodNode.desc)) {
return true;
}
}
return false;
}
Prerequisites
Please check the FAQ, and search existing issues for similar questions before creating a new issue.YOU MAY DELETE THIS PREREQUISITES SECTION.
What version of pinpoint are you using?
v3.0.3
Describe the bug
When the Java service is started, the error message "ClassFormatError: Duplicate method name "_$PINPOINT$_getAsyncContext" with signature "()Lcom.navercorp.pinpoint.bootstrap.context.AsyncContext;" in class file xxx/xxxTask$$SpringCGLIB$$0" is displayed. As a result, the service fails to be started.
Additional context
I analyzed the cause of this error:
The scenario is as follows:
AClazz implements Callable/Runnable/Supplier
BClazz extends AClazz
BClazz is proxied by CGLIB.
In this scenario, the error is reported. The root cause is that Pinpoint injects method collection asynchronous calls to the classes that implement the Callable, Runnable, and Supplier interfaces. When BClazz is proxied by CGLIB, the methods in BClazz are copied, including the injected _$PINPOINT$_getAsyncContext. The class generated by CGLIB is injected by Pinpoint again. As a result, the xxxTask$$SpringCGLIB$$0 class contains two methods with the same signature. As a result, an error is reported during class compliance check.
Currently, the reason for the following scenario is unknown:
AClazz implements Callable/Runnable/Supplier
When AClazz is proxied by CGLIB, no error is reported. According to the debug information, the AClazz proxy class generated by CGLIB does not have the method injected by Pinpoint. However, in the scenario where BClazz is inherited, the method already exists in the BClazz proxy class generated by CGLIB before the Pinpoint injection logic is executed.
Modification Method
The place where the
$PINPOINT$_getAsyncContextmethod is injected is in theaddFieldmethod of ASMClass. I modified theaddMethodNode0method in theASMClassNodeAdapterclass to check whether a methodNode with the same name already exists in the existing class before adding a new methodNode.