This is an automated email from the ASF dual-hosted git repository.
wusheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-java.git
The following commit(s) were added to refs/heads/main by this push:
new 529d6d7eb3 fix parent class enhance issue (#757)
529d6d7eb3 is described below
commit 529d6d7eb31db1306081d078a0689e84201cb3c4
Author: tjuwangning <[email protected]>
AuthorDate: Wed May 28 11:26:05 2025 +0800
fix parent class enhance issue (#757)
---
CHANGES.md | 1 +
.../plugin/AbstractClassEnhancePluginDefine.java | 8 +++
.../enhance/ClassEnhancePluginDefine.java | 4 ++
.../enhance/v2/ClassEnhancePluginDefineV2.java | 4 ++
.../apm/agent/bytebuddy/biz/ChildBar.java | 27 ++++++++++
.../apm/agent/bytebuddy/biz/ParentBar.java | 26 +++++++++
.../bytebuddy/cases/AbstractInterceptTest.java | 27 +++++++++-
.../agent/bytebuddy/cases/ReTransform4Test.java | 62 ++++++++++++++++++++++
8 files changed, 157 insertions(+), 2 deletions(-)
diff --git a/CHANGES.md b/CHANGES.md
index 8affde9592..8e58c3459d 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -11,6 +11,7 @@ Release Notes.
* Agent kernel services could be not-booted-yet as
ServiceManager#INSTANCE#boot executed after agent transfer
initialization. Delay so11y metrics#build when the services are not ready to
avoid MeterService status is not
initialized.
+* Fix retransform failure when enhancing both parent and child classes.
All issues and pull requests are
[here](https://github.com/apache/skywalking/milestone/236?closed=1)
diff --git
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/AbstractClassEnhancePluginDefine.java
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/AbstractClassEnhancePluginDefine.java
index c53e54f0fa..f0ab14a75b 100644
---
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/AbstractClassEnhancePluginDefine.java
+++
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/AbstractClassEnhancePluginDefine.java
@@ -51,6 +51,14 @@ public abstract class AbstractClassEnhancePluginDefine {
* New field name.
*/
public static final String CONTEXT_ATTR_NAME = "_$EnhancedClassField_ws";
+ /**
+ * Getter method name.
+ */
+ public static final String CONTEXT_GETTER_NAME =
"getSkyWalkingDynamicField";
+ /**
+ * Setter method name.
+ */
+ public static final String CONTEXT_SETTER_NAME =
"setSkyWalkingDynamicField";
/**
* Main entrance of enhancing the class.
diff --git
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/ClassEnhancePluginDefine.java
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/ClassEnhancePluginDefine.java
index b595d89e92..ec6628fe95 100644
---
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/ClassEnhancePluginDefine.java
+++
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/ClassEnhancePluginDefine.java
@@ -19,6 +19,7 @@
package org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance;
import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FieldAccessor;
@@ -102,6 +103,9 @@ public abstract class ClassEnhancePluginDefine extends
AbstractClassEnhancePlugi
newClassBuilder = newClassBuilder.defineField(
CONTEXT_ATTR_NAME, Object.class, ACC_PRIVATE |
ACC_VOLATILE)
.implement(EnhancedInstance.class)
+
.defineMethod(CONTEXT_GETTER_NAME, Object.class, Visibility.PUBLIC)
+
.intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME))
+
.defineMethod(CONTEXT_SETTER_NAME, void.class,
Visibility.PUBLIC).withParameters(Object.class)
.intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME));
context.extendObjectCompleted();
}
diff --git
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/ClassEnhancePluginDefineV2.java
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/ClassEnhancePluginDefineV2.java
index 8ea6cdfb99..3423ac1392 100644
---
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/ClassEnhancePluginDefineV2.java
+++
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/ClassEnhancePluginDefineV2.java
@@ -18,6 +18,7 @@
package org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2;
import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FieldAccessor;
@@ -135,6 +136,9 @@ public abstract class ClassEnhancePluginDefineV2 extends
AbstractClassEnhancePlu
newClassBuilder = newClassBuilder.defineField(
CONTEXT_ATTR_NAME, Object.class, ACC_PRIVATE |
ACC_VOLATILE)
.implement(EnhancedInstance.class)
+
.defineMethod(CONTEXT_GETTER_NAME, Object.class, Visibility.PUBLIC)
+
.intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME))
+
.defineMethod(CONTEXT_SETTER_NAME, void.class,
Visibility.PUBLIC).withParameters(Object.class)
.intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME));
context.extendObjectCompleted();
}
diff --git
a/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/biz/ChildBar.java
b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/biz/ChildBar.java
new file mode 100644
index 0000000000..e7ac8d49ff
--- /dev/null
+++
b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/biz/ChildBar.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.agent.bytebuddy.biz;
+
+public class ChildBar extends ParentBar {
+
+ public String sayHelloChild() {
+ return "Joe";
+ }
+
+}
diff --git
a/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/biz/ParentBar.java
b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/biz/ParentBar.java
new file mode 100644
index 0000000000..6113b4c41a
--- /dev/null
+++
b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/biz/ParentBar.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.agent.bytebuddy.biz;
+
+public class ParentBar {
+
+ public String sayHelloParent() {
+ return "Joe";
+ }
+}
diff --git
a/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/AbstractInterceptTest.java
b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/AbstractInterceptTest.java
index ba9cf4d372..627fc8888d 100644
---
a/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/AbstractInterceptTest.java
+++
b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/AbstractInterceptTest.java
@@ -24,6 +24,7 @@ import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.agent.builder.SWAgentBuilderDefault;
import net.bytebuddy.agent.builder.SWDescriptionStrategy;
import net.bytebuddy.agent.builder.SWNativeMethodStrategy;
+import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.implementation.FieldAccessor;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.SWImplementationContextFactory;
@@ -38,6 +39,7 @@ import
org.apache.skywalking.apm.agent.bytebuddy.SWAsmVisitorWrapper;
import org.apache.skywalking.apm.agent.bytebuddy.SWAuxiliaryTypeNamingStrategy;
import org.apache.skywalking.apm.agent.bytebuddy.SWClassFileLocator;
import org.apache.skywalking.apm.agent.bytebuddy.biz.BizFoo;
+import org.apache.skywalking.apm.agent.bytebuddy.biz.ChildBar;
import
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.junit.Assert;
import org.junit.BeforeClass;
@@ -58,11 +60,15 @@ import java.util.List;
import static net.bytebuddy.jar.asm.Opcodes.ACC_PRIVATE;
import static net.bytebuddy.jar.asm.Opcodes.ACC_VOLATILE;
import static
org.apache.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine.CONTEXT_ATTR_NAME;
+import static
org.apache.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine.CONTEXT_GETTER_NAME;
+import static
org.apache.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine.CONTEXT_SETTER_NAME;
public class AbstractInterceptTest {
public static final String BIZ_FOO_CLASS_NAME =
"org.apache.skywalking.apm.agent.bytebuddy.biz.BizFoo";
public static final String PROJECT_SERVICE_CLASS_NAME =
"org.apache.skywalking.apm.agent.bytebuddy.biz.ProjectService";
public static final String DOC_SERVICE_CLASS_NAME =
"org.apache.skywalking.apm.agent.bytebuddy.biz.DocService";
+ public static final String PARENT_BAR_CLASS_NAME =
"org.apache.skywalking.apm.agent.bytebuddy.biz.ParentBar";
+ public static final String CHILD_BAR_CLASS_NAME =
"org.apache.skywalking.apm.agent.bytebuddy.biz.ChildBar";
public static final String SAY_HELLO_METHOD = "sayHello";
public static final int BASE_INT_VALUE = 100;
public static final String CONSTRUCTOR_INTERCEPTOR_CLASS =
"constructorInterceptorClass";
@@ -85,6 +91,20 @@ public class AbstractInterceptTest {
}
};
+ protected static void callBar(int round) {
+ Log.info("-------------");
+ Log.info("callChildBar: " + round);
+ // load target class
+ String strResultChild = new ChildBar().sayHelloChild();
+ Log.info("result: " + strResultChild);
+
+ String strResultParent = new ChildBar().sayHelloParent();
+ Log.info("result: " + strResultParent);
+
+ Assert.assertEquals("String value is unexpected", "John",
strResultChild);
+ Assert.assertEquals("String value is unexpected", "John",
strResultParent);
+ }
+
protected static void callBizFoo(int round) {
Log.info("-------------");
Log.info("callBizFoo: " + round);
@@ -115,7 +135,7 @@ public class AbstractInterceptTest {
protected static void checkInterface(Class testClass, Class interfaceCls) {
Assert.assertTrue("Check interface failure, the test class: " +
testClass + " does not implement the expected interface: " + interfaceCls,
- EnhancedInstance.class.isAssignableFrom(BizFoo.class));
+ EnhancedInstance.class.isAssignableFrom(testClass));
}
protected static void checkErrors() {
@@ -195,6 +215,9 @@ public class AbstractInterceptTest {
builder = builder.defineField(
CONTEXT_ATTR_NAME,
Object.class, ACC_PRIVATE | ACC_VOLATILE)
.implement(EnhancedInstance.class)
+ .defineMethod(CONTEXT_GETTER_NAME,
Object.class, Visibility.PUBLIC)
+
.intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME))
+ .defineMethod(CONTEXT_SETTER_NAME,
void.class, Visibility.PUBLIC).withParameters(Object.class)
.intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME));
}
return builder;
@@ -223,7 +246,7 @@ public class AbstractInterceptTest {
ClassFileTransformer classFileTransformer = new ClassFileTransformer()
{
@Override
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[]
classfileBuffer) throws IllegalClassFormatException {
- if (className.endsWith("BizFoo") ||
className.endsWith("ProjectService") || className.endsWith("DocService")) {
+ if (className.endsWith("BizFoo") ||
className.endsWith("ProjectService") || className.endsWith("DocService") ||
className.endsWith("ChildBar") || className.endsWith("ParentBar")) {
Log.error(msg + className);
ByteArrayOutputStream outputStream = new
ByteArrayOutputStream();
ClassReader cr = new ClassReader(classfileBuffer);
diff --git
a/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/ReTransform4Test.java
b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/ReTransform4Test.java
new file mode 100644
index 0000000000..877dd416e7
--- /dev/null
+++
b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/ReTransform4Test.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.agent.bytebuddy.cases;
+
+import net.bytebuddy.agent.ByteBuddyAgent;
+import org.apache.skywalking.apm.agent.bytebuddy.biz.ChildBar;
+import org.apache.skywalking.apm.agent.bytebuddy.biz.ParentBar;
+import
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.junit.Test;
+
+import java.lang.instrument.Instrumentation;
+
+public class ReTransform4Test extends AbstractReTransformTest {
+
+ @Test
+ public void testInterceptConstructor() throws Exception {
+ Instrumentation instrumentation = ByteBuddyAgent.install();
+
+ // install transformer
+ installMethodInterceptor(PARENT_BAR_CLASS_NAME, "sayHelloParent", 1);
+ installMethodInterceptor(CHILD_BAR_CLASS_NAME, "sayHelloChild", 1);
+ // implement EnhancedInstance
+ installInterface(PARENT_BAR_CLASS_NAME);
+ installInterface(CHILD_BAR_CLASS_NAME);
+
+ // call target class
+ callBar(1);
+
+ // check interceptors
+ checkInterface(ParentBar.class, EnhancedInstance.class);
+ checkInterface(ChildBar.class, EnhancedInstance.class);
+ checkErrors();
+
+ installTraceClassTransformer("Trace class: ");
+
+ // do retransform
+ reTransform(instrumentation, ChildBar.class);
+
+ // check interceptors
+ checkInterface(ParentBar.class, EnhancedInstance.class);
+ checkInterface(ChildBar.class, EnhancedInstance.class);
+ checkErrors();
+ }
+
+}
+