Reputation: 81
I am building a Spring Boot application with Kotlin and wanted to use inline classes. I made a Spring data repository that had a method as follows:
fun getBy(name: GameName)
where GameName is an inline class
inline class GameName(val value: String)
And everything works locally, where I am running JDK 1.8.0_181-b13. But when I deploy it to Google Cloud, the Spring Boot app doesn't start up. Google Cloud seems to be running OpenJDK 1.8.0_181.
When I decompile the code locally, it looks like this:
public GameConfigurationEntity getBy_00UsoVY/* $FF was: getBy-00UsoVY*/(@NotNull String gameName, @NotNull UUID id) { ... }
But on Google Cloud Platform, I get the following error:
Caused by: java.lang.ClassFormatError: Illegal method name "getByName-MZoZWhM"
So it seems locally it uses _
, while on Google Cloud it uses -
and -
is not a valid character in a method name.
How can I fix this?
Full stack trace:
[INFO] GCLOUD: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'gameConfigurationService' defined in URL [jar:file:/app.jar!/BOOT-INF/classes!/com/hexigames/configurationservice/domain/game/GameConfigurationService.class]: Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class com.hexigames.configurationservice.domain.game.GameConfigurationService: 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
[INFO] GCLOUD: at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:581) ~[spring-beans-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495) ~[spring-beans-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317) ~[spring-beans-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) ~[spring-beans-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:759) ~[spring-beans-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) ~[spring-context-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:548) ~[spring-context-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) ~[spring-boot-2.0.6.RELEASE.jar!/:2.0.6.RELEASE]
[INFO] GCLOUD: at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) [spring-boot-2.0.6.RELEASE.jar!/:2.0.6.RELEASE]
[INFO] GCLOUD: at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:386) [spring-boot-2.0.6.RELEASE.jar!/:2.0.6.RELEASE]
[INFO] GCLOUD: at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) [spring-boot-2.0.6.RELEASE.jar!/:2.0.6.RELEASE]
[INFO] GCLOUD: at org.springframework.boot.SpringApplication.run(SpringApplication.java:1242) [spring-boot-2.0.6.RELEASE.jar!/:2.0.6.RELEASE]
[INFO] GCLOUD: at org.springframework.boot.SpringApplication.run(SpringApplication.java:1230) [spring-boot-2.0.6.RELEASE.jar!/:2.0.6.RELEASE]
[INFO] GCLOUD: at com.hexigames.configurationservice.ConfigurationServiceApplicationKt.main(ConfigurationServiceApplication.kt:12) [classes!/:0.0.1-SNAPSHOT]
[INFO] GCLOUD: at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181]
[INFO] GCLOUD: at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181]
[INFO] GCLOUD: at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
[INFO] GCLOUD: at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
[INFO] GCLOUD: at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) [app.jar:0.0.1-SNAPSHOT]
[INFO] GCLOUD: at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) [app.jar:0.0.1-SNAPSHOT]
[INFO] GCLOUD: at org.springframework.boot.loader.Launcher.launch(Launcher.java:50) [app.jar:0.0.1-SNAPSHOT]
[INFO] GCLOUD: at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51) [app.jar:0.0.1-SNAPSHOT]
[INFO] GCLOUD: Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class com.hexigames.configurationservice.domain.game.GameConfigurationService: 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
[INFO] GCLOUD: at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:208) ~[spring-aop-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:110) ~[spring-aop-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:473) ~[spring-aop-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:355) ~[spring-aop-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:304) ~[spring-aop-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:431) ~[spring-beans-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1698) ~[spring-beans-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:573) ~[spring-beans-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: ... 23 common frames omitted
[INFO] GCLOUD: Caused by: org.springframework.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
[INFO] GCLOUD: at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:345) ~[spring-core-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:492) ~[spring-core-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:93) ~[spring-core-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:91) ~[spring-core-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54) ~[spring-core-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_181]
[INFO] GCLOUD: at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61) ~[spring-core-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34) ~[spring-core-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:116) ~[spring-core-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:291) ~[spring-core-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:480) ~[spring-core-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:337) ~[spring-core-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.aop.framework.ObjenesisCglibAopProxy.createProxyClassAndInstance(ObjenesisCglibAopProxy.java:58) ~[spring-aop-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:205) ~[spring-aop-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: ... 30 common frames omitted
[INFO] GCLOUD: Caused by: java.lang.reflect.InvocationTargetException: null
[INFO] GCLOUD: at sun.reflect.GeneratedMethodAccessor41.invoke(Unknown Source) ~[na:na]
[INFO] GCLOUD: at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
[INFO] GCLOUD: at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
[INFO] GCLOUD: at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:459) ~[spring-core-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:336) ~[spring-core-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: ... 43 common frames omitted
[INFO] GCLOUD: Caused by: java.lang.ClassFormatError: Illegal method name "createConfiguration-tQynZQ0" in class com/hexigames/configurationservice/domain/game/GameConfigurationService$$EnhancerBySpringCGLIB$$76757398
[INFO] GCLOUD: at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_181]
[INFO] GCLOUD: at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[na:1.8.0_181]
[INFO] GCLOUD: ... 48 common frames omitted
[INFO] GCLOUD:
[INFO] GCLOUD: I1101 09:02:28.364653 25 jvmti_agent.cc:225] Java VM termination
[INFO] GCLOUD: I1101 09:02:28.377487 36 jvmti_agent_thread.cc:103] Agent thread exited: CloudDebugger_main_worker_thread
[INFO] GCLOUD: I1101 09:02:28.398113 25 worker.cc:116] Debugger threads terminated
[INFO] GCLOUD: I1101 09:02:28.405902 25 jvmti_agent.cc:239] JvmtiAgent::JvmtiOnVMDeath cleanup time: 44024 microseconds
Upvotes: 3
Views: 861
Reputation: 4918
The key points are in the bottom of the stack trace:
org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:336) ~[spring-core-5.0.10.RELEASE.jar!/:5.0.10.RELEASE]
[INFO] GCLOUD: ... 43 common frames omitted
[INFO] GCLOUD: Caused by: java.lang.ClassFormatError: Illegal method name "createConfiguration-tQynZQ0" in class com/hexigames/configurationservice/domain/game/GameConfigurationService$$EnhancerBySpringCGLIB$$76757398
[INFO] GCLOUD: at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_181]
[INFO] GCLOUD: at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[na:1.8.0_181]
In other words, Spring uses a custom class loader to generate a class on demand. This class uses the method name with a - in it. The defineClass1
method in the class loader chokes on it. As classloaders are used for loading any class, my only assumption is that somehow Google Cloud uses an adjusted class loader. As classloaders are highly security sensitive, this makes sense, but obviously your Kotlin code is not security sensitive.
According to the JVM specification the -
character is not an illegal character in a method name at JVM level: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.2.2. As such, this appears to be a bug in the Google Cloud platform. Btw., the character is illegal in Java, but the JVM is much more lenient.
Upvotes: 2
Reputation: 139
This happens due to name mangling done by Kotlin compiler. Functions accepting inline classes are not callable from Java. (Official documentation)
Upvotes: 0