Inline classes generate strange names on openJdk

Viewed 722

Hej, I am building a spring boot app with kotlin and wanted to use inline classes. I made a spring data repository that has 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 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 charactar in a method name.

Anyone else had this?

Full stacktrace: [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

2 Answers

The key points are in the bottom of the stacktrace:

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.

This happens due to name mangling done by kotlin compiler. Functions accepting inline classes are not callable from Java. (Official docs)

Related