Skip to content

GraalVM native-image fails with missing "property: name for class: org.thymeleaf.standard.StandardDialect" #232

@mmoayyed

Description

@mmoayyed

I am using the latest version of the dialect, 3.2.0, with GraalVM 22.3 and JDK 17. When building a native image via the GraalVM gradle plugin, I ultimately see the following failure when I run the native application:

Caused by: groovy.lang.MissingPropertyException: No such property: name for class: org.thymeleaf.standard.StandardDialect
Possible solutions: name
	at groovy.lang.MetaClassImpl.invokeStaticMissingProperty(MetaClassImpl.java:992) ~[cas:4.0.7]
	at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:2018) ~[cas:4.0.7]
	at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:1999) ~[cas:4.0.7]
	at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:3863) ~[cas:4.0.7]
	at java.base@17.0.5/java.lang.reflect.Method.invoke(Method.java:568) ~[cas:na]
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.methodhandles.Util_java_lang_invoke_MethodHandle.invokeInternal(Target_java_lang_invoke_MethodHandle.java:221) ~[na:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:76) ~[cas:na]
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.methodhandles.MethodHandleIntrinsicImpl.execute(MethodHandleIntrinsicImpl.java:177) ~[na:na]
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.methodhandles.Util_java_lang_invoke_MethodHandle.invokeInternal(Target_java_lang_invoke_MethodHandle.java:142) ~[na:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:76) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:96) ~[na:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:964) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:941) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:82) ~[cas:na]
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.methodhandles.MethodHandleIntrinsicImpl.execute(MethodHandleIntrinsicImpl.java:177) ~[na:na]
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.methodhandles.Util_java_lang_invoke_MethodHandle.invokeInternal(Target_java_lang_invoke_MethodHandle.java:142) ~[na:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:76) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:96) ~[na:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:964) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:941) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:82) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:0) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm$MH/0x00000003042b0400.invokeExact_MT(LambdaForm$MH) ~[na:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:732) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandleImpl.guardWithCatch(MethodHandleImpl.java:950) ~[na:na]
	at java.base@17.0.5/java.lang.reflect.Method.invoke(Method.java:568) ~[cas:na]
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.methodhandles.Util_java_lang_invoke_MethodHandle.invokeInternal(Target_java_lang_invoke_MethodHandle.java:212) ~[na:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:76) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:96) ~[na:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:964) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:941) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:82) ~[cas:na]
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.methodhandles.MethodHandleIntrinsicImpl.execute(MethodHandleIntrinsicImpl.java:177) ~[na:na]
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.methodhandles.Util_java_lang_invoke_MethodHandle.invokeInternal(Target_java_lang_invoke_MethodHandle.java:142) ~[na:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:76) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:96) ~[na:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:964) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:941) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:82) ~[cas:na]
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.methodhandles.MethodHandleIntrinsicImpl.execute(MethodHandleIntrinsicImpl.java:177) ~[na:na]
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.methodhandles.Util_java_lang_invoke_MethodHandle.invokeInternal(Target_java_lang_invoke_MethodHandle.java:142) ~[na:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:76) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:96) ~[na:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:964) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:941) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:82) ~[cas:na]
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.methodhandles.MethodHandleIntrinsicImpl.execute(MethodHandleIntrinsicImpl.java:177) ~[na:na]
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.methodhandles.Util_java_lang_invoke_MethodHandle.invokeInternal(Target_java_lang_invoke_MethodHandle.java:142) ~[na:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:76) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:96) ~[na:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:964) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:941) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:82) ~[cas:na]
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.methodhandles.MethodHandleIntrinsicImpl.execute(MethodHandleIntrinsicImpl.java:177) ~[na:na]
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.methodhandles.Util_java_lang_invoke_MethodHandle.invokeInternal(Target_java_lang_invoke_MethodHandle.java:142) ~[na:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:76) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:96) ~[na:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:964) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:941) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:82) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:0) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm$MH/0x0000000304291c00.invokeExact_MT(LambdaForm$MH) ~[na:na]
	at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:321) ~[na:na]
	at java.base@17.0.5/java.lang.reflect.Method.invoke(Method.java:568) ~[cas:na]
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.methodhandles.Util_java_lang_invoke_MethodHandle.invokeInternal(Target_java_lang_invoke_MethodHandle.java:212) ~[na:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:76) ~[cas:na]
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.methodhandles.MethodHandleIntrinsicImpl.execute(MethodHandleIntrinsicImpl.java:177) ~[na:na]
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.methodhandles.Util_java_lang_invoke_MethodHandle.invokeInternal(Target_java_lang_invoke_MethodHandle.java:142) ~[na:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:76) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:96) ~[na:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:964) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:941) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:82) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:0) ~[cas:na]
	at java.base@17.0.5/java.lang.invoke.Invokers$Holder.linkToCallSite(Invokers$Holder) ~[na:na]
	at nz.net.ultraq.thymeleaf.layoutdialect.context.extensions.IContextExtensions.getPrefixForDialect(IContextExtensions.groovy:54) ~[na:na]

The key here seems to be:

nz.net.ultraq.thymeleaf.layoutdialect.context.extensions.IContextExtensions.getPrefixForDialect

...which does this:

static String getPrefixForDialect(IContext self, Class<IProcessorDialect> dialectClass) {
		return self.getOrCreate(DIALECT_PREFIX_PREFIX + dialectClass.name) { ->
			def dialectConfiguration = self.configuration.dialectConfigurations.find { dialectConfig ->
				return dialectClass.isInstance(dialectConfig.dialect)
			}
			return dialectConfiguration?.prefixSpecified ?
					dialectConfiguration?.prefix :
					dialectConfiguration?.dialect?.prefix
		}
	}

I am a complete n00b when it comes to Groovy, but should the use of dialectClass.name be revisited? The StandardDialect class has a NAME constant, a name property and here we are invoking getName() on a Class. I think the native-image builder is getting confused here.

My reflection configuration is as follows:

{
    "name": "org.thymeleaf.standard.StandardDialect",
    "queryAllDeclaredMethods": true,
    "queryAllPublicMethods": true,
    "allPublicMethods": true,
    "allDeclaredMethods": true
  },

I can certainly share a reproducer as a github repository if you find that to be helpful.

Metadata

Metadata

Assignees

Labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions