Skip to content

Commit 4e05144

Browse files
committed
fix: correctly handle default value for @Instrument updateMajorVersion annotation. #46
1 parent a6b884a commit 4e05144

File tree

3 files changed

+79
-2
lines changed

3 files changed

+79
-2
lines changed

bytekit-core/src/main/java/com/alibaba/bytekit/asm/instrument/InstrumentTemplate.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,10 @@ private void parse(InstrumentParseResult result, byte[] classBytes, boolean trig
185185
// 清除apm类的行号
186186
AsmUtils.removeLineNumbers(classNode);
187187

188-
boolean updateMajorVersion = Boolean.parseBoolean((String) AsmAnnotationUtils.queryAnnotationValue(classNode.visibleAnnotations,
189-
Type.getDescriptor(Instrument.class), "updateMajorVersion"));
188+
// 注意:注解字段值如果等于默认值,编译到 class 文件时不会写入 values 里,这里需要补齐默认值
189+
String updateMajorVersionValue = (String) AsmAnnotationUtils.queryAnnotationValue(classNode.visibleAnnotations,
190+
Type.getDescriptor(Instrument.class), "updateMajorVersion");
191+
boolean updateMajorVersion = updateMajorVersionValue == null || Boolean.parseBoolean(updateMajorVersionValue);
190192

191193
List<String> matchClassList = AsmAnnotationUtils.queryAnnotationArrayValue(classNode.visibleAnnotations,
192194
Type.getDescriptor(Instrument.class), "Class");
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.alibaba.bytekit.asm.inst;
2+
3+
import java.util.Comparator;
4+
5+
import org.springframework.beans.factory.BeanCreationException;
6+
import org.springframework.beans.factory.support.RootBeanDefinition;
7+
8+
import com.alibaba.bytekit.agent.inst.Instrument;
9+
import com.alibaba.bytekit.agent.inst.InstrumentApi;
10+
11+
@Instrument(Class = "org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory")
12+
public abstract class AbstractAutowireCapableBeanFactory_Instrument {
13+
14+
public Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
15+
// 触发 Java8 接口静态方法调用(invokestatic + InterfaceMethodref),用于覆盖 updateMajorVersion 的默认行为
16+
Comparator.naturalOrder();
17+
return InstrumentApi.invokeOrigin();
18+
}
19+
}
20+
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.alibaba.bytekit.asm.instrument;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import org.junit.Test;
6+
import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
7+
8+
import com.alibaba.bytekit.asm.inst.AbstractAutowireCapableBeanFactory_Instrument;
9+
import com.alibaba.bytekit.utils.AsmUtils;
10+
import com.alibaba.bytekit.utils.ClassLoaderUtils;
11+
import com.alibaba.bytekit.utils.VerifyUtils;
12+
import com.alibaba.deps.org.objectweb.asm.tree.ClassNode;
13+
14+
/**
15+
* 覆盖 @Instrument(updateMajorVersion) 的默认值解析逻辑。
16+
*/
17+
public class UpdateMajorVersionDefaultTest {
18+
19+
@Test
20+
public void testUpdateMajorVersionDefaultValue() throws Exception {
21+
byte[] instrumentBytes = ClassLoaderUtils.readBytecode(AbstractAutowireCapableBeanFactory_Instrument.class);
22+
InstrumentTemplate instrumentTemplate = new InstrumentTemplate();
23+
instrumentTemplate.addInstrumentClass(instrumentBytes);
24+
25+
InstrumentParseResult parseResult = instrumentTemplate.build();
26+
assertThat(parseResult.getInstrumentConfigs()).hasSize(1);
27+
28+
InstrumentConfig config = parseResult.getInstrumentConfigs().get(0);
29+
assertThat(config.isUpdateMajorVersion()).isTrue();
30+
31+
Class<?> targetClass = AbstractAutowireCapableBeanFactory.class;
32+
byte[] originBytes = ClassLoaderUtils.readBytecode(targetClass);
33+
34+
ClassNode originNode = AsmUtils.toClassNode(originBytes);
35+
int originMajorVersion = AsmUtils.getMajorVersion(originNode.version);
36+
assertThat(originMajorVersion).isLessThan(52);
37+
38+
InstrumentTransformer transformer = new InstrumentTransformer(parseResult);
39+
byte[] transformedBytes = transformer.transform(targetClass.getClassLoader(),
40+
targetClass.getName().replace('.', '/'), targetClass, targetClass.getProtectionDomain(), originBytes);
41+
assertThat(transformedBytes).isNotNull();
42+
43+
ClassNode transformedNode = AsmUtils.toClassNode(transformedBytes);
44+
int transformedMajorVersion = AsmUtils.getMajorVersion(transformedNode.version);
45+
assertThat(transformedMajorVersion).isGreaterThanOrEqualTo(52);
46+
47+
// 触发 JVM 校验,避免出现 VerifyError: Illegal type at constant pool entry
48+
java.net.URL[] urls = ClassLoaderUtils.getUrls(ClassLoader.getSystemClassLoader());
49+
if (urls != null) {
50+
VerifyUtils.ClassbyteClassLoader cl = new VerifyUtils.ClassbyteClassLoader(urls,
51+
ClassLoader.getSystemClassLoader().getParent());
52+
cl.addClass(targetClass.getName(), transformedBytes);
53+
}
54+
}
55+
}

0 commit comments

Comments
 (0)