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

EvaluationException after an automatic restart of Spring Boot DevTools #286

Open
marcelopbarros opened this issue Mar 26, 2022 · 0 comments

Comments

@marcelopbarros
Copy link

Hi guys. In our project I had a problem that started when we updated Thymeleaf to version 3.0.15. I hope I can help improve Thymeleaf showing the details of the problem.

Brief description of the problem:

In our project we have a method that receives an Enum and is called from the view. In the view, we iterate over the enum values to present a select element and then call the function with every enum. Everything works fine at first glance, but when a hot restart occurs (Spring Boot DevTools) the method returns an error.

Steps to reproduce de problem:

  1. Start a new project on https://start.spring.io/ using any version newer than 2.5.10. Chose only the following dependencies:
  • Spring Web
  • Thymeleaf
  • Spring Boot DevTools
  1. Include the file bellow BasicController.java in src/main/java/com/example/demo:
package com.example.demo;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class BasicController {

    @GetMapping
    public String index() {
        return "basic";
    }

    public String getEnumName(BasicEnum myEnum) {
        return myEnum.name();
    }

    public enum BasicEnum {
        IPSUM, LOREM
    }
}
  1. Include the file bellow basic.html in /src/main/resources/templates:
<html>
<body th:with="BasicEnum=${T(com.example.demo.BasicController$BasicEnum)}">
    <h1 th:each="myEnum : ${BasicEnum.values()}"
    th:text="${@basicController.getEnumName(myEnum)}"></h1>
</body>
</html>
  1. Execute the project on IDE or with ./mvnw spring-boot:run.
  2. Access the main page at http://localhost:8080/. Everything works fine.
  3. Make any dummy change on Java file on IDE or execute ./mvnw compile to fire a hot restart using Spring Boot DevTools.
  4. Now access the main page at http://localhost:8080/. You should see the error message below:
There was an unexpected error (type=Internal Server Error, status=500).
An error happened during template parsing (template: "class path resource [templates/basic.html]")
org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resource [templates/basic.html]")
	at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:241)
	at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parseStandalone(AbstractMarkupTemplateParser.java:100)
	at org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:666)
	at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1098)
	at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1072)
	at org.thymeleaf.spring5.view.ThymeleafView.renderFragment(ThymeleafView.java:366)
	at org.thymeleaf.spring5.view.ThymeleafView.render(ThymeleafView.java:190)
	at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1401)
	at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1145)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1084)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:655)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:889)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: org.attoparser.ParseException: Exception evaluating SpringEL expression: "@basicController.getEnumName(myEnum)" (template: "basic" - line 4, col 5)
	at org.attoparser.MarkupParser.parseDocument(MarkupParser.java:393)
	at org.attoparser.MarkupParser.parse(MarkupParser.java:257)
	at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:230)
	... 48 more
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "@basicController.getEnumName(myEnum)" (template: "basic" - line 4, col 5)
	at org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:292)
	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.Model.process(Model.java:282)
	at org.thymeleaf.engine.Model.process(Model.java:290)
	at org.thymeleaf.engine.IteratedGatheringModelProcessable.processIterationModel(IteratedGatheringModelProcessable.java:367)
	at org.thymeleaf.engine.IteratedGatheringModelProcessable.process(IteratedGatheringModelProcessable.java:221)
	at org.thymeleaf.engine.ProcessorTemplateHandler.handleCloseElement(ProcessorTemplateHandler.java:1640)
	at org.thymeleaf.engine.TemplateHandlerAdapterMarkupHandler.handleCloseElementEnd(TemplateHandlerAdapterMarkupHandler.java:388)
	at org.thymeleaf.templateparser.markup.InlinedOutputExpressionMarkupHandler$InlineMarkupAdapterPreProcessorHandler.handleCloseElementEnd(InlinedOutputExpressionMarkupHandler.java:322)
	at org.thymeleaf.standard.inline.OutputExpressionInlinePreProcessorHandler.handleCloseElementEnd(OutputExpressionInlinePreProcessorHandler.java:220)
	at org.thymeleaf.templateparser.markup.InlinedOutputExpressionMarkupHandler.handleCloseElementEnd(InlinedOutputExpressionMarkupHandler.java:164)
	at org.attoparser.HtmlElement.handleCloseElementEnd(HtmlElement.java:169)
	at org.attoparser.HtmlMarkupHandler.handleCloseElementEnd(HtmlMarkupHandler.java:412)
	at org.attoparser.MarkupEventProcessorHandler.handleCloseElementEnd(MarkupEventProcessorHandler.java:473)
	at org.attoparser.ParsingEle<thymeleaf.version>3.0.14.RELEASE</thymeleaf.version>mentMarkupUtil.parseCloseElement(ParsingElementMarkupUtil.java:201)
	at org.attoparser.MarkupParser.parseBuffer(MarkupParser.java:725)
	at org.attoparser.MarkupParser.parseDocument(MarkupParser.java:301)
	... 50 more
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1004E: Method call: Method getEnumName(com.example.demo.BasicController$BasicEnum) cannot be found on type com.example.demo.BasicController
	at org.springframework.expression.spel.ast.MethodReference.findAccessorForMethod(MethodReference.java:225)
	at org.springframework.expression.spel.ast.MethodReference.getValueInternal(MethodReference.java:135)
	at org.springframework.expression.spel.ast.MethodReference.access$000(MethodReference.java:55)
	at org.springframework.expression.spel.ast.MethodReference$MethodValueRef.getValue(MethodReference.java:386)
	at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:92)
	at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:112)
	at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:338)
	at org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:265)
	... 75 more
  1. Now stop the project and include the property bellow in pom.xml:
<thymeleaf.version>3.0.14.RELEASE</thymeleaf.version>
  1. Reproduce again the steps 4 to 7, but now, no error will be rendered no screen.

Workarounds:

The way we've been doing is fixing version of Thymeleaf to 3.0.14. But I see that rewriting the method to receive a String and passing the name(), retrieving again on controller with BasicEnum.valueOf would do the job. It seems like the problem happens exclusively with enums.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant