Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ClassNotFoundException with Caffeine and Spring Boot 3 #271

Closed
AndrewIISM opened this issue Apr 18, 2023 · 7 comments
Closed

ClassNotFoundException with Caffeine and Spring Boot 3 #271

AndrewIISM opened this issue Apr 18, 2023 · 7 comments
Labels
duplicate This issue or pull request already exists

Comments

@AndrewIISM
Copy link

Hello!
I use spring boot (v. 3.0.5) with com.github.ben-manes.caffeine (v. 3.1.2). When I make native-image with custom configuration of CaffeineCacheManager, I get this error:

Caused by: java.lang.IllegalStateException: com.github.benmanes.caffeine.cache.SSSMSW
	at com.github.benmanes.caffeine.cache.LocalCacheFactory.loadFactory(LocalCacheFactory.java:90) ~[na:na]
	at com.github.benmanes.caffeine.cache.LocalCacheFactory.newBoundedLocalCache(LocalCacheFactory.java:40) ~[na:na]
	at com.github.benmanes.caffeine.cache.BoundedLocalCache$BoundedLocalManualCache.<init>(BoundedLocalCache.java:3939) ~[na:na]
	at com.github.benmanes.caffeine.cache.BoundedLocalCache$BoundedLocalManualCache.<init>(BoundedLocalCache.java:3935) ~[na:na]
	at com.github.benmanes.caffeine.cache.Caffeine.build(Caffeine.java:1051) ~[app:na]
	at com.tpe.job.loan.notification.configuration.NotificationCacheConfiguration.notificationTemplateCacheManager(NotificationCacheConfiguration.java:25) ~[app:na]
	at com.tpe.job.loan.notification.configuration.NotificationCacheConfiguration$$SpringCGLIB$$0.CGLIB$notificationTemplateCacheManager$0(<generated>) ~[app:na]
	at com.tpe.job.loan.notification.configuration.NotificationCacheConfiguration$$SpringCGLIB$$2.invoke(<generated>) ~[app:na]
	at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) ~[app:6.0.7]
	at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) ~[na:na]
	at com.tpe.job.loan.notification.configuration.NotificationCacheConfiguration$$SpringCGLIB$$0.notificationTemplateCacheManager(<generated>) ~[app:na]
	at com.tpe.job.loan.notification.configuration.NotificationCacheConfiguration__BeanDefinitions.lambda$getNotificationTemplateCacheManagerInstanceSupplier$0(NotificationCacheConfiguration__BeanDefinitions.java:31) ~[na:na]
	at org.springframework.util.function.ThrowingFunction.apply(ThrowingFunction.java:63) ~[app:6.0.7]
	at org.springframework.util.function.ThrowingFunction.apply(ThrowingFunction.java:51) ~[app:6.0.7]
	at org.springframework.beans.factory.aot.BeanInstanceSupplier.lambda$withGenerator$0(BeanInstanceSupplier.java:171) ~[na:na]
	at org.springframework.util.function.ThrowingBiFunction.apply(ThrowingBiFunction.java:68) ~[app:6.0.7]
	at org.springframework.util.function.ThrowingBiFunction.apply(ThrowingBiFunction.java:54) ~[app:6.0.7]
	at org.springframework.beans.factory.aot.BeanInstanceSupplier.lambda$get$2(BeanInstanceSupplier.java:204) ~[na:na]
	at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58) ~[app:6.0.7]
	at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46) ~[app:6.0.7]
	at org.springframework.beans.factory.aot.BeanInstanceSupplier.invokeBeanSupplier(BeanInstanceSupplier.java:216) ~[na:na]
	at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:204) ~[na:na]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.obtainInstanceFromSupplier(DefaultListableBeanFactory.java:947) ~[app:6.0.7]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1214) ~[app:6.0.7]
	... 17 common frames omitted
Caused by: java.lang.ClassNotFoundException: com.github.benmanes.caffeine.cache.SSSMSW
	at java.base@17.0.6/java.lang.Class.forName(DynamicHub.java:1132) ~[app:na]
	at java.base@17.0.6/java.lang.Class.forName(DynamicHub.java:1105) ~[app:na]
	at com.github.benmanes.caffeine.cache.LocalCacheFactory.loadFactory(LocalCacheFactory.java:84) ~[na:na]
	... 40 common frames omitted

My configuration:

@Configuration
@EnableCaching
public class NotificationCacheConfiguration {

    @Bean(NOTIFICATION_TEMPLATE)
    public CacheManager notificationTemplateCacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager(NOTIFICATION_CACHE);
        cacheManager.setCaffeine(Caffeine.newBuilder()
                .initialCapacity(5)
                .maximumSize(50)
                .expireAfterWrite(2, TimeUnit.HOURS)
                .recordStats()
        );
        cacheManager.setAllowNullValues(false);

        return cacheManager;
    }

}

I found similar problem here

@AndrewIISM AndrewIISM added the bug Something isn't working label Apr 18, 2023
@dnestoro
Copy link
Member

@bclozel is this possibly issue for Spring Boot?

@AndrewIISM
Copy link
Author

AndrewIISM commented Apr 19, 2023

As I understood, in metadata for Caffeine missed class com.github.benmanes.caffeine.cache.SSSMSW

It's work if I add hint manually:

hints.reflection().registerType(
                    TypeReference.of("com.github.benmanes.caffeine.cache.SSSMSW"),
                    PUBLIC_FIELDS, INVOKE_DECLARED_CONSTRUCTORS, INVOKE_PUBLIC_METHODS
            )

@snicoll
Copy link

snicoll commented Apr 24, 2023

@dnestoro I don't think so, from the stacktrace it looks like Caffeine is doing the reflection call. We can't infer that.

@linghengqian
Copy link
Contributor

@zizare
Copy link
Contributor

zizare commented Sep 15, 2023

On my side
to fix it on spring boot application
I also add an hint manually :

hints.reflection()
	.registerType(TypeReference.of("com.github.benmanes.caffeine.cache.SSSMSW"),
					builder -> builder.withConstructor(
						List.of(TypeReference.of("com.github.benmanes.caffeine.cache.Caffeine"),
							TypeReference.of("com.github.benmanes.caffeine.cache.AsyncCacheLoader"),
							TypeReference.of("boolean")), ExecutableMode.INVOKE))

@tedyoung
Copy link

tedyoung commented Jan 7, 2024

Despite the fact that it seems like the hints should already be there (from output log):

[INFO] [graalvm reachability metadata repository for com.github.ben-manes.caffeine:caffeine:3.0.5]: Configuration directory not found. Trying latest version.
[INFO] [graalvm reachability metadata repository for com.github.ben-manes.caffeine:caffeine:3.0.5]: Configuration directory is com.github.ben-manes.caffeine/caffeine/3.1.2

I found I had to explicitly add this hint (Spring Boot 3.2.1):

import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportRuntimeHints;

import java.util.List;

@ImportRuntimeHints(RuntimeHintsConfig.SsmsRuntimeHintsRegistrar.class)
@Configuration
class RuntimeHintsConfig {

    static class SsmsRuntimeHintsRegistrar implements RuntimeHintsRegistrar {

        @Override
        public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
            List<TypeReference> paramTypes = List.of(
                    TypeReference.of("com.github.benmanes.caffeine.cache.Caffeine"),
                    TypeReference.of("com.github.benmanes.caffeine.cache.CacheLoader"),
                    TypeReference.of("boolean"));
            hints.reflection()
                 .registerType(TypeReference.of("com.github.benmanes.caffeine.cache.SSMS"),
                               builder -> builder.withConstructor(paramTypes, ExecutableMode.INVOKE));
        }
    }
}

and that worked.

@bclozel
Copy link
Collaborator

bclozel commented Jan 8, 2024

@tedyoung that's strange, the constructor definition you've shared is not the right one and the correct one is already declared in the metadata: com.github.benmanes.caffeine.cache.SSMS#SSMS(Caffeine<K, V>, AsyncCacheLoader, boolean):

  {
    "condition": {
      "typeReachable": "com.github.benmanes.caffeine.cache.BoundedLocalCache$BoundedLocalLoadingCache"
    },
    "name": "com.github.benmanes.caffeine.cache.SSMS",
    "methods": [
      {
        "name": "<init>",
        "parameterTypes": [
          "com.github.benmanes.caffeine.cache.Caffeine",
          "com.github.benmanes.caffeine.cache.AsyncCacheLoader",
          "boolean"
        ]
      }
    ]
  }

If you can come up with a minimal sample application (ideally, just having caffeine as a dependency), please create a new issue so we can look into it.

Metadata should be complete here so I'm closing this issue now.

@bclozel bclozel closed this as not planned Won't fix, can't repro, duplicate, stale Jan 8, 2024
@bclozel bclozel added duplicate This issue or pull request already exists and removed bug Something isn't working labels Jan 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
duplicate This issue or pull request already exists
Projects
None yet
Development

No branches or pull requests

7 participants