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.
Comment From: wilkinsona
Duplicates #34206.