Skip to content

ClassFormatError: Duplicate method name "_$PINPOINT$_getAsyncContext" with signature "()Lcom.navercorp.pinpoint.bootstrap.context.AsyncContext;" #13864

Description

@spurs30

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;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions