eclipse-ee4j / krazo

Apache License 2.0
52 stars 19 forks source link

`NullPointerException` when using `thymeleaf-extras-java8time` #222

Closed thomas-mc-work closed 3 years ago

thomas-mc-work commented 3 years ago

I'd like to format a LocalDate value properly in a Thymeleaf template like this:

@Inject
Models models;

@GET
public String getRequest() {
    models.put("localDate", LocalDate.now());
    return "demo.html";
}

View:

<html>
    <body>
        <p th:text="${#temporals.formatISO(localDate)}"></p>
    </body>
</html>

This leads to an exception:

  org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating OGNL expression: "#temporals.formatISO(localDate)" (template: "/WEB-INF/views/demo.html" - line 4, col 12)
org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating OGNL expression: "#temporals.formatISO(localDate)" (template: "/WEB-INF/views/demo.html" - line 4, col 12)
    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:592)
    at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1098)
    at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1067)
    at org.eclipse.krazo.ext.thymeleaf.ThymeleafViewEngine.processView(ThymeleafViewEngine.java:77)
    at org.eclipse.krazo.ext.thymeleaf.ThymeleafViewEngine$Proxy$_$$_WeldClientProxy.processView(Unknown Source)
    at org.eclipse.krazo.core.ViewableWriter.writeTo(ViewableWriter.java:160)
    at org.eclipse.krazo.core.ViewableWriter.writeTo(ViewableWriter.java:72)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.invokeWriteTo(WriterInterceptorExecutor.java:242)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo(WriterInterceptorExecutor.java:227)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:139)
    at org.glassfish.jersey.server.internal.JsonWithPaddingInterceptor.aroundWriteTo(JsonWithPaddingInterceptor.java:85)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:139)
    at org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundWriteTo(MappableExceptionWrapperInterceptor.java:61)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:139)
    at org.glassfish.jersey.message.internal.MessageBodyFactory.writeTo(MessageBodyFactory.java:1115)
    at org.glassfish.jersey.server.ServerRuntime$Responder.writeResponse(ServerRuntime.java:638)
    at org.glassfish.jersey.server.ServerRuntime$Responder.processResponse(ServerRuntime.java:371)
    at org.glassfish.jersey.server.ServerRuntime$Responder.process(ServerRuntime.java:361)
    at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:256)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:248)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:244)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:292)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:274)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:244)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:265)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:232)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:680)
    at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:392)
    at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:346)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:365)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:318)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:205)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1628)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:258)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:755)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:575)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:159)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:371)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:238)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:520)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:217)
    at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:182)
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:156)
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:218)
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:95)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:260)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:177)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:109)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:88)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:53)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:524)
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:89)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:94)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:33)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:114)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:569)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:549)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.NullPointerException: target is null for method formatISO
    at ognl.OgnlRuntime.callMethod(OgnlRuntime.java:1613)
    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:467)
    at ognl.Ognl.getValue(Ognl.java:431)
    at org.thymeleaf.standard.expression.OGNLVariableExpressionEvaluator.executeExpression(OGNLVariableExpressionEvaluator.java:316)
    at org.thymeleaf.standard.expression.OGNLVariableExpressionEvaluator.evaluate(OGNLVariableExpressionEvaluator.java:170)
    ... 72 more

Here the relevant pom.xml part:

    <dependency>
        <groupId>org.eclipse.krazo.ext</groupId>
        <artifactId>krazo-thymeleaf</artifactId>
        <version>1.1.0</version>
    </dependency>
    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-java8time</artifactId>
        <version>3.0.4.RELEASE</version>
    </dependency>

What could be the reason for that exception? Only printing the raw date is working.

erdlet commented 3 years ago

Thanks for reporting this issue. I'll try to reproduce it.

erdlet commented 3 years ago

Hello @thomas-mc-work ,

It seems, that the Java Time Dialect has to be configured according to the add-on's installation guide within the Template-Engine.

package de.erdlet.thymeleaf_time_error;

import javax.enterprise.inject.Produces;
import javax.enterprise.inject.Specializes;

import org.eclipse.krazo.ext.thymeleaf.DefaultTemplateEngineProducer;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.extras.java8time.dialect.Java8TimeDialect;

public class ThymeleafConfiguration extends DefaultTemplateEngineProducer {

    @Override
    @Produces
    @Specializes
    public TemplateEngine getTemplateEngine() {
        final TemplateEngine templateEngine = super.getTemplateEngine();
        templateEngine.addDialect(new Java8TimeDialect());

        return templateEngine;
    }
}

I tried your example and was able to reproduce your problem without the class above. As soon as I add this configuration, my LocalDate will be formatted to 2020-11-11T00:00:00.000+0100.

Hope that resolves your problem.

thomas-mc-work commented 3 years ago

Thank you very much for your precise and fast reply, @erdlet!

I had to add the annotation @ApplicationScoped for the bean to be recognized. You've probably set bean-discovery-mode to all, did you?

erdlet commented 3 years ago

Yes, you're right. I think this is default in the projects generated by our archetype.

thomas-mc-work commented 3 years ago

Wouldn't it be nice to have this documented somewhere in this repository?

erdlet commented 3 years ago

Wouldn't it be nice to have this documented somewhere in this repository?

Good idea, I‘ll add a few words regarding this to the docs within the next days.