alibaba / alibaba/one-java-agent
SpringBoot fatjar模式下,Instrument方法中出现强转逻辑导致asm报 java.lang.TypeNotPresentException: Type com/one/agent/app/api/model/EmployeeAndy not present
- Dominant language
- Java
- Stars
- 579
- Forks
- 128
- PR merge metrics
- No merged PRs in 30d
Description
异常栈:
```
2023-03-14 10:32:39 [main] ERROR c.a.o.s.OneAgentClassFileTransformer -transform error, loader: org.springframework.boot.loader.LaunchedURLClassLoader@6a03bcb1, className: com/saleson/oneagent/springboot/app/demo/service/EmployeeServiceImpl, transformer: com.alibaba.bytekit.asm.instrument.InstrumentTransformer@293d0107
java.lang.TypeNotPresentException: Type com/one/agent/app/api/model/EmployeeAndy not present
at com.alibaba.deps.org.objectweb.asm.ClassWriter.getCommonSuperClass(ClassWriter.java:1041)
at com.alibaba.deps.org.objectweb.asm.SymbolTable.addMergedType(SymbolTable.java:1202)
at com.alibaba.deps.org.objectweb.asm.Frame.merge(Frame.java:1299)
at com.alibaba.deps.org.objectweb.asm.Frame.merge(Frame.java:1197)
at com.alibaba.deps.org.objectweb.asm.MethodWriter.computeAllFrames(MethodWriter.java:1611)
at com.alibaba.deps.org.objectweb.asm.MethodWriter.visitMaxs(MethodWriter.java:1547)
at com.alibaba.deps.org.objectweb.asm.tree.MethodNode.accept(MethodNode.java:767)
at com.alibaba.deps.org.objectweb.asm.tree.MethodNode.accept(MethodNode.java:647)
at com.alibaba.deps.org.objectweb.asm.tree.ClassNode.accept(ClassNode.java:451)
at com.alibaba.bytekit.utils.AsmUtils.toBytes(AsmUtils.java:86)
at com.alibaba.bytekit.asm.instrument.InstrumentTransformer.transform(InstrumentTransformer.java:60)
at com.alibaba.oneagent.service.OneAgentClassFileTransformer.transform(OneAgentClassFileTransformer.java:35)
at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:473)
at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at org.springframework.util.ClassUtils.forName(ClassUtils.java:284)
at org.springframework.beans.factory.support.AbstractBeanDefinition.resolveBeanClass(AbstractBeanDefinition.java:469)
at org.springframework.beans.factory.support.AbstractBeanFactory.doResolveBeanClass(AbstractBeanFactory.java:1621)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1548)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:704)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:674)
at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1684)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:570)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:542)
at org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration$DispatcherServletRegistrationCondition.checkServletRegistration(DispatcherServletAutoConfiguration.java:187)
at org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration$DispatcherServletRegistrationCondition.getMatchOutcome(DispatcherServletAutoConfiguration.java:167)
at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47)
at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:108)
at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:225)
at org.springframework.context.annotation.ConfigurationClassParser.processMemberClasses(ConfigurationClassParser.java:371)
at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:271)
at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:249)
at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:599)
at org.springframework.context.annotation.ConfigurationClassParser.access$800(ConfigurationClassParser.java:110)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGroupingHandler.lambda$processGroupImports$1(ConfigurationClassParser.java:812)
at java.util.ArrayList.forEach(ArrayList.java:1259)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGroupingHandler.processGroupImports(ConfigurationClassParser.java:809)
at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorHandler.process(ConfigurationClassParser.java:780)
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:192)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:331)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:247)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:311)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:112)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:746)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:564)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:745)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:423)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1317)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306)
at com.saleson.oneagent.springboot.app.demo.AppDemoApplication.main(AppDemoApplication.java:21)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
Caused by: java.lang.ClassNotFoundException: com.one.agent.app.api.model.EmployeeAndy
at java.net.URLClassLoader.findClass(URLClassLoader.java:387)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at com.alibaba.deps.org.objectweb.asm.ClassWriter.getCommonSuperClass(ClassWriter.java:1039)
... 72 common frames omitted
```
复现逻辑:
1. 在common module中新建2个类,Employee, 以及其子类EmployeeAndy。
2. 新建springboot module, 并添加spring-boot-maven-plugin 将其编译为springboot fatjar。
3. 在instrument-lib.jar中添加Instrument类,并在增强方法中加入强转代码:
```
@Instrument(Interface = {"com.one.agent.app.api.EmployeeService"})
public class EmployeeServiceInst {
public void check(Employee employee) {
if(employee instanceof EmployeeAndy){
employee = (EmployeeAndy) employee;
System.out.println("EmployeeServiceInst.check employee type is " + EmployeeAndy.class);
}
InstrumentApi.invokeOrigin();
}
```
4. 添加one-java-agent参数运行springboot fatjar, 在oneagent.log中出现上述异常日志。
原因:
反复排查后,发现asm在计算方法的最大栈空间和最大本地变量数时,遇到强转逻辑会执行到ClassWriter.getCommonSuperClass()方法,该方法会去尝试加载被转换对象的class和转换的目标class,进行assignable from比对判断。问题在于此方法中的ClassLoader是Launcher$AppClassLoader, debug截图如下:

在springboot fatjar 运行模式下, Launcher$AppClassLoader是无法加载到springboot fatjar中的class和资源,所以导致此处抛出ClassNotFoundException, 被捕获后包装成TypeNotPresentException抛出。
[demo-all.zip](https://github.com/alibaba/one-java-agent/files/10965421/demo-all.zip)
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by reproducing the failure with demo-all.zip and the Spring Boot fat JAR entry point at AppDemoApplication.main. Trace the transformation through OneAgentClassFileTransformer, InstrumentTransformer.transform, and AsmUtils.toBytes into ASM's ClassWriter.getCommonSuperClass. Done means the EmployeeService instrumentation with the EmployeeAndy cast runs in fat-JAR mode without the reported ClassNotFoundException or TypeNotPresentException.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring-boot
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100