spring-projects / spring-boot

Spring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss.
https://spring.io/projects/spring-boot
Apache License 2.0
75.21k stars 40.69k forks source link

SpelEvaluationException on native image when injecting a Map from @ConfigurationProperties into thymeleaf's view model #36684

Closed eidottermihi closed 1 year ago

eidottermihi commented 1 year ago

I have a simple Spring Boot / Spring MVC + Thymeleaf application, which injects a custom Map from application.yaml into the Thymeleaf model.

custom map props.apps in application.yaml:

props:
  apps:
    app1:
      display-name: App 1
    app2:
      display-name: App 2

@ConfigurationProperties classes (incl. @NestedConfigurationProperty):

@Configuration
@ConfigurationProperties(prefix = "props")
public class MyProperties {
    @NestedConfigurationProperty
    private Map<String, MyApp> apps;
        // getter / setter
}

@Configuration
@ConfigurationProperties
public class MyApp {
    private String displayName;
        // getter / setter
}

Spring MVC controller with Thymeleaf:

@Controller
public class ThymeleafMvcController {
        // .. autowired constructor with MyProperties attribute `props`

    @GetMapping("/")
    public String greeting(Model model) {
        model.addAttribute("apps", props.getApps());
        return "view";
    }
}

The view itself uses the map to render some content, view.html excerpt:

<body>
    <p>Apps: </p>
    <ul>
        <li th:each="app: ${apps}" th:id="'item-' + ${app.key}">
            <span th:text="${app.value.displayName}"></span>
        </li>
    </ul>
</body>

This is all working fine, but stops to work, if I'm building the app as a native image (with spring-boot-maven-plugin:build-image). The aot-processed native image starts fine, however a request to GET / then produces the following error:

org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'key' cannot be found on object of type 'java.util.LinkedHashMap$Entry' - maybe not public or not valid?

2023-08-02T13:27:00.399Z ERROR 1 --- [nio-8080-exec-3] org.thymeleaf.TemplateEngine             : [THYMELEAF][http-nio-8080-exec-3] Exception processing template "view": Exception evaluating SpringEL expression: "app.key" (template: "view" - line 13, col 30)

org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "app.key" (template: "view" - line 13, col 30)
        at org.thymeleaf.spring6.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:292) ~[na:na]
        at org.thymeleaf.standard.expression.VariableExpression.executeVariableExpression(VariableExpression.java:166) ~[de.muenchen.oss.appswitcher.Application:3.1.1.RELEASE]
        [.....]
        at java.base@17.0.7/java.lang.Thread.run(Thread.java:833) ~[de.muenchen.oss.appswitcher.Application:na]
        at com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:838) ~[de.muenchen.oss.appswitcher.Application:na]
        at com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:211) ~[na:na]
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'key' cannot be found on object of type 'java.util.LinkedHashMap$Entry' - maybe not public or not valid?
        at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:222) ~[na:na]
        at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:105) ~[na:na]
        at org.springframework.expression.spel.ast.PropertyOrFieldReference$AccessorLValue.getValue(PropertyOrFieldReference.java:410) ~[na:na]
        at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:96) ~[na:na]
        at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:114) ~[de.muenchen.oss.appswitcher.Application:6.0.11]
        at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:338) ~[na:na]
        at org.thymeleaf.spring6.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:265) ~[na:na]
        ... 73 common frames omitted

Demo to reproduce the issue: https://github.com/eidottermihi/native-thymeleaf-spel-config-props-demo , using Spring Boot 3.1.2.

wilkinsona commented 1 year ago

Duplicates #34206.