Unit Testing Freemarker templates in SpringBoot - unable to initialize freemarker configuration - spring-boot

we are using Freemarker for generating the HTML code for the emails our application is going to be sending.
Our usage and configuration is based off of https://github.com/hdineth/SpringBoot-freemaker-email-send
Particularly:
package com.example.techmagister.sendingemail.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
import org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean;
import java.io.IOException;
#Configuration
public class FreemarkerConfig {
#Bean(name="emailConfigBean")
public FreeMarkerConfigurationFactoryBean getFreeMarkerConfiguration(ResourceLoader resourceLoader) {
FreeMarkerConfigurationFactoryBean bean = new FreeMarkerConfigurationFactoryBean();
bean.setTemplateLoaderPath("classpath:/templates/");
return bean;
}
}
However, there is absolutely no information or documentation anywhere, about how to run Unit Tests for this using JUnit 5.
When I added the relevant dependencies
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
versions:
<junit.jupiter.version>5.3.1</junit.jupiter.version>
<mockito.version>2.23.0</mockito.version>
And made a test class:
package com.example.techmagister.sendingemail;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.io.IOException;
#ExtendWith({SpringExtension.class, MockitoExtension.class})
#Import(com.example.techmagister.sendingemail.config.FreemarkerConfig.class)
public class EmailTestTest {
private static final Logger LOGGER = LogManager.getLogger(EmailTestTest.class);
#Autowired
#Qualifier("emailConfigBean")
private Configuration emailConfig;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void test() throws Exception {
try {
Template template = emailConfig.getTemplate("email.ftl");
} catch (IOException e) {
e.printStackTrace();
}
}
}
When I run that in debug mode, emailConfig is null.
Why is that?
Their test example https://github.com/hdineth/SpringBoot-freemaker-email-send/blob/master/src/test/java/com/example/techmagister/sendingemail/SendingemailApplicationTests.java
works if I add the same autowired property, but it is a full SprintBoot context that is slow to boot, and I need to test just template usage, without actually sending out the email.
In our actual code (which is large, multi module project), I have another error org.springframework.beans.factory.UnsatisfiedDependencyException
caused by:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'freemarker.template.Configuration' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true), #org.springframework.beans.factory.annotation.Qualifier(value=emailConfigBean)}
But that is just for context, first I want to get it working in the simple, sample project then worry about getting it working in our complex one.

You cannot autowire your emailConfigBean directly as a freemarker.template.Configuration
FreeMarkerConfigurationFactoryBean is a factorybean.
To get the Confuguration you need to call factorybean.getObject()
so instead of
#Autowired
#Qualifier("emailConfigBean")
private Configuration emailConfig;
just autowire your factorybean FreeMarkerConfigurationFactoryBean and load your template with emailConfig.getObject().getTemplate("email.ftl")
#Autowired
#Qualifier("emailConfigBean")
private FreeMarkerConfigurationFactoryBean emailConfig;
#Test
void testFreemarkerTemplate(){
Assertions.assertNotNull(emailConfig);
try {
Template template =
emailConfig
.getObject() // <-- get the configuration
.getTemplate("email.ftl"); // <-- load the template
Assertions.assertNotNull(template);
} catch (Exception e) {
e.printStackTrace();
}
working test on github
On the other hand...
In a Spring Boot application the Freemarker configuration can be simplified by using the spring-boot-starter-freemarker dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
<version>1.5.6.RELEASE</version>
</dependency>
This starter for building MVC web applications using FreeMarker views adds the necessary auto-configuration. All you need to do is placing your template files in the resources/templates folder.
Then you just can autowire the freemarkerConfig (or use constructor injection):
#Autowired
private Configuration freemarkerConfig;

There is a nice example here, in the attached github code. I was able to use it as a starting point to test my freeMarker code: https://cleantestcode.wordpress.com/2014/06/01/unit-testing-freemarker-templates/

Related

Injection of CommandGateway not work in Quarkus using AxonIq

I have a microservice in Quarkus which implementing CQRS/Event sourcing using AxonIq Framework. I Already made it using Spring boot and everythings it's ok. I would like to migrate it in Quarkus but I have error during maven compilation probably because the Ioc. When CDI try to create the service I think he can inject Axon CommandGateway and QueryGateway.
[ERROR] Failed to execute goal io.quarkus.platform:quarkus-maven-plugin:2.7.1.Final:build (default) on project domain: Failed to build quarkus application: io.quarkus.builder.BuildExce
ption: Build failure: Build failed due to errors
[ERROR] [error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: Found 2 deployment problems:
[ERROR] [1] Unsatisfied dependency for type org.axonframework.Commandhandling.CommandGateway and qualifiers [#Default]
[ERROR] - java member: com.omb.commands.MyAggregateCommandService().commandGateway
[ERROR] - declared on CLASS bean [types=[com.omb.commands.MyAggregateCommandService, java.lang.Object], qualifiers=[#Default, #Any], target=com.omb.commands.MyAggregateCommandService]
Configuration
package com.omb..configuration;
import com.omb..MyAggregate;
import com.omb..commands.MyAggregateCommandService;
import com.omb..mongo.MongoMyAggregateProjector;
import com.omb..queries.MyAggregateQueryService;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoDatabase;
import org.axonframework.config.Configurer;
import org.axonframework.config.DefaultConfigurer;
import org.axonframework.eventsourcing.eventstore.EventStorageEngine;
import org.axonframework.extensions.mongo.DefaultMongoTemplate;
import org.axonframework.extensions.mongo.eventsourcing.tokenstore.MongoTokenStore;
import org.axonframework.serialization.xml.XStreamSerializer;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
#ApplicationScoped
public class AxonConfiguration {
#Produces
public org.axonframework.config.Configuration getAxonConfiguration(MongoMyAggregateProjector MyAggregateProjector, MongoDatabase database, EventStorageEngine eventStorageEngine) {
XStreamSerializer serializer = XStreamSerializer.defaultSerializer();
Configurer configurer = DefaultConfigurer
.defaultConfiguration()
.configureAggregate(MyAggregate.class)
.eventProcessing(conf -> conf
.registerTokenStore(config -> MongoTokenStore.builder()
.mongoTemplate(
DefaultMongoTemplate.builder()
// optionally choose collection names here
.mongoDatabase(database)
.build())
.serializer(serializer)
.build()))
.registerEventHandler(conf -> MyAggregateProjector)
.registerQueryHandler(conf -> MyAggregateProjector)
.configureEmbeddedEventStore(conf -> eventStorageEngine);
return configurer.start();
}
#Produces
public MongoDatabase mongoDatabase(MongoClient client) {
return client.getDatabase("MyAggregate");
}
#Produces
#ApplicationScoped
public MyAggregateQueryService queryService(org.axonframework.config.Configuration configuration) {
return new MyAggregateQueryService(configuration.queryGateway());
}
#Produces
#ApplicationScoped
public MyAggregateCommandService commandService(org.axonframework.config.Configuration configuration) {
return new MyAggregateCommandService(configuration.commandGateway());
}
}
Service :
package com.omb..commands;
import com.omb..models.MyAggregateDTO;
import org.axonframework.commandhandling.gateway.CommandGateway;
import javax.enterprise.context.ApplicationScoped;
import java.util.concurrent.CompletableFuture;
#ApplicationScoped
public class MyAggregateCommandService {
CommandGateway commandGateway;
public MyAggregateCommandService(CommandGateway commandGateway) {
this.commandGateway = commandGateway;
}
public CompletableFuture<String> createMyAggregate(final MyAggregateDTO MyAggregate) {
return commandGateway.send(new CreateMyAggregateCommand(MyAggregate.id(), MyAggregate.name()));
}
public CompletableFuture<MyAggregateDTO> updateMyAggregate(final String MyAggregateId, final MyAggregateDTO MyAggregate) {
if(MyAggregate.id().equals(MyAggregateId)) {
return commandGateway.send(new UpdateMyAggregateCommand(MyAggregate.id(), MyAggregate.name()));
} else {
throw new IllegalArgumentException("Identifiers are not the same, does not update");
}
}
}
Controller :
package com.omb;
import com.omb..commands.MyAggregateCommandService;
import com.omb..models.MyAggregateDTO;
import javax.validation.Valid;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
#Path("/commands/MyAggregate")
public class MyAggregateCommandController {
private MyAggregateCommandService MyAggregateCommandService;
public MyAggregateCommandController(MyAggregateCommandService MyAggregateCommandService) {
this.MyAggregateCommandService = MyAggregateCommandService;
}
#POST
#Path("/create")
public CompletableFuture<String> createMyAggregate(#Valid MyAggregateCreateInput MyAggregate) {
MyAggregateDTO MyAggregateDTO = new MyAggregateDTO(UUID.randomUUID().toString(), MyAggregate.name());
return MyAggregateCommandService.createMyAggregate(MyAggregateDTO);
}
#PUT
#Path("/{MyAggregateId}")
public CompletableFuture<MyAggregateDTO> updateMyAggregate(#PathParam("MyAggregateId") String MyAggregateId, MyAggregateDTO MyAggregate) {
MyAggregateDTO MyAggregateDTO = new MyAggregateDTO(MyAggregate.id(), MyAggregate.name());
return MyAggregateCommandService.updateMyAggregate(MyAggregateId,MyAggregateDTO);
}
/* #ExceptionHandler(value = Exception.class)
public ResponseEntity<String> handle(Exception e) {
return ResponseEntity.badRequest().body(e.getMessage());
}*/
}
dependency
<dependency>
<groupId>org.axonframework.extensions.mongo</groupId>
<artifactId>axon-mongo</artifactId>
<version>4.5</version>
</dependency>
<dependency>
<groupId>org.axonframework</groupId>
<artifactId>axon-test</artifactId>
<scope>test</scope>
<version>4.5.6</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-mongodb-panache</artifactId>
</dependency>
<dependency>
<groupId>org.axonframework</groupId>
<artifactId>axon-configuration</artifactId>
</dependency>
<dependency>
<groupId>org.axonframework</groupId>
<artifactId>axon-modelling</artifactId>
</dependency>
<dependency>
<groupId>org.axonframework</groupId>
<artifactId>axon-messaging</artifactId>
</dependency>
<!-- Quarkus -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-core</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-validator</artifactId>
</dependency>
I had the same issue, one of the reasons can be that your bean is brought by a dependency and to fix it you need to add an empty beans.xml in main/resources/META-INF in this dependency in order for Quarkus to discover the beans as indicated by the documentation
Relevant extract:
The bean archive is synthesized from:
the application classes,
dependencies that contain a beans.xml descriptor (content is ignored),
dependencies that contain a Jandex index - META-INF/jandex.idx,
dependencies referenced by quarkus.index-dependency in application.properties,
and Quarkus integration code.

Required: Definitive Annotations and pom dependencies to test Apache Camel with Spring Boot and Java Config

I'm going round in circles with this one.
Because it uses Spring Test and Java Config, I copied the simple FilterTest example from here, which worked OK as was.
But as soon as I added an #Autowired field, I got an UnsatisfiedDependencyException [Unsatisfied dependency expressed through field ... No qualifying bean of type ... available].
After fixing that I now get a NullPointerException on resultEndpoint.expectedBodiesReceived(expectedBody); in the first #Test method. When this happens, there is absolutely no output in the console, so evidently Spring hasn't even started.
Here's the slightly modified test class:
package org.apache.camel.spring.javaconfig.patterns;
import org.apache.camel.EndpointInject;
import org.apache.camel.Produce;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.spring.javaconfig.SingleRouteCamelConfiguration;
import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.context.ContextConfiguration;
import c10y.camel.converter.QbInvoiceConverter;
/**
* Tests filtering using Spring Test and Java Config
* page: https://camel.apache.org/manual/latest/testing.html
* code: https://github.com/apache/camel/blob/master/core/camel-core/src/test/java/org/apache/camel/processor/FilterTest.java
*/
#CamelSpringBootTest
#ContextConfiguration
#DirtiesContext(classMode = ClassMode.BEFORE_EACH_TEST_METHOD)
public class FilterTest {
#EndpointInject("mock:result")
protected MockEndpoint resultEndpoint;
#Produce("direct:start")
protected ProducerTemplate template;
#Autowired
private QbInvoiceConverter converter;
#Test
public void testSendMatchingMessage() throws Exception {
String expectedBody = "<matched/>";
resultEndpoint.expectedBodiesReceived(expectedBody);
template.sendBodyAndHeader(expectedBody, "foo", "bar");
resultEndpoint.assertIsSatisfied();
}
#Test
public void testSendNotMatchingMessage() throws Exception {
resultEndpoint.expectedMessageCount(0);
template.sendBodyAndHeader("<notMatched/>", "foo", "notMatchedHeaderValue");
resultEndpoint.assertIsSatisfied();
}
#Configuration
public static class ContextConfig extends SingleRouteCamelConfiguration {
#Bean
public RouteBuilder route() {
return new RouteBuilder() {
public void configure() {
from("direct:start")
.filter(header("foo")
.isEqualTo("bar"))
.to("mock:result")
;
}
};
}
}
}
I have tried to bring this up to date with the migration instructions here. Briefly, this states:
Migration steps linked to JUnit 5 support in Camel Test itself should have been applied first
Imports of org.apache.camel.test.spring.* should be replaced with org.apache.camel.test.spring.junit5.*
Usage of #RunWith(CamelSpringRunner.class) should be replaced with #CamelSpringTest
Usage of #BootstrapWith(CamelTestContextBootstrapper.class) should be replaced with #CamelSpringTest
Usage of #RunWith(CamelSpringBootRunner.class) should be replaced with #CamelSpringBootTest
The other part of my question relates to having the correct dependencies in pom.xml. I'm learning Camel from Camel in Action E2, so my pom has test dependencies from the book as well as others I have picked up on the way; so there may be clashes or incompatibilities in there:
<!-- from .../camel-in-action-2/chapter9/spring-boot-test-one-route/pom.xml -->
<!-- test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-test</artifactId>
<scope>test</scope>
</dependency>
<!-- testing -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-test-spring</artifactId>
<scope>test</scope>
</dependency>
<!-- from elsewhere -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-test-spring-junit5</artifactId>
<scope>test</scope>
</dependency>
I'm using Apache Camel 3.4.0 LTS and Spring Boot 2.3.0.RELEASE.
As the title to this question states, I'd really like to have the definitive annotation and pom configuration to allow me to simply get on with creating test routes to unit test my Components, Converters, and so forth [without tearing my hair out!].
PS: What's the difference between org.junit.Test and org.junit.jupiter.api.Test annotations, and when should you use one over the other?

Error creating spring boot bean - "The blank final field em may not have been initialized"

I am a newbie for the spring boot framework. I have successfully done crud operation. After that I have decided that to do Advanced search concepts. Please see the code below, which I used.
package com.lean.repository;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.springframework.data.jpa.repository.JpaRepository;
import com.lean.entity.Merchant;
public interface MerchantDao extends JpaRepository<Merchant, Long> {
EntityManager em;
public List<Merchant> findAllByNameIn(Set<String> name);
public default List<Merchant> findMerchantList(String name, String email) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Merchant> cq = cb.createQuery(Merchant.class);
Root<Merchant> book = cq.from(Merchant.class);
List<Predicate> predicates = new ArrayList<>();
if (name != null) {
predicates.add(cb.equal(book.get("name"), name));
}
if (email != null) {
predicates.add(cb.equal(book.get("email"), email));
}
cq.where(predicates.toArray(new Predicate[0]));
return em.createQuery(cq).getResultList();
};
}
Here, I am getting the below error.
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'merchantDao': Invocation of init method failed; nested exception is java.lang.Error: Unresolved compilation problem:
The blank final field em may not have been initialized
When I am trying to get the"EntityManager em" entity object, I will get the above error.
Please help someone to fix the issue. Thanks in advance
Try this :-
#PersistenceContext
private EntityManager em;
Also check for below dependencies
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.3.11.Final</version>
</dependency>
</dependencies>

org.springframework.beans.factory.UnsatisfiedDependencyException on Cloud Rest Client with Netflix Ribbon

I am getting
a org.springframework.beans.factory.UnsatisfiedDependencyException while running SpringClientSideRibbonApplication.java class. I think there is no error but I don't know why this exception comes. Please help me. I am using STS IDE.
MyConfiguration.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.PingUrl;
import com.netflix.loadbalancer.WeightedResponseTimeRule;
public class MyConfiguration {
#Autowired
IClientConfig ribbonClientConfig;
#Bean
public IPing ribbonPing(IClientConfig config) {
return new PingUrl();
}
#Bean
public IRule ribbonRule() {
return new WeightedResponseTimeRule();
}
}
SpringClientSideRibbonApplication.java
package com.javasampleapproach.ribbon;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
#SpringBootApplication
#RibbonClient(name = "helloworld", configuration =
MyConfiguration.class)
public class SpringClientSideRibbonApplication {
public static void main(String[] args)
{
SpringApplication.run(SpringClientSideRibbonApplication.class,
args);
}
}
WebController.java
package com.javasampleapproach.ribbon;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
#RestController
public class WebController {
#LoadBalanced
#Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
#Autowired
RestTemplate restTemplate;
#RequestMapping("/helloworld")
public String home() {
return
this.restTemplate.getForObject("http://helloworld/greeting",
String.class);
}
}
Error Msg
Error creating bean with name 'myConfiguration': Unsatisfied
dependency expressed through field 'ribbonClientConfig'; nested
exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'ribbonClientConfiguration': Invocation
of init method failed; nested exception is
java.lang.NoClassDefFoundError:
org/apache/commons/configuration/AbstractConfiguration
Application.yml
spring:
application:
name: Ribbon-Client
helloworld:
ribbon:
eureka:
enabled: false
listOfServers: localhost:8090,localhost:8091,localhost:8092
ServerListRefreshInterval: 15000
server:
port: 8080
Dependency
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.3.5.RELEASE </version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Their is no coding error. The problem was in my Maven dependency.My internet is slow so Maven download the corrupt jar file. I tried with Gradle. Now it's okey

How to configure Java8TimeDialect manually in a Spring Boot application

Since I'm using Thymeleaf only for email template processing (not for view creation), I have the following exclusion in my application class (i.e. a class extending SpringBootServletInitializer):
#SpringBootApplication(exclude=org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration.class)
Absent Spring Boot's autoconfiguration, I need to configure the Java8TimeDialect class manually, so I've added the following bean to my ThymeleafConfig class:
#Bean
public Java8TimeDialect java8TimeDialect() {
return new Java8TimeDialect();
}
Nonetheless, I'm still getting the following exception:
Attempted to call method
format(java.time.LocalDateTime,java.lang.String) on null context
object
Clearly the temporals object isn't being added to the context. How can I resolve this?
I've included Thymeleaf in my POM file as follows:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
<version>3.0.0.RELEASE</version>
</dependency>
Add pom.xml
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
then:
package com.users.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.thymeleaf.extras.java8time.dialect.Java8TimeDialect;
import nz.net.ultraq.thymeleaf.LayoutDialect;
#Configuration
public class Thymeleaf {
//TemplateEngine templateEngine = new TemplateEngine();
#Bean
public Java8TimeDialect java8TimeDialect() {
return new Java8TimeDialect();
}
#Bean
public LayoutDialect layoutDialect() {
return new LayoutDialect();
}
Finnally:
The time is: <strong th:text="${#temporals.format(now, 'dd/MMM/yyyy HH:mm')}">31/12/2015 15:00</strong>

Resources