Log4j1.x升级2.x运行PowerMock测试报invalid constant type:18错误
Log4j版本迁移后PowerMock类转换失败问题
问题现象
将老旧遗留应用从Log4j 1.x版本迁移至2.x版本时,运行测试用例抛出如下异常,参考相关排查帖操作后问题未解决:
java.lang.IllegalStateException: Failed to transform class with name com.ABCTest. Reason: java.io.IOException: invalid constant type: 18 at org.powermock.core.classloader.MockClassLoader.loadMockClass(MockClassLoader.java:283) at org.powermock.core.classloader.MockClassLoader.loadModifiedClass(MockClassLoader.java:192) at org.powermock.core.classloader.DeferSupportingClassLoader.loadClass(DeferSupportingClassLoader.java:71) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:348) at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.createDelegatorFromClassloader(JUnit4TestSuiteChunkerImpl.java:161) at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.createDelegatorFromClassloader(JUnit4TestSuiteChunkerImpl.java:48) at org.powermock.tests.utils.impl.AbstractTestSuiteChunkerImpl.createTestDelegators(AbstractTestSuiteChunkerImpl.java:113) at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.<init>(JUnit4TestSuiteChunkerImpl.java:71) at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.<init>(AbstractCommonPowerMockRunner.java:32) at org.powermock.modules.junit4.PowerMockRunner.<init>(PowerMockRunner.java:34) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:31) at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:24) at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57) at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:29) at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57) at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:24) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createUnfilteredTest(JUnit4TestLoader.java:90) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:76) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:49) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:526) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210) Caused by: java.lang.RuntimeException: java.io.IOException: invalid constant type: 18 at javassist.CtClassType.getClassFile2(CtClassType.java:207) at javassist.CtClassType.getModifiers(CtClassType.java:370) at javassist.CtClassType.isInterface(CtClassType.java:358) at org.powermock.core.transformers.impl.ClassMockTransformer.transformMockClass(ClassMockTransformer.java:39) at org.powermock.core.transformers.impl.AbstractMainMockTransformer.transform(AbstractMainMockTransformer.java:247) at org.powermock.core.classloader.MockClassLoader.loadMockClass(MockClassLoader.java:264) ... 28 more
环境依赖
项目核心Maven依赖树如下:
[INFO] +- org.assertj:assertj-core:jar:3.5.1:test [INFO] +- junit:junit:jar:4.8.2:test [INFO] +- org.mockito:mockito-core:jar:1.10.19:test [INFO] | +- org.hamcrest:hamcrest-core:jar:1.1:test [INFO] | \- org.objenesis:objenesis:jar:2.1:test [INFO] +- org.powermock:powermock-module-junit4:jar:1.6.5:test [INFO] | \- org.powermock:powermock-module-junit4-common:jar:1.6.5:test [INFO] | +- org.powermock:powermock-core:jar:1.6.5:test [INFO] | | \- org.javassist:javassist:jar:3.20.0-GA:test [INFO] | \- org.powermock:powermock-reflect:jar:1.6.5:test [INFO] +- org.powermock:powermock-api-mockito:jar:1.6.5:test [INFO] | \- org.powermock:powermock-api-mockito-common:jar:1.6.5:test [INFO] | \- org.powermock:powermock-api-support:jar:1.6.5:test [INFO] +- commons-lang:commons-lang:jar:2.4:compile [INFO] +- commons-codec:commons-codec:jar:1.6:compile [INFO] +- org.mybatis:mybatis-spring:jar:2.0.1:compile [INFO] +- org.mybatis:mybatis:jar:3.5.1:compile [INFO] +- com.sybase:jconnect:jar:7.0.7:compile [INFO] +- commons-collections:commons-collections:jar:3.2.1:compile [INFO] +- jdbc:jcon3:jar:0:compile [INFO] +- commons-dbcp:commons-dbcp:jar:1.4:compile [INFO] | \- commons-pool:commons-pool:jar:1.5.4:compile [INFO] +- javax.jms:jms:jar:1.1:compile [INFO] +- javax.mail:mail:jar:1.4.5:compile [INFO] | \- javax.activation:activation:jar:1.1:compile [INFO] +- org.slf4j:slf4j-api:jar:1.5.6:compile [INFO] +- org.slf4j:slf4j-log4j12:jar:1.5.6:compile [INFO] +- org.springframework:spring-test:jar:3.2.9.RELEASE:test [INFO] +- com.ubs.gfs.sbl.halo:HaloAxisWSClient:jar:29.3.1:compile [INFO] +- antlr:antlr:jar:2.7.7:compile [INFO] +- com.ibm.mq:com.ibm.mq.allclient:jar:9.1.2.0:compile [INFO] | +- org.bouncycastle:bcprov-jdk15on:jar:1.60:compile [INFO] | +- org.bouncycastle:bcpkix-jdk15on:jar:1.60:compile [INFO] | \- javax.jms:javax.jms-api:jar:2.0.1:compile [INFO] +- com.ibm.mq:connector:jar:7.0.1.8:compile [INFO] +- axis:axis:jar:1.4:compile [INFO] | +- org.apache.axis:axis-jaxrpc:jar:1.4:compile [INFO] | +- org.apache.axis:axis-saaj:jar:1.4:compile [INFO] | \- commons-discovery:commons-discovery:jar:0.2:runtime [INFO] +- wsdl4j:wsdl4j:jar:1.6.2:compile [INFO] +- com.oracle:ojdbc6:jar:12.1.0.2:compile [INFO] \- org.apache.poi:poi:jar:3.0.2-FINAL:compile
已尝试操作
- 参考公开问题排查帖排查,未解决
- 手动指定javassist依赖版本为3.18.2-GA,问题仍存在,对应依赖配置如下:
<dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.18.2-GA</version> </dependency>
根因分析
报错invalid constant type: 18的核心原因是当前使用的PowerMock 1.6.5版本配套的Javassist字节码处理工具存在兼容性缺陷,无法识别Java 8引入的常量池类型CONSTANT_InvokeDynamic(常量tag值为18)。手动将Javassist降级到3.18.2-GA的操作反而进一步降低了字节码兼容性,无法解决问题。同时当前项目还存在Log4j迁移后的日志依赖冲突问题,会加剧类加载阶段的异常。
解决步骤
按以下顺序操作即可修复问题:
- 升级PowerMock相关依赖到1.7.4版本(1.x系列稳定版,原生修复了Java 8字节码解析bug),配套将JUnit升级到4.12及以上版本,保持Mockito 1.10.19版本即可,对应依赖配置:
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>1.7.4</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito</artifactId> <version>1.7.4</version> <scope>test</scope> </dependency>
- 移除手动添加的低版本javassist依赖,若存在其他依赖引入的javassist版本冲突,显式指定javassist版本为3.24.0-GA,该版本完整支持Java 8所有字节码特性:
<dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.24.0-GA</version> <scope>test</scope> </dependency>
- 修正Log4j2迁移的依赖配置,删除原有
org.slf4j:slf4j-log4j12依赖,替换为Log4j2对应的SLF4J绑定包,避免日志桥接冲突:
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.17.2</version> <!-- 与项目引入的Log4j2核心包版本保持一致即可 --> </dependency>
- 执行
mvn clean test命令,全量清理历史编译的class缓存后重新运行测试,即可解决该报错。
内容的提问来源于stack exchange,提问作者PAA
相关产品推荐
相关产品推荐

