我的作业项目使用 kotlin spring-boot。
当我尝试should success WHEN setting key is api updatable
在 MacBookapple-m1
机器上运行具有空间的测验用例时,我发现了这个问题。
例子
@Test
@Transactional
fun `should success when setting key is api updatable`()
然后 JVM 抛出包含堆栈跟踪的例外看起来像这样
Caused by: java.lang.ClassFormatError: Illegal method name "should success when setting key is api updatable" in class com/xxx/xxx/web/rest/CompanySettingResourceIntTest$$EnhancerBySpringCGLIB$$f0902682
这发生在我的 MacBook m1 机器上,但从未发生在英特尔机器上。
我尝试调查这个问题,然后我发现@Transactional
在bean中使用方法时,spring-aop
会通过使用方法创建一个代理类java.lang.ClassLoader.defineClass
。
我有很多看起来像这样的方法,而且很容易阅读。我可以使用包含space
在 m1 机器中运行的方法名称,我该如何修复它?
谢谢你。
环境
- JDK 1.8 版 (AArch64)
- 春季启动 1.5.16
- JUnit 4
(我尝试使用 spring-boot2 JUnit5 测验用例名称包含空格进行 POC。但是 bean 中的方法Illegal method name
也抛出了。)
JUnit 日志(运行测验)
Could not generate CGLIB subclass of class com.xxx.xxx.web.rest.CompanySettingResourceIntTest: Common causes of this problem include using a final class or a non-visible class; nested exception is org.springframework.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class com.xxx.xxx.web.rest.CompanySettingResourceIntTest: Common causes of this problem include using a final class or a non-visible class; nested exception is org.springframework.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:204)
at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:109)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:466)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:349)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:298)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:421)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1635)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:398)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:119)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:44)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:40)
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.Iterator.forEachRemaining(Iterator.java:116)
at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:485)
at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:80)
at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:71)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:92)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$100(JUnitPlatformTestClassProcessor.java:77)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:73)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
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.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy2.stop(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:131)
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.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:155)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:137)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.springframework.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:345)
at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:492)
at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:93)
at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:91)
at org.springframework.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61)
at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)
at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:116)
at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:291)
at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:480)
at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:337)
at org.springframework.aop.framework.ObjenesisCglibAopProxy.createProxyClassAndInstance(ObjenesisCglibAopProxy.java:55)
at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:201)
... 73 more
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.GeneratedMethodAccessor82.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:459)
at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:336)
... 86 more
Caused by: java.lang.ClassFormatError: Illegal method name "should success when setting key is api updatable" in class com/xxx/xxx/web/rest/CompanySettingResourceIntTest$$EnhancerBySpringCGLIB$$f0902682
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
... 91 more
uj5u.com热心网友回复:
您可能会遇到Spring 5.1 中修复的Spring 问题 #21674。如果可以的话,您可能想要升级。似乎有一个忽略这些方法的修复程序。这对你来说是否合适,我不知道。
一些背景信息:您的目标方法是事务性的,因此 Spring 尝试为它创建一个 CGLIB 代理。我在一个简单的 Spock (Groovy) 测验中快速验证了 CGLIB 似乎无法正确处理包含空格的方法——可能是因为它根本不知道像 Groovy 和 Kotlin 这样的语言允许这样的事情。这是一个概念证明。我使用了 Groovy 和 Spock,因为我很懒,不想建立 Kotlin 项目。但我希望结果是相同的。
被测Java类:
package de.scrum_master.stackoverflow.q70654015;
public class SampleJava {
public String greet(String input) {
return "Hello " input "!";
}
}
正在测验的 Groovy 类:
package de.scrum_master.stackoverflow.q70654015
class SampleGroovy {
String "say hello to"(String input) {
"Hello $input!"
}
}
Spock 测验创建 CGLIB 代理:
package de.scrum_master.stackoverflow.q70654015
import net.sf.cglib.proxy.Enhancer
import net.sf.cglib.proxy.MethodInterceptor
import spock.lang.Specification
class CGLIBProxyTest extends Specification {
def "create CGLIB proxy for Java class"() {
given:
Enhancer enhancer = new Enhancer()
enhancer.superclass = SampleJava
enhancer.callback = { obj, method, args, proxy ->
method.getDeclaringClass() != Object.class && method.getReturnType() == String.class
? "Hello cglib!"
: proxy.invokeSuper(obj, args)
} as MethodInterceptor
when:
SampleJava proxy = enhancer.create()
then:
proxy.greet("world") == "Hello cglib!"
}
def "create CGLIB proxy for Groovy class with spaces in method name"() {
given:
Enhancer enhancer = new Enhancer()
enhancer.superclass = SampleGroovy
enhancer.callback = { obj, method, args, proxy ->
method.getDeclaringClass() != Object.class && method.getReturnType() == String.class
? "Hello cglib!"
: proxy.invokeSuper(obj, args)
} as MethodInterceptor
when:
SampleGroovy proxy = enhancer.create()
then:
proxy."say hello to"("world") == "Hello cglib!"
}
}
第一个测验通过,第二个测验失败:
net.sf.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:345)
at net.sf.cglib.proxy.Enhancer.generate(Enhancer.java:492)
at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:93)
at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:91)
at net.sf.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at net.sf.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61)
at net.sf.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)
at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:116)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:291)
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:480)
at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:305)
at de.scrum_master.stackoverflow.q70654015.CGLIBProxyTest.create CGLIB proxy for Groovy class with spaces in method name(CGLIBProxyTest.groovy:36)
Caused by: java.lang.reflect.InvocationTargetException
at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:459)
at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:336)
... 12 more
Caused by: java.lang.ClassFormatError: Illegal method name "say hello to" in class de/scrum_master/stackoverflow/q70654015/SampleGroovy$$EnhancerByCGLIB$$ef703cf1
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
... 14 more
这与您遇到的错误相同。只要将 Groovy 方法重命名为在 JVM 中合法的名称,测验就会通过。
关于您声称该行为应该取决于硬件或作业系统平台的说法,我不同意。我认为您的运行时环境可能存在差异。你是如何构建和运行你的项目的?Maven,Gradle,还有别的吗?
Update: I have good news for you: I had run my test on JDK 8 and 15 and cglib:cglib-nodep:3.2.6
. When upgrading to CGLIB 3.3.0, the test started passing. So you might want to version-manage CGLIB in your Maven POM's <dependencyManagement>
section (or whatever is Gradle's equivalent) to that version. Maybe it helps. Please note that some tools might also depend on cglib:cglib
, so you want to version-manage that one too. I.e., make sure that you use these versions:
cglib:cglib-nodep:3.3.0
cglib:cglib:3.3.0
(if it is used in your application)
Update 2: I am not a regular Spring user, so I forgot that Spring Core (artifact org.springframework:spring-core
) includes its own CGLIB version, relocated to base package name org.springframework.cglib
. Please note the package name difference from your stack trace to the original net.sf.cglib
for my stand-alone example.
我查了一下,发现自版本以来5.2.0.RELEASE
,Spring Core升级到了 CGLIB 3.3.0。因此,如果您可以使用 Spring 5.2.0 或更高版本,那么它很可能适合您。
0 评论