[JAVA] Extend Thymeleaf (UtilityObject)

There are several ways to add your own functionality to Thymeleaf, but this time we will summarize how to add a UtilityObject. I refer to the following documents. http://www.thymeleaf.org/doc/tutorials/3.0/extendingthymeleaf.html

environment

What is Utility Object?

Something like \ # dates or \ #lists. http://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#expression-utility-objects

How to make

Create the body

Create a class and method that actually does the processing. You can create this without thinking about anything. This time, I will create a method that formats JapaneseDate and returns a character string.

public class SampleObject {

    DateTimeFormatter jpFormatter = DateTimeFormatter.ofPattern("Gyy year MM month dd day",
            Locale.JAPAN);

    public String format(JapaneseDate date) {
        if (date == null) {
            return null;
        }

        return jpFormatter.format(date);
    }
}

Create a class to manage the extension

To do your own extension, you need to create a Dialect class to manage it. The class to be implemented will change depending on the extension method, but this time we will create a class that implements IExpressionObjectDialect. Following the StantdardDialect class, we also inherit the AbstractDialect class.

However, before extending UtilityObject, it is necessary to create a Factory class that implements IExpressionObjectFactory. In this Factory class, instantiate the main SampleObject class.

Create a Factory class

public class SampleExpressionObjectFactory implements IExpressionObjectFactory {

    private static final String sampleExcepressionObjectName = "sample";

    @Override
    public Set<String> getAllExpressionObjectNames() {
        Set<String> nameSet = new HashSet<>();
        nameSet.add(sampleExcepressionObjectName);
        return nameSet;
    }

    @Override
    public Object buildObject(IExpressionContext context, String expressionObjectName) {
        if (Objects.equals(sampleExcepressionObjectName, expressionObjectName)) {
            return new SampleObject();
        }
        return null;
    }

    @Override
    public boolean isCacheable(String expressionObjectName) {
        return true;
    }
}

In the getAllExpressionObjectNames method, the character string for calling the UtitlityObject to be added is returned as a Set. This time, I am trying to make it possible to call the process in the format of #sample.

In the buildObject method, associate the character string for calling UtilityObject with the actual UtilityObject. For the character string sample, the SampleObject instance is returned.

The isCacheable method determines whether to cache the object. This time, I set it to true for the time being. It can be specified for each Object.

Create a Dialect class

public class SampleDialect extends AbstractDialect implements IExpressionObjectDialect {

    public SampleDialect() {
        super("sample");
    }

    @Override
    public IExpressionObjectFactory getExpressionObjectFactory() {
        return new SampleExpressionObjectFactory();
    }
}

Decide on a name for this Dialect in the constructor. I'm not sure what it's used for. .. I checked the call hierarchy, but since it is only called from a method called printConfiguration, is it for log output?

In the getExpressionObjectFactory method, return the Factory class created earlier.

Register Dialect

Add the Dialect class created this time to TemplateEngine of Thymeleaf. This time, Thymeleaf settings are defined in spring-mvc.xml, so add them to additionalDialects as follows.

<bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
  <property name="templateResolver" ref="templateResolver" />
  <property name="additionalDialects">
    <set>
      <bean class="sample.SampleDialect" />
    </set>
  </property>
</bean>

Try to move

I created the following Controller and html and confirmed the operation.

@Controller
public class HelloController {

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(Model model) {

        model.addAttribute("date", JapaneseDate.now());

        return "home";
    }

}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Home</title>
</head>
<body>
  <h1>Hello world!</h1>
  <p th:text="${#sample.format(date)}">hogehoge</p>
</body>
</html>

If "Heisei yy MM month dd day" (current date) is displayed under Hello World, it is complete.

Recommended Posts

Extend Thymeleaf (UtilityObject)
Extend Thymeleaf to implement unique tags (Part 1)
thymeleaf start-up
thymeleaf memorandum