Lambda expression classes in GraalVM reflection configuration

Viewed 123

I am trying to run JDBI library in Quarkus native mode. By including all classes that are accessed via reflection to reflection-config.json, I was able to run it successfully.

However, I still got this exception (as warning) at runtime upon calling:

Jdbi jdbi = Jdbi.create(agroalDataSource).installPlugin(new SqlObjectPlugin());
2022-07-18 09:33:32,935 [] WARNING [com.git.ben.caf.cac.LocalLoadingCache] (main) Cannot determine if CacheLoader can bulk load: java.lang.NoSuchMethodException: org.jdbi.v3.core.statement.CachingSqlParser$$Lambda$1a0f8d592d890e8f26473320a5cdb05c88cf7099.loadAll(java.lang.Iterable)
        at java.lang.Class.getMethod(DynamicHub.java:2227)
        at com.github.benmanes.caffeine.cache.LocalLoadingCache.hasLoadAll(LocalLoadingCache.java:182)
        at com.github.benmanes.caffeine.cache.LocalLoadingCache.newBulkMappingFunction(LocalLoadingCache.java:160)
        at com.github.benmanes.caffeine.cache.BoundedLocalCache$BoundedLocalLoadingCache.<init>(BoundedLocalCache.java:3761)
        at com.github.benmanes.caffeine.cache.Caffeine.build(Caffeine.java:1104)
        at org.jdbi.v3.core.statement.CachingSqlParser.<init>(CachingSqlParser.java:30)
        at org.jdbi.v3.core.statement.CachingSqlParser.<init>(CachingSqlParser.java:25)
        at org.jdbi.v3.core.statement.ColonPrefixSqlParser.<init>(ColonPrefixSqlParser.java:41)
        at org.jdbi.v3.core.statement.SqlStatements.<init>(SqlStatements.java:53)
        at java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:480)
        at com.oracle.svm.methodhandles.Util_java_lang_invoke_MethodHandle.invokeInternal(Target_java_lang_invoke_MethodHandle.java:205)
        at java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:76)
        at java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:0)
        at java.lang.invoke.Invokers$Holder.invokeExact_MT(Invokers$Holder)
        at org.jdbi.v3.core.config.ConfigRegistry.lambda$configFactory$3(ConfigRegistry.java:100)
        at org.jdbi.v3.core.internal.exceptions.Unchecked.lambda$function$4(Unchecked.java:76)
        at org.jdbi.v3.core.config.ConfigRegistry.get(ConfigRegistry.java:78)
        at org.jdbi.v3.core.config.ConfigRegistry.<init>(ConfigRegistry.java:47)
        at org.jdbi.v3.core.Jdbi.<init>(Jdbi.java:58)
        at org.jdbi.v3.core.Jdbi.create(Jdbi.java:109)
        at org.jdbi.v3.core.Jdbi.create(Jdbi.java:93)

I tried adding the lambda expression class to reflection-config.json but that didn't solve it:

  {
    "name" : "org.jdbi.v3.core.statement.CachingSqlParser$$Lambda$1a0f8d592d890e8f26473320a5cdb05c88cf7099",
    "allDeclaredConstructors" : true,
    "allPublicConstructors" : true,
    "allDeclaredMethods" : true,
    "allPublicMethods" : true,
    "allDeclaredFields" : true,
    "allPublicFields" : true,
    "queryAllDeclaredConstructors" : true,
    "queryAllPublicConstructors" : true,
    "queryAllDeclaredMethods" : true,
    "queryAllPublicMethods" : true,
    "allDeclaredClasses" : true,
    "allPublicClasses" : true
  }

I got this warning message at generating native image:

Warning: Could not resolve org.jdbi.v3.core.statement.CachingSqlParser$$Lambda$1a0f8d592d890e8f26473320a5cdb05c88cf7099 for reflection configuration. Reason: java.lang.ClassNotFoundException: org.jdbi.v3.core.statement.CachingSqlParser$$Lambda$1a0f8d592d890e8f26473320a5cdb05c88cf7099.

How to include lambda expression classes into reflection-config?

2 Answers

Currently, reflection on lambda classes is not supported on Native Image. Configuration files expect the fully qualified name of the class that should be registered for reflection, serialization, etc. Lambda classes in the JDK don't have stable names, so we cannot store them in those files. We are aware of the problem, and we have in plan to fix it. I will let you know here as soon as it is done.

Unfortunately, as far as I know, there is no workaround at the moment for what you need. The main problem is that on Native Image, we have a closed world principle, and all the types used at runtime must be known at build time. Therefore, all the lambdas will be created at build time. But since lambda names are unstable, at build time we don't have the same name as it would be in the reflection-config.json and we cannot write down lambdas in the configuration file.

The solution was simple. The default method CacheLoader.loadAll has to be included into reflection-config.json:

{"name":"com.github.benmanes.caffeine.cache.CacheLoader","methods":[{"name":"loadAll","parameterTypes":["java.lang.Iterable"]}]}
Related