java.lang.ClassFormatError: Invalid method Code length while using PowerMock

java.lang.ClassFormatError: Invalid method Code length while using PowerMock

我是 运行 JUnit 案例,在 jdk7 中使用 PowerMock,使用以下库:

cglib-nodep-2.2.2.jar
javassist-3.19.0-GA.jar
junit-4.12.jar
mockito-all-1.10.19.jar
objenesis-2.1.jar
powermock-mockito-1.6.2-full.jar

下面是我使用 PowerMock 的单元测试的代码片段

@RunWith(PowerMockRunner.class)
@PrepareForTest(ValidateBindingImpl.class)
public class ValidateBindingImplTest{

//more code follows
}

执行此测试用例时出现以下错误:

java.lang.ClassFormatError: Invalid method Code length 119842 in class file com/v1/ValidateBindingImpl
    at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.lang.ClassLoader.defineClass(ClassLoader.java:465)
at org.powermock.core.classloader.MockClassLoader.loadMockClass(MockClassLoader.java:269)
at org.powermock.core.classloader.MockClassLoader.loadModifiedClass(MockClassLoader.java:180)
at org.powermock.core.classloader.DeferSupportingClassLoader.loadClass(DeferSupportingClassLoader.java:68)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:249)
at sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:95)
at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:107)
at sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:31)
at sun.reflect.annotation.AnnotationParser.parseSig(AnnotationParser.java:370)
at sun.reflect.annotation.AnnotationParser.parseClassValue(AnnotationParser.java:351)
at sun.reflect.annotation.AnnotationParser.parseClassArray(AnnotationParser.java:653)
at sun.reflect.annotation.AnnotationParser.parseArray(AnnotationParser.java:460)
at sun.reflect.annotation.AnnotationParser.parseMemberValue(AnnotationParser.java:286)
at sun.reflect.annotation.AnnotationParser.parseAnnotation(AnnotationParser.java:222)
at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:69)
at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:52)
at java.lang.Class.initAnnotationsIfNecessary(Class.java:3079)
at java.lang.Class.getAnnotation(Class.java:3038)
at org.junit.internal.MethodSorter.getDeclaredMethods(MethodSorter.java:52)
at org.junit.internal.runners.TestClass.getAnnotatedMethods(TestClass.java:45)
at org.junit.internal.runners.MethodValidator.validateTestMethods(MethodValidator.java:71)
at org.junit.internal.runners.MethodValidator.validateStaticMethods(MethodValidator.java:44)
at org.junit.internal.runners.MethodValidator.validateMethodsForDefaultRunner(MethodValidator.java:50)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.validate(PowerMockJUnit44RunnerDelegateImpl.java:108)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.<init>(PowerMockJUnit44RunnerDelegateImpl.java:70)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl.<init>(PowerMockJUnit47RunnerDelegateImpl.java:42)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit49RunnerDelegateImpl.<init>(PowerMockJUnit49RunnerDelegateImpl.java:25)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.createDelegatorFromClassloader(JUnit4TestSuiteChunkerImpl.java:156)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.createDelegatorFromClassloader(JUnit4TestSuiteChunkerImpl.java:40)
at org.powermock.tests.utils.impl.AbstractTestSuiteChunkerImpl.createTestDelegators(AbstractTestSuiteChunkerImpl.java:244)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.<init>(JUnit4TestSuiteChunkerImpl.java:61)
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:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:29)
at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:21)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:26)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.<init>(JUnit4TestReference.java:33)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestClassReference.<init>(JUnit4TestClassReference.java:25)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:48)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:444)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

发现类似 post 讨论 here and here 基于它我尝试在 VM 参数中添加 -XX:-UseSplitVerifier 但它不起作用。

此外,我了解到错误似乎是由于我的 class 文件中的冗长方法而发生的,但作为我的组织代码,我无法 modify/split 一些 [=26] 中建议的方法=]在线。

您遇到了以下问题issue:JVM 对方法大小有限制,但在进行字节码转换期间(为了使模拟静态成为可能),方法的最终大小可能会超过此限制。在这种情况下,您会看到此错误

java.lang.ClassFormatError: Invalid method Code length 119842 in class file

在下一个版本中将包含修复,它通过使用默认抛出异常的代码替换巨大的方法来解决这个问题,但您仍然可以抑制这样的方法。

但是,它仍然是您无法修改的 类 的唯一解决方法。解决问题的正确方法是重构您的代码以使方法更小。有很多重构技术可以实现这个目标。

你可能不喜欢我的回答,但唯一合理的答案是:停止使用 PowerMock。

如果您的生产代码需要 PowerMock 才能编写单元测试;然后认真地:更改您的生产代码。如果您需要 PowerMock,那么您的 "code under test" 很可能是:bad.

PowerMock(以及所有其他依赖字节码操作的模拟框架)最常见的是麻烦多于好处。它们会导致您现在遇到的问题;它们极大地限制了您使用不同 JVM 或 运行 覆盖工具的能力。

这来自一个花了无数时间修复基于 "PowerMock" 的单元测试的人;谁在过去几个月仅依靠 EasyMock 编写了数百个单元测试;而且一次也不需要求助于 PowerMock。

如前所述,这不仅可以通过尝试检测大型方法来实现,还可以通过尝试 检测具有大量方法的 class 来实现

我在 around +/- 1500 methods 遇到了中断。这取决于 class.

中的方法签名

尝试减少 class 中的方法数量。

要使用 JVM 选项“-noverify”:https://bugs.eclipse.org/bugs/show_bug.cgi?id=435446