quarkus: [Quarkus Native] ClassNotFoundException: com.github.benmanes.caffeine.cache.SSSW

Describe the bug

Using the Cache API with caffeine leads to the following exception when running Quarkus 2.16.0.Final in native mode:

2023-01-31 13:56:54,211 ERROR [io.qua.run.Application] (main) Failed to start application (with profile [prod]): java.lang.ClassNotFoundException: com.github.benmanes.caffeine.cache.SSSW
        at java.base@17.0.5/java.lang.Class.forName(DynamicHub.java:1132)
        at java.base@17.0.5/java.lang.Class.forName(DynamicHub.java:1105)
        at com.github.benmanes.caffeine.cache.LocalCacheFactory.loadFactory(LocalCacheFactory.java:84)
        at com.github.benmanes.caffeine.cache.LocalCacheFactory.newBoundedLocalCache(LocalCacheFactory.java:40)
        at com.github.benmanes.caffeine.cache.BoundedLocalCache$BoundedLocalAsyncCache.<init>(BoundedLocalCache.java:4216)
        at com.github.benmanes.caffeine.cache.Caffeine.buildAsync(Caffeine.java:1096)
        at io.quarkus.cache.runtime.caffeine.CaffeineCacheImpl.<init>(CaffeineCacheImpl.java:71)
        at io.quarkus.cache.runtime.caffeine.CaffeineCacheManagerBuilder$1.get(CaffeineCacheManagerBuilder.java:56)
        at io.quarkus.cache.runtime.caffeine.CaffeineCacheManagerBuilder$1.get(CaffeineCacheManagerBuilder.java:34)
        at io.quarkus.cache.CacheManager_7ace4235729bbc654ace276b403267860dc707de_Synthetic_Bean.createSynthetic(Unknown Source)
        at io.quarkus.cache.CacheManager_7ace4235729bbc654ace276b403267860dc707de_Synthetic_Bean.create(Unknown Source)
        at io.quarkus.cache.CacheManager_7ace4235729bbc654ace276b403267860dc707de_Synthetic_Bean.create(Unknown Source)
        at io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:113)
        at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:37)
        at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:34)
        at io.quarkus.arc.impl.LazyValue.get(LazyValue.java:26)
        at io.quarkus.arc.impl.ComputingCache.computeIfAbsent(ComputingCache.java:69)
        at io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:34)
        at io.quarkus.arc.impl.ClientProxies.getApplicationScopedDelegate(ClientProxies.java:21)
        at io.quarkus.cache.CacheManager_7ace4235729bbc654ace276b403267860dc707de_Synthetic_ClientProxy.arc$delegate(Unknown Source)
        at io.quarkus.cache.CacheManager_7ace4235729bbc654ace276b403267860dc707de_Synthetic_ClientProxy.getCacheNames(Unknown Source)
        at io.quarkus.cache.runtime.CacheManagerInitializer.onStartup(CacheManagerInitializer.java:14)
        at java.base@17.0.5/java.lang.reflect.Method.invoke(Method.java:568)
        at io.quarkus.arc.impl.Reflections.invokeMethod(Reflections.java:170)
        at io.quarkus.cache.runtime.CacheManagerInitializer_Observer_onStartup_8dc69ad76cf9cc31e6928ed65580a8d3fd18a734.notify(Unknown Source)
        at io.quarkus.arc.impl.EventImpl$Notifier.notifyObservers(EventImpl.java:328)
        at io.quarkus.arc.impl.EventImpl$Notifier.notify(EventImpl.java:310)
        at io.quarkus.arc.impl.EventImpl.fire(EventImpl.java:78)
        at io.quarkus.arc.runtime.ArcRecorder.fireLifecycleEvent(ArcRecorder.java:131)
        at io.quarkus.arc.runtime.ArcRecorder.handleLifecycleEvents(ArcRecorder.java:100)
        at io.quarkus.deployment.steps.LifecycleEventsBuildStep$startupEvent1144526294.deploy_0(Unknown Source)
        at io.quarkus.deployment.steps.LifecycleEventsBuildStep$startupEvent1144526294.deploy(Unknown Source)
        at io.quarkus.runner.ApplicationImpl.doStart(Unknown Source)
        at io.quarkus.runtime.Application.start(Application.java:101)
        at io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:108)
        at io.quarkus.runtime.Quarkus.run(Quarkus.java:71)
        at io.quarkus.runtime.Quarkus.run(Quarkus.java:44)
        at io.quarkus.runtime.Quarkus.run(Quarkus.java:124)
        at io.quarkus.runner.GeneratedMain.main(Unknown Source)

Expected behavior

No response

Actual behavior

This issue is related to the native mode only. The JVM mode is working just fine. It also looks like it’s just an issue with 2.16.0.Final, with 2.15.3.Final everything works as expected, even in the native mode.

How to Reproduce?

  1. Define a Quarkus 2.16.0.Final dependency
  2. Add the @CacheResult annotation to an interceptable method
  3. Run your app in native mode

Output of uname -a or ver

No response

Output of java -version

openjdk 17.0.2 2022-01-18

GraalVM version (if different from Java)

GraalVM 22.3.0 Java 17 CE

Quarkus version or git rev

Quarkus 2.16.0.Final

Build tool (ie. output of mvnw --version or gradlew --version)

mvn

Additional information

The native build is conducted with the help of quay.io/quarkus/ubi-quarkus-native-image:22.3-java17

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 25 (15 by maintainers)

Commits related to this issue

Most upvoted comments

@ben-manes done here: https://github.com/quarkusio/quarkus/pull/30825

@manuelwallrapp yeah the whole array of classes with metrics are missing. I’ll have a closer look either tomorrow or next week.

It’s not only this one. I think we need to record all the metrics-capable ones and I would prefer doing it only if Micrometer is around. I think I will just drop the feature and do things in the processor. It was a nice optimization while we didn’t have conditions but it’s going to be annoying now.

To give you a bit more background:

  • Caffeine generates a lot of classes for all the cache configurations so that it’s perfectly optimized for each setup.
  • We don’t register all of them for reflection because the cost in image size is too high: we register only the most common ones.
  • If you’re using a more exotic cache configuration, you have to register the classes you want following this advice: https://quarkus.io/guides/cache#going-native

Your problem is due to metrics-enabled which might have not been supported (or supported differently before) and it now triggers the need for a cache class that we don’t enable by default.

I think we should enable these classes by default if we have Micrometer around. I’ll have a look at it next week.

In the meantime, just register the class manually as explained in the guide pointed above.