Saturday, December 13, 2014

Spring MVC 4 Quickstart Maven Archetype Improved

Spring Boot allows getting started with Spring extremely easy. But there are still people interested in not using Spring Boot and bootstrap the application in a more classical way. Several years ago, I created an archetype (long before Spring Boot) that simplifies bootstrapping Spring web applications. Although Spring Boot is already some time on the market, Spring MVC 4 Quickstart Maven Archetype is still quite popular project on GitHub. With some recent additions I hope it is even better.

Sunday, December 7, 2014

Sunday, November 23, 2014

Saturday, November 15, 2014

Monday, October 27, 2014

Spring Boot Actuator: custom endpoint with MVC layer on top of it

Spring Boot Actuator endpoints allow you to monitor and interact with your application. Spring Boot includes a number of built-in endpoints and you can also add your own. Adding custom endpoints is as easy as creating a class that extends from org.springframework.boot.actuate.endpoint.AbstractEndpoint. But Spring Boot Actuator offers also possibility to decorate endpoints with MVC layer.

Wednesday, October 22, 2014

ConEmu - Windows console emulator with tabs

After switching to Git some time ago, I started working more and more with Git Bash on Windows. Git Bash is pretty cool as it provides (apart from Git) Bash supported with basic Unix tools including curl or ssh. Git Bash in Windows has some limitation though including limited customization options and lack of good copy & paste options supported with keyboard shortcuts. Fortunately, there is ConEmu that not only fills that gap but adds various features that make working with console applications more productive and more enjoyable for me.

Friday, October 17, 2014

Spring Boot / Java 8 / Tomcat 8 on Openshift with DIY

DIY cartridge is an experimental cartridge that provides a way to test unsupported languages on OpenShift. It provides a minimal, free-form scaffolding which leaves all details of the cartridge to the application developer. This blog post illustrates the use of Spring Boot / Java 8 / Tomcat 8 application with PostgreSQL service bound to it.

Wednesday, October 8, 2014

Spring Boot and Spring Data REST - exposing repositories over REST

Exposing Spring Data repositories over REST is pretty easy with Spring Boot and Spring Data REST. With minimal code one can create REST representations of JPA entities that follow the HATEOAS principle. I decided to re-use Spring PetClinic’s JPA entities (business layer) as the foundation for this article.

Wednesday, September 17, 2014

Using @ConfigurationProperties in Spring Boot

In my latest blog post I described shortly how one can configure mail in Spring Boot application. To inject properties into the configuration I used Spring’s @Value annotation. But Spring Boot provides an alternative method of working with properties that allows strongly typed beans to govern and validate the configuration of your application. In this post I will demonstrate how to utilize @ConfigurationProperties while configuring the application.

Tuesday, September 16, 2014

Testing mail code in Spring Boot application

Whilst building a Spring Boot application you may encounter a need of adding a mail configuration. Actually, configuring the mail in Spring Boot does not differ much from configuring it in Spring Bootless application. But how to test that mail configuration and submission is working fine? Let’s have a look.

Tuesday, August 12, 2014

Validation groups in Spring MVC

All constraints in Bean Validation may be added to one or more groups via groups attribute. This allows you to restrict the set of constraints applied during validation. It can be handy in cases where some groups should be validated before others like e.g. in wizards. As of Spring MVC 3.1, automatic validation utilizing validation groups is possible with org.springframework.validation.annotation.Validated annotation. In this article I will use simple Spring MVC application to demonstrate how easily you can use validation groups to validate Spring’s MVC model attributes.

Form

Let’s start with the form class that will be validated in steps. Firstly, we define interfaces that represents constraint groups:

public class Account implements PasswordAware {

    interface ValidationStepOne {
        // validation group marker interface
    }

    interface ValidationStepTwo {
        // validation group marker interface
    }
}

Validation contraints

Next we assign constraint to groups. Remember, if you don’t provide groups the default one will be used. Please also note @SamePasswords, @StrongPassword - custom constraints, that must define groups attribute:

@SamePasswords(groups = {Account.ValidationStepTwo.class})
public class Account implements PasswordAware {

    @NotBlank(groups = {ValidationStepOne.class})
    private String username;

    @Email(groups = {ValidationStepOne.class})
    @NotBlank(groups = {ValidationStepOne.class})
    private String email;

    @NotBlank(groups = {ValidationStepTwo.class})
    @StrongPassword(groups = {ValidationStepTwo.class})
    private String password;

    @NotBlank(groups = {ValidationStepTwo.class})
    private String confirmedPassword;

    // getters and setters
}

Wizard

Having the Account, we can create a 3-step wizard @Controller that will let users create an account. In first step we will let Spring validate constraint in ValidationStepOne group:

@Controller
@RequestMapping("validationgroups")
@SessionAttributes("account")
public class AccountController {

    @RequestMapping(value = "stepOne")
    public String stepOne(Model model) {
        model.addAttribute("account", new Account());
        return VIEW_STEP_ONE;
    }

    @RequestMapping(value = "stepOne", method = RequestMethod.POST)
    public String stepOne(@Validated(Account.ValidationStepOne.class) Account account, Errors errors) {
        if (errors.hasErrors()) {
            return VIEW_STEP_ONE;
        }
        return "redirect:stepTwo";
    }
}

To trigger validation with groups I used @Validated annotation. This annotation takes var-arg argument with groups’ types. The code @Validated(ValidationStepOne.class) triggers validation of constraint in ValidationStepOne group.

In the next step we will let Spring validate constraint in ValidationStepTwo group:

@Controller
@RequestMapping("validationgroups")
@SessionAttributes("account")
public class AccountController {

    @RequestMapping(value = "stepTwo")
    public String stepTwo() {
        return VIEW_STEP_TWO;
    }

    @RequestMapping(value = "stepTwo", method = RequestMethod.POST)
    public String stepTwo(@Validated(Account.ValidationStepTwo.class) Account account, Errors errors) {
        if (errors.hasErrors()) {
            return VIEW_STEP_TWO;
        }
        return "redirect:summary";
    }
}

In the summary step we will confirm entered data and we will let Spring validate constraint of both groups:

@Controller
@RequestMapping("validationgroups")
@SessionAttributes("account")
public class AccountController {

    @RequestMapping(value = "summary")
    public String summary() {
        return VIEW_SUMMARY;
    }

    @RequestMapping(value = "confirm")
    public String confirm(@Validated({Account.ValidationStepOne.class, Account.ValidationStepTwo.class}) Account account, Errors errors, SessionStatus status) {
        status.setComplete();
        if (errors.hasErrors()) {
            // did not pass full validation
        }
        return "redirect:start";
    }
}

Prior to Spring 3.1 you could trigger the validation manually. I described this in one of my previous posts: http://blog.codeleak.pl/2011/03/how-to-jsr303-validation-groups-in.html

Note: If you want to use validation groups without Spring, you need to pass groups to javax.validation.Validator#validate():

Validation groups without Spring

Validator validator = Validation
        .buildDefaultValidatorFactory().getValidator();
Account account = new Account();

// validate with first group
Set<ConstraintViolation<Account>> constraintViolations =
        validator.validate(account, Account.ValidationStepOne.class);
assertThat(constraintViolations).hasSize(2);

// validate with both groups
Set<ConstraintViolation<Account>> constraintViolations =
        validator.validate(account, Account.ValidationStepOne.class, Account.ValidationStepTwo.class);
assertThat(constraintViolations).hasSize(4);

This is also the easiest way to test validations:

public class AccountValidationTest {

    private Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

    @Test
    public void shouldHaveFourConstraintViolationsWhileValidatingBothGroups() {
        Account account = new Account();
        Set<ConstraintViolation<Account>> constraintViolations = validator.validate(
                account, Account.ValidationStepOne.class, Account.ValidationStepTwo.class
        );
        assertThat(constraintViolations).hasSize(4);
    }

    @Test
    public void shouldHaveTwoConstraintViolationsWhileStepOne() {
        Account account = new Account();
        Set<ConstraintViolation<Account>> constraintViolations = validator.validate(
                account, Account.ValidationStepOne.class
        );
        assertThat(constraintViolations).hasSize(2);

    }
}

Testing validation with Spring Test

Testing validation with Spring Test offers more sophisticated way of testing if validation/binding failed. For the examples, have a look at my other blog post: Spring MVC Integration Testing: Assert the given model attribute(s) have global errors

The source code for this article can be found here: https://github.com/kolorobot/spring-mvc-beanvalidation11-demo

Tuesday, August 5, 2014

Spring MVC Integration Testing: Assert the given model attribute(s) have global errors

In order to report a global error in Spring MVC using Bean Validation we can create a custom class level constraint annotation. Global errors are not associated with any specific fields in the validated bean. In this article I will show how to write a test with Spring Test that verifies if the given model attribute has global validation errors.

Monday, July 28, 2014

Spring 4.1 and Java 8: java.util.Optional as a @RequestParam, @RequestHeader and @MatrixVariable in Spring MVC

As of Spring 4.1 Java 8’s java.util.Optional, a container object which may or may not contain a non-null value, is supported with @RequestParam, @RequestHeader and @MatrixVariable. While using Java 8’s java.util.Optional you make sure your parameters are never null.

Monday, July 7, 2014

JUnit: testing exception with Java 8 and Lambda Expressions

In JUnit there are many ways of testing exceptions in test code, including try-catch idiom, JUnit @Rule, with catch-exception library. As of Java 8 we have another way of dealing with exceptions: with lambda expressions. In this short blog post I will demonstrate a simple example how one can utilize the power of Java 8 and lambda expressions to test exceptions in JUnit.

Wednesday, July 2, 2014

Spring 4: CGLIB-based proxy classes with no default constructor

In Spring, if the class of a target object that is to be proxied doesn’t implement any interfaces, then a CGLIB-based proxy will be created. Prior to Spring 4, CGLIB-based proxy classes require a default constructor. And this is not the limitation of CGLIB library, but Spring itself. Fortunately, as of Spring 4 this is no longer an issue. CGLIB-based proxy classes no longer require a default constructor. How can this impact your code? Let’s see.

One of the idioms of dependency injection is constructor injection. It can be generally used when the injected dependencies are required and must not change after the object is initiated. In this article I am not going to discuss why and when you should use constructor dependency injection. I assume you use this idiom in your code or you consider using it. If you are interested in learning more, see the resources section in the bottom of this article.

Contructor injection with no-proxied beans

Having the following collaborator:


package pl.codeleak.services;

import org.springframework.stereotype.Service;

@Service
public class Collaborator {
    public String collaborate() {
        return "Collaborating";
    }
}

we can easily inject it via constructor:

package pl.codeleak.services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class SomeService {

    private final Collaborator collaborator;

    @Autowired
    public SomeService(Collaborator collaborator) {
        this.collaborator = collaborator;
    }

    public String businessMethod() {
        return collaborator.collaborate();
    }

}

You may notice the both Collaborator and the Service has no interfaces, but they are no proxy candidates. So this code will work perfectly fine with Spring 3 and Spring 4:

package pl.codeleak.services;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import pl.codeleak.Configuration;

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Configuration.class)
public class WiringTests {

    @Autowired
    private SomeService someService;

    @Autowired
    private Collaborator collaborator;

    @Test
    public void hasValidDependencies() {
        assertThat(someService)
                .isNotNull()
                .isExactlyInstanceOf(SomeService.class);

        assertThat(collaborator)
                .isNotNull()
                .isExactlyInstanceOf(Collaborator.class);

        assertThat(someService.businessMethod())
                .isEqualTo("Collaborating");
    }
}

Contructor injection with proxied beans

In many cases your beans need to be decorated with an AOP proxy at runtime, e.g when you want to use declarative transactions with @Transactional annotation. To visualize this, I created an aspect that will advice all methods in SomeService. With the below aspect defined, SomeService becomes a candidate for proxying:

package pl.codeleak.aspects;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class DummyAspect {

    @Before("within(pl.codeleak.services.SomeService)")
    public void before() {
        // do nothing
    }

}

When I re-run the test with Spring 3.2.9, I get the following exception:

Could not generate CGLIB subclass of class [class pl.codeleak.services.SomeService]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given

This can be simply fixed by providing a default, no argument, constructor to SomeService, but this is not what I want to do - as I would also need to make dependencies non-final.

Another solution would be to provide an interface for SomeService. But again, there are many situation when you don’t need to create interfaces.

Updating to Spring 4 solves the problem immediately. As documentation states:

CGLIB-based proxy classes no longer require a default constructor. Support is provided via the objenesis library which is repackaged inline and distributed as part of the Spring Framework. With this strategy, no constructor at all is being invoked for proxy instances anymore.

The test I created will fail, but it visualizes that CGLIB proxy was created for SomeService:

java.lang.AssertionError: 
Expecting:
 <pl.codeleak.services.SomeService@6a84a97d>
to be exactly an instance of:
 <pl.codeleak.services.SomeService>
but was an instance of:
 <pl.codeleak.services.SomeService$$EnhancerBySpringCGLIB$$55c3343b>

After removing the first assertion from the test, it will run just perfectly fine.

Resources

In case you need read more about constructor dependency injection, have a look at this great article by Petri Kainulainen: http://www.petrikainulainen.net/software-development/design/why-i-changed-my-mind-about-field-injection.

Core Container Improvements in Spring 4: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/new-in-4.0.html#_core_container_improvements

You may also be interested in reading my other articles about Spring: Spring 4: @DateTimeFormat with Java 8 Date-Time API and Better error messages with Bean Validation 1.1 in Spring MVC application

Sunday, June 29, 2014

Thursday, June 19, 2014

Better error messages with Bean Validation 1.1 in Spring MVC application

Bean Validation 1.1, among many new features, introduced error message interpolation using Unified Expression Language (EL) expressions. This allows to define error messages based on conditional logic and also enables advanced formatting options. Added to a Spring MVC application let you display more friendly error messages quite simply.

In the first part of this article I will shortly describe message interpolation with EL expressions, in the second part we will build a simple web application with Spring Boot and Thymeleaf that runs on Tomcat 8.

Monday, June 16, 2014

Sunday, June 15, 2014

Test Data Builders and Object Mother: another look

Constructing objects in tests is usually a painstaking work and usually it produces a lot of repeatable and hard to read code. There are two common solutions for working with complex test data: Object Mother and Test Data Builder. Both has advantages and disadvantages, but (smartly) combined can bring new quality to your tests.

Monday, June 9, 2014

Tuesday, June 3, 2014

Saturday, May 24, 2014

Thursday, May 22, 2014

Sunday, May 11, 2014

HOW-TO: Quartz Scheduler with Clustering in JEE application with MySQL

Quartz Scheduler is one of the most popular scheduling library in Java world. I had worked with Quartz mostly in Spring applications in the past. Recently, I have been investigating scheduling in JEE 6 application running on JBoss 7.1.1 that is going to be deployed in the cloud. As one of the options I consider is Quartz Scheduler as it offers clustering with database. In this article I will show how easy is to configure Quartz in JEE application and run it either on JBoss 7.1.1 or WildFly 8.0.0, use MySQL as job store and utilize CDI to use dependency injection in jobs. All will be done in IntelliJ. Let's get started.

Friday, May 2, 2014

Spring MVC and Thymeleaf: how to acess data from templates

Spring MVC and Thymeleaf: how to acess data from templates

I wrote this article for thymeleaf.org, with a great help of Daniel Fernández. You can find it here: http://www.thymeleaf.org/doc/articles/springmvcaccessdata.html

12/11/2016: Updated to Thymeleaf 3.0. Find the examples used in this article in this repository: https://github.com/kolorobot/spring-boot-thymeleaf (http://blog.codeleak.pl/2014/04/how-to-spring-boot-and-thymeleaf-with-maven.html)

In a typical Spring MVC application, @Controller classes are responsible for preparing a model map with data and selecting a view to be rendered. This model map allows for the complete abstraction of the view technology and, in the case of Thymeleaf, it is
transformed into a Thymeleaf context object (part of the Thymeleaf template execution context) that makes all the defined variables available to expressions executed in templates.

Spring model attributes

Spring MVC calls the pieces of data that can be accessed during the execution of views model attributes. The equivalent term in Thymeleaf language is context variables.

There are several ways of adding model attributes to a view in Spring MVC. Below you will find some common cases:

Add attribute to Model via its addAttribute method:


    @RequestMapping(value = "message", method = RequestMethod.GET)
    public String messages(Model model) {
        model.addAttribute("messages", messageRepository.findAll());
        return "message/list";
    }

Return ModelAndView with model attributes included:

    @RequestMapping(value = "message", method = RequestMethod.GET)
    public ModelAndView messages() {
        ModelAndView mav = new ModelAndView("message/list");
        mav.addObject("messages", messageRepository.findAll());
        return mav;
    }

Expose common attributes via methods annotated with @ModelAttribute:

    @ModelAttribute("messages")
    public List<Message> messages() {
        return messageRepository.findAll();
    }

As you may have noticed, in all the above cases the messages attribute is added to the model and it will be available in Thymeleaf views.

In Thymeleaf, these model attributes (or context variables in Thymeleaf jargon) can be accessed with the following syntax: ${attributeName}, where attributeName in our case is messages. This is a Spring EL expression. In short, Spring EL (Spring Expression Language) is a language that supports querying and manipulating an object graph at runtime.

You can access model attributes in views with Thymeleaf as follows:

    <tr th:each="message : ${messages}">
        <td th:text="${message.id}">1</td>
        <td><a href="#" th:text="${message.title}">Title ...</a></td>
        <td th:text="${message.text}">Text ...</td>
    </tr>

Request parameters

Request parameters can be easily accessed in Thymeleaf views. Request parameters are passed from the client to server like:

https://example.com/query?q=Thymeleaf+Is+Great!

Let’s assume we have a @Controller that sends a redirect with a request parameter:

    @Controller
    public class SomeController {
        @RequestMapping("/")
        public String redirect() {
            return "redirect:/query?q=Thymeleaf Is Great!";
        }
    }

In order to access the q parameter you can use the param. prefix:

    <p th:text="${param.q}">Test</p>

In the above example if parameter q is not present, empty string will be displayed in the above paragraph otherwise the value of q will be shown.

Since parameters can be multivalued (e.g. `https://example.com/query?q=Thymeleaf%20Is%20Great!&q=Really%3F) you may access them using brackets syntax:

    <p th:text="${param.q[0] + ' ' + param.q[1]}" th:unless="${param.q == null}">Test</p>

Note: If you access multivalued parameter with ${param.q} you will get a serialized array as a value.

Another way to access request parameters is by using the special #request object that gives you direct access to the javax.servlet.http.HttpServletRequest object:

<p th:text="${#request.getParameter('q')}" th:unless="${#request.getParameter('q') == null}">Test</p>

Session attributes

In the below example we add mySessionAttribute to session:

@RequestMapping({"/"})
String index(HttpSession session) {
    session.setAttribute("mySessionAttribute", "someValue");
    return "index";
}

Similarly to the request parameters, session attributes can be access by using the session. prefix:

<p th:text="${session.mySessionAttribute}" th:unless="${session == null}">[...]</p>

Or by using #session, that gives you direct access to the javax.servlet.http.HttpSession object: ${#session.getAttribute('mySessionAttribute')}

ServletContext attributes

The ServletContext attributes are shared between requests and sessions. In order to access ServletContext attributes in Thymeleaf you can use the #servletContext. prefix:

    <table>
        <tr>
            <td>My context attribute</td>
            <!-- Retrieves the ServletContext attribute 'myContextAttribute' -->
            <td th:text="${#servletContext.getAttribute('myContextAttribute')}">42</td>
        </tr>
        <tr th:each="attr : ${#servletContext.getAttributeNames()}">
            <td th:text="${attr}">javax.servlet.context.tempdir</td>
            <td th:text="${#servletContext.getAttribute(attr)}">/tmp</td>
        </tr>
    </table>

Spring beans

Thymeleaf allows accessing beans registered at the Spring Application Context with the @beanName syntax, for example:

<div th:text="${@urlService.getApplicationUrl()}">...</div> 

In the above example, @urlService refers to a Spring Bean registered at your context. E.g.

    @Configuration
    public class MyConfiguration {
        @Bean(name = "urlService")
        public UrlService urlService() {
            return () -> "domain.com/myapp";
        }
    }

    public interface UrlService {
        String getApplicationUrl();
    }

This is fairly easy and useful in some scenarios.

Sunday, April 13, 2014

HOW-TO: Spring Boot and Thymeleaf with Maven

Spring Boot is a great piece of software allowing you to bootstrap Spring application within a few seconds. And it really works. As little configuration as possible to get started. And still possible to change the defaults. Let's see how easily is to bootstrap Spring MVC with Thymeleaf and Maven and work with it in IntelliJ.

Week 14 and 15 in links!

Welcome to the next installment of Codeleak.pl: Week Review!, which became bi-weekly (so new name should apply...) I want to share with you some interesting reads that I encountered within last two weeks. A very subjective selection.

Thursday, April 10, 2014

CSRF protection in Spring MVC, Thymeleaf, Spring Security application

Cross-Site Request Forgery (CSRF) is an attack which forces an end user to execute unwanted actions on a web application in which he/she is currently authenticated. Preventing CSRF attacks in Spring MVC / Thymeleaf application is fairly easy if you use Spring Security 3.2 and above.

Wednesday, April 9, 2014

Yet another way to handle exceptions in JUnit: catch-exception

There are many ways of handling exceptions in JUnit (3 ways of handling exceptions in JUnit. Which one to choose?, JUnit ExpectedException rule: beyond basics). In this post I will introduce catch-exception library that I was recommended to give a try. In short, catch-exceptions is a library that catches exceptions in a single line of code and makes them available for further analysis.

Monday, March 31, 2014

Week 12 and 13 review

Welcome to the next installment of Codeleak.pl: Week Review!. I want to share with you some interesting reads that I encountered within last two weeks. A very subjective selection.

Sunday, March 16, 2014

Week 10 and 11 Review

Welcome to the next installment of Codeleak.pl: Week Review!. I want to share with you some interesting reads that I encountered this and previous week. A very subjective selection.

Wednesday, March 5, 2014

Sunday, March 2, 2014

Week 09 Review

Welcome to the next installment of Codeleak.pl: Week Review!. I want to share with you some interesting reads that I encountered this week. A very subjective selection.

Saturday, March 1, 2014

JUnit ExpectedException rule: beyond basics

There are different ways of handling exceptions in JUnit tests. As I wrote in one of my previous posts, my preferable way is using org.junit.rules.ExpectedException rule. Basically, rules are used as an alternative (or an addition) to methods annotated with org.junit.Before, org.junit.After, org.junit.BeforeClass, or org.junit.AfterClass, but they are more powerful, and more easily shared between projects and classes. In this post I will show more advanced usage of org.junit.rules.ExpectedException rule.

Sunday, February 23, 2014

Teacher's notes about reporting issues: theory and practice

In 2014, for the second time, I am a lecturer at Postgraduate Studies on Software Testing. I mainly run lectures, actually workshops, about tools and automation. The object of one of the workshops was to present and practice reporting issues in Jira. During the first day of workshop, students were testing a simple web application (https://github.com/kolorobot/spring-mvc-icm-demo) based on the test cases they created. As a result of testing they were asked to report their findings.

Sunday, February 16, 2014

Colored logs in a console (ANSI styling)

We had recently a big debate about logging in applications at my company. Inspired by my colleague, I decided to check how coloring will work on my Windows 8 64-bit machine. The idea is to have the logs colored in the console. Maybe a small detail, but while going through huge amounts of logs - can be handy. So I gave it a try.

Wednesday, February 12, 2014

Monday, February 3, 2014

Git bash in IntelliJ IDEA 13 on Windows

One of the top features of the recent release of IntelliJ IDEA 13 is definitively a built-in command-line interface. For me, this is really great feature - especially local terminal . I don't need to abandon the IDE to work with command-line interface anymore, e.g. while working with source code management systems like Git.

Monday, January 20, 2014

Thymeleaf Page Layouts

Usually websites share common page components like the header, footer, menu and possibly many more. These page components can be used by the same or different layouts. There are two main styles of organizing layouts in projects: include style and hierarchical style. Both styles can be easily utilized with Thymeleaf without losing its biggest value: natural templating.