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

Thymeleaf and Velocity Map access fails in native image #370

Open
burtbeckwith opened this issue Mar 8, 2022 · 3 comments
Open

Thymeleaf and Velocity Map access fails in native image #370

burtbeckwith opened this issue Mar 8, 2022 · 3 comments
Labels
info: workaround available A workaround is available for the issue relates-to: graal

Comments

@burtbeckwith
Copy link
Member

Expected Behavior

No response

Actual Behaviour

Basically the same error as in #257

00:01:05.154 [io-executor-thread-1] ERROR org.thymeleaf.TemplateEngine - [THYMELEAF][io-executor-thread-1] Exception processing template "home": Exception evaluating OGNL expression: "security.attributes.get('foo')" (template: "home" - line 7, col 16)
org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating OGNL expression: "security.attributes.get('foo')" (template: "home" - line 7, col 16)
        at org.thymeleaf.standard.expression.OGNLVariableExpressionEvaluator.evaluate(OGNLVariableExpressionEvaluator.java:191)
        at org.thymeleaf.standard.expression.OGNLVariableExpressionEvaluator.evaluate(OGNLVariableExpressionEvaluator.java:95)
        at org.thymeleaf.standard.expression.VariableExpression.executeVariableExpression(VariableExpression.java:166)
        at org.thymeleaf.standard.expression.SimpleExpression.executeSimple(SimpleExpression.java:66)
        at org.thymeleaf.standard.expression.Expression.execute(Expression.java:109)
        at org.thymeleaf.standard.expression.Expression.execute(Expression.java:138)
        at org.thymeleaf.standard.processor.AbstractStandardExpressionAttributeTagProcessor.doProcess(AbstractStandardExpressionAttributeTagProcessor.java:144)
        at org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess(AbstractAttributeTagProcessor.java:74)
        at org.thymeleaf.processor.element.AbstractElementTagProcessor.process(AbstractElementTagProcessor.java:95)
        at org.thymeleaf.util.ProcessorConfigurationUtils$ElementTagProcessorWrapper.process(ProcessorConfigurationUtils.java:633)
        at org.thymeleaf.engine.ProcessorTemplateHandler.handleOpenElement(ProcessorTemplateHandler.java:1314)
        at org.thymeleaf.engine.OpenElementTag.beHandled(OpenElementTag.java:205)
        at org.thymeleaf.engine.TemplateModel.process(TemplateModel.java:136)
        at org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:661)
        at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1098)
        at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1067)
        at io.micronaut.views.thymeleaf.ThymeleafViewsRenderer.render(ThymeleafViewsRenderer.java:123)
        at io.micronaut.views.thymeleaf.ThymeleafViewsRenderer.lambda$render$0(ThymeleafViewsRenderer.java:110)
        at io.micronaut.core.io.Writable.writeTo(Writable.java:77)
        at io.micronaut.http.server.netty.RoutingInBoundHandler.lambda$encodeHttpResponse$6(RoutingInBoundHandler.java:946)
        at io.micronaut.scheduling.instrument.InvocationInstrumenterWrappedRunnable.run(InvocationInstrumenterWrappedRunnable.java:47)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at java.lang.Thread.run(Thread.java:829)
        at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:597)
        at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:194)
Caused by: ognl.MethodFailedException: Method "get" failed for object {foo=bar}
        at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1932)
        at ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:68)
        at ognl.OgnlRuntime.callMethod(OgnlRuntime.java:1996)
        at ognl.ASTMethod.getValueBody(ASTMethod.java:91)
        at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
        at ognl.SimpleNode.getValue(SimpleNode.java:258)
        at ognl.ASTChain.getValueBody(ASTChain.java:141)
        at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
        at ognl.SimpleNode.getValue(SimpleNode.java:258)
        at ognl.Ognl.getValue(Ognl.java:537)
        at ognl.Ognl.getValue(Ognl.java:501)
        at org.thymeleaf.standard.expression.OGNLVariableExpressionEvaluator.executeExpression(OGNLVariableExpressionEvaluator.java:326)
        at org.thymeleaf.standard.expression.OGNLVariableExpressionEvaluator.evaluate(OGNLVariableExpressionEvaluator.java:170)
        ... 25 common frames omitted
Caused by: java.lang.NoSuchMethodException: java.util.HashMap.get(java.lang.String)
        at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1873)
        ... 37 common frames omitted
Exception in thread "io-executor-thread-1" io.micronaut.views.exceptions.ViewRenderingException: Error rendering Thymeleaf view [home]: Exception evaluating OGNL expression: "security.attributes.get('foo')" (template: "home" - line 7, col 16)
        at io.micronaut.views.thymeleaf.ThymeleafViewsRenderer.render(ThymeleafViewsRenderer.java:125)
        at io.micronaut.views.thymeleaf.ThymeleafViewsRenderer.lambda$render$0(ThymeleafViewsRenderer.java:110)
        at io.micronaut.core.io.Writable.writeTo(Writable.java:77)
        at io.micronaut.http.server.netty.RoutingInBoundHandler.lambda$encodeHttpResponse$6(RoutingInBoundHandler.java:946)
        at io.micronaut.scheduling.instrument.InvocationInstrumenterWrappedRunnable.run(InvocationInstrumenterWrappedRunnable.java:47)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at java.lang.Thread.run(Thread.java:829)
        at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:597)
        at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:194)
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating OGNL expression: "security.attributes.get('foo')" (template: "home" - line 7, col 16)
        at org.thymeleaf.standard.expression.OGNLVariableExpressionEvaluator.evaluate(OGNLVariableExpressionEvaluator.java:191)
        at org.thymeleaf.standard.expression.OGNLVariableExpressionEvaluator.evaluate(OGNLVariableExpressionEvaluator.java:95)
        at org.thymeleaf.standard.expression.VariableExpression.executeVariableExpression(VariableExpression.java:166)
        at org.thymeleaf.standard.expression.SimpleExpression.executeSimple(SimpleExpression.java:66)
        at org.thymeleaf.standard.expression.Expression.execute(Expression.java:109)
        at org.thymeleaf.standard.expression.Expression.execute(Expression.java:138)
        at org.thymeleaf.standard.processor.AbstractStandardExpressionAttributeTagProcessor.doProcess(AbstractStandardExpressionAttributeTagProcessor.java:144)
        at org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess(AbstractAttributeTagProcessor.java:74)
        at org.thymeleaf.processor.element.AbstractElementTagProcessor.process(AbstractElementTagProcessor.java:95)
        at org.thymeleaf.util.ProcessorConfigurationUtils$ElementTagProcessorWrapper.process(ProcessorConfigurationUtils.java:633)
        at org.thymeleaf.engine.ProcessorTemplateHandler.handleOpenElement(ProcessorTemplateHandler.java:1314)
        at org.thymeleaf.engine.OpenElementTag.beHandled(OpenElementTag.java:205)
        at org.thymeleaf.engine.TemplateModel.process(TemplateModel.java:136)
        at org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:661)
        at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1098)
        at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1067)
        at io.micronaut.views.thymeleaf.ThymeleafViewsRenderer.render(ThymeleafViewsRenderer.java:123)
        ... 9 more
Caused by: ognl.MethodFailedException: Method "get" failed for object {foo=bar} [java.lang.NoSuchMethodException: java.util.HashMap.get(java.lang.String)]
        at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1932)
        at ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:68)
        at ognl.OgnlRuntime.callMethod(OgnlRuntime.java:1996)
        at ognl.ASTMethod.getValueBody(ASTMethod.java:91)
        at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
        at ognl.SimpleNode.getValue(SimpleNode.java:258)
        at ognl.ASTChain.getValueBody(ASTChain.java:141)
        at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
        at ognl.SimpleNode.getValue(SimpleNode.java:258)
        at ognl.Ognl.getValue(Ognl.java:537)
        at ognl.Ognl.getValue(Ognl.java:501)
        at org.thymeleaf.standard.expression.OGNLVariableExpressionEvaluator.executeExpression(OGNLVariableExpressionEvaluator.java:326)
        at org.thymeleaf.standard.expression.OGNLVariableExpressionEvaluator.evaluate(OGNLVariableExpressionEvaluator.java:170)
        ... 25 more
Caused by: java.lang.NoSuchMethodException: java.util.HashMap.get(java.lang.String)
        at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1873)
        ... 37 more

Steps To Reproduce

  • Create an app with features views-thymeleaf and graalvm
    mn create-app com.example.demo --features=views-thymeleaf,graalvm

  • Create a controller with a method that creates a model similar to what's available when using security, i.e. a security map containing an attributes map:

package com.example;

import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.views.View;

import java.util.HashMap;
import java.util.Map;

@Controller
class HomeController {

    @View("home")
    @Get
    Map<String, Object> index() {
        Map<String, Object> attributes = new HashMap<>();
        attributes.put("foo", "bar");

        Map<String, Object> security = new HashMap<>();
        security.put("attributes", attributes);

        Map<String, Object> model = new HashMap<>();
        model.put("security", security);

        return model;
    }
}
  • Create src/main/resources/views/home.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<body>

<h2>foo: <span th:text="${security.attributes.get('foo')}"></span></h2>

</body>
</html>

Environment Information

GraalVM version 22.0.0.2.r11-grl

Example Application

No response

Version

3.3.4

@burtbeckwith
Copy link
Member Author

I tried switching to Velocity and that failed too, but with different output - instead of a stacktrace, the expression is rendered unprocessed to the HTML, e.g. Username: $security.attributes.get('user_displayname')

@sdelamo
Copy link
Contributor

sdelamo commented May 25, 2022

You can add:

package com.example;

import io.micronaut.core.annotation.TypeHint;

import java.util.HashMap;
import java.util.Map;

@TypeHint(value = {Map.class, HashMap.class}, accessType = TypeHint.AccessType.ALL_DECLARED_METHODS)
public class ThymleafGraalConfig {
}

which will generate at build/classes/java/main/META-INF/native-image/xxx/xxx/reflect-config.json:

[ {
  "name" : "java.util.Map",
  "allDeclaredMethods" : true
}, {
  "name" : "java.util.HashMap",
  "allDeclaredMethods" : true
} ]

One way to see what you need to generate is to add the following snippet to build.gradle.

run {
    jvmArgs = [
        "-agentlib:native-image-agent=experimental-class-loader-support,config-output-dir=tmp",
        "-Dorg.graalvm.nativeimage.imagecode=agent"
    ]
}

run the app with a GraalVM JDK but JIT:

% sdk use java 22.1.0.r11-grl
% ./gradlew run

A folder tmp is created by the GraalVM agent with information about the necessary reflect-config.json

@sdelamo sdelamo added info: workaround available A workaround is available for the issue relates-to: graal labels May 25, 2022
@gijsleussink
Copy link

Does the snippet with which you see what to generate still apply? I'm not aware of the changes since 1,5y in that area.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
info: workaround available A workaround is available for the issue relates-to: graal
Projects
None yet
Development

No branches or pull requests

3 participants