We highly recommend completing the upgrade to Thymeleaf 3 as it is mostly a drop-in replacement for Thymeleaf 2. You can read about the Thymeleaf 3 migration on Thymeleaf's website which also goes over the new features available in Thymeleaf 3.
If you are not using Thymeleaf at all (for instance if you are just using the Broadleaf REST APIs) then you can remove all of your Thymeleaf-specific code in your application.
Overview of Broadleaf changes
- All Thymeleaf specific code has been refactored to conform to various components defined in Common Presentation module. This allows us to provide a compatibility bridge between Thymeleaf 2 and 3.
- Thymeleaf version-specific code (for both Thymeleaf 2 and 3) has been refactored into Maven modules
broadleaf-thymeleaf2-presentation
](https://github.com/BroadleafCommerce/PresentationLayer/tree/HEAD/broadleaf-thymeleaf2-presentation) andbroadleaf-thymeleaf3-presentation
](https://github.com/BroadleafCommerce/PresentationLayer/tree/HEAD/broadleaf-thymeleaf3-presentation) that have a common dependency onbroadleaf-common-presentation
- All boilerplate setup (like default template resolvers, email template resolvers, template engines and view resolvers) has been moved to their respective implementations (either Thymeleaf 2 or 3) reducing the amount of code you have to continue to maintain
- The Thymeleaf Layout Dialect is no longer included by default
Required Migration
Adjust the new pom.xml
dependencies
First, you will need to choose which version of Thymeleaf you would like to use. We strongly recommend upgrading to use Thymeleaf 3. You can read about the Thymeleaf-specific upgrade via the Thymeleaf migration docs. To use Thymeleaf 3 with Broadleaf, add this dependency to both your site/pom.xml
and admin/pom.xml
:
<dependency>
<groupId>org.broadleafcommerce</groupId>
<artifactId>broadleaf-thymeleaf3-presentation</artifactId>
<version>1.0.0-GA</version>
</dependency>
If you would instead like to continue to use Thymeleaf 2, add this dependency to both your site/pom.xml
and admin/pom.xml
:
<dependency>
<groupId>org.broadleafcommerce</groupId>
<artifactId>broadleaf-thymeleaf2-presentation</artifactId>
<version>1.0.0-GA</version>
</dependency>
Note: the site and admin applications can run different versions of Thymeleaf
Thymeleaf Layout Dialect
If you are using the Thymeleaf Layout Dialect (meaning, you declarations like layout:decorator
in your templates) then you will also need to manually add in that dependency.
Thymeleaf 2
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
<version>1.2.5</version>
</dependency>
Note: this 1.2.5 version of the layout dialect past version 1.2.5 has large performance penalties as the codebase has moved to a Groovy implementation instead of a Java one. This is remedied by a Thymeleaf 3 fork of the layout dialect
Thymeleaf 3
<dependency>
<groupId>com.github.zhanhb</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
<version>2.1.2</version>
</dependency>
You will also need to manually add the layout dialect into the list of dialects to be picked up by the blWebTemplateEngine
; it is no longer added automatically. Add this to your applicationContext.xml
:
<bean id="siteWebDialects" class="org.springframework.beans.factory.config.SetFactoryBean">
<property name="sourceSet">
<set>
<bean class="nz.net.ultraq.thymeleaf.LayoutDialect" />
</set>
</property>
</bean>
<bean class="org.broadleafcommerce.common.extensibility.context.merge.LateStageMergeBeanPostProcessor">
<property name="collectionRef" value="siteWebDialects" />
<property name="targetRef" value="blWebDialects" />
</bean>
Processor APIs
All of the Broadleaf default processors in the blc
and blc_admin
dialects have changed their implementations to match the common presentation API spec to support both Thymeleaf 2 and 3. If you have not extended one of these default processors, the HTML is still the same so you should not have to make any updates. If you have overridden one of the default processors this should just be a matter of changing the method signature to match the new parent.
If you have a custom processor, you only need to change if you decide to upgrade to Thymeleaf 3 with the new processor API.
Processor Registration
If you have added custom processors to a custom dialect, the way you register that dialect with Broadleaf has changed. If you have configuration in your application context XML files that looks similar to this:
<bean id="myDialect" class="com.mycompany.common.web.dialect.MyDialect">
<property name="processors">
<set>
<bean class="com.mycompany.common.web.processor.MyProcessor" />
</set>
</property>
</bean>
<bean id="blWebTemplateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
<property name="dialects">
<set>
<bean ref="myDialect" />
</set>
</property>
</bean>
You must replace it with this:
<bean id="myDialect" class="com.mycompany.common.web.dialect.MyDialect">
<property name="processors">
<set>
<bean class="com.mycompany.common.web.processor.MyProcessor" />
</set>
</property>
</bean>
<bean id="customDialects" class="org.springframework.beans.factory.config.SetFactoryBean">
<property name="sourceSet">
<set>
<bean ref="myDialect" />
</set>
</property>
</bean>
<bean class="org.broadleafcommerce.common.extensibility.context.merge.LateStageMergeBeanPostProcessor">
<property name="collectionRef" value="customDialects" />
<property name="targetRef" value="blWebDialects" />
</bean>
This adds your dialect to the blWebDialects
set that is registered in the blWebTemplateEngine
. There are also other dialect sets for blEmailDialects
and blAdminDialects
if you want to add your custom dialect to the blEmailTemplateEngine
or the blAdminTemplateEngine
.
Variable expressions
These are classes that implement the BroadleafVariableExpression
interface and are used in a template like ${#brc.getSite()}
. These work exactly as they did before, except for configuration changes.
Remove any instances of blVariableExpressions
from your ApplicationContext xml files. For instance, if you have something like this:
<bean id="blVariableExpressions" class="org.springframework.beans.factory.config.ListFactoryBean">
<property name="sourceList">
<list>
<bean class="com.mycompany.web.expression.CustomVariableExpression" />
</list>
</property>
</bean>
You should remove this bean definition completely and replace it with just this:
<bean class="com.mycompany.web.expression.CustomVariableExpression" />
Note: it is not required to specify this in XML, just ensure that your
VariableExpression
implementation is registered in the SpringApplicationContext
with just@Component
Template resolvers
Custom Resolvers
Previously, 3 lists were maintained and were the only avenues to add custom template resolvers to Broadleaf:
blWebTemplateResolvers
- frontend site resolvers, registered inblWebTemplateEngine
blEmailTemplateResolvers
- email resolvers, registered inblEmailTemplateEngine
blAdminWebTemplateResolvers
- admin resolvers, registered inblAdminTemplateEngine
If you have custom resolvers registered into any of these lists, then depending on what Thymeleaf version you are using you might have to modify the class name. However, it might also be useful to just create a bean in the application context that conforms to the BroadleafTemplateResolver
class.
For instance, say that you had this custom classpath template resolver in your application context xml:
<bean id="customClasspathResolver" class="org.thymeleaf.templateresolver.ClassLoaderTemplateResolver">
<property name="prefix" value="common_templates/templates/" />
<property name="suffix" value=".html" />
<property name="templateMode" value="HTML5" />
<property name="characterEncoding" value="UTF-8" />
<property name="cacheable" value="${cache.page.templates}"/>
<property name="cacheTTLMs" value="${cache.page.templates.ttl}" />
<property name="order" value="300"/>
</bean>
<!-- Register this -->
<bean class="org.broadleafcommerce.common.extensibility.context.merge.LateStageMergeBeanPostProcessor">
<property name="collectionRef" value="customClasspathResolver" />
<property name="targetRef" value="blWebTemplateResolvers" />
</bean>
Notice how the customClasspathResolver
is a Thymeleaf class, and also requires registration into the blWebTemplateResolvers
list. Instead, you can remove the extra registration like this:
<bean id="customClasspathResolver" class="org.broadleafcommerce.common.web.resolver.BroadleafThymeleafClasspathTemplateResolver">
<property name="prefix" value="common_templates/templates/" />
<property name="suffix" value=".html" />
<property name="templateMode" value="HTML5" />
<property name="characterEncoding" value="UTF-8" />
<property name="cacheable" value="${cache.page.templates}"/>
<property name="cacheTTLMs" value="${cache.page.templates.ttl}" />
<property name="order" value="300"/>
</bean>
This will automatically register this bean into blWebTemplateResolvers
in the frontend and blAdminWebTemplateResolvers
in the admin. If instead you want to make this available to resolve email templates, set emailResolver=true
:
<bean id="customClasspathResolver" class="org.broadleafcommerce.common.web.resolver.BroadleafThymeleafClasspathTemplateResolver">
<property name="emailResolver" value="true" />
<property name="prefix" value="common_templates/templates/" />
<property name="suffix" value=".html" />
<property name="templateMode" value="HTML5" />
<property name="characterEncoding" value="UTF-8" />
<property name="cacheable" value="${cache.page.templates}"/>
<property name="cacheTTLMs" value="${cache.page.templates.ttl}" />
<property name="order" value="300"/>
</bean>
If there is no reference to a custom TemplateResolver
then there is no change needed.
Email template resolvers
By default there was an email template resolver set up in core/src/main/resources/applicationContext-email.xml
which was moved into the default Broadleaf resolvers so this should be removed. Look for this in your application:
<bean id="blEmailTemplateResolver" class="org.thymeleaf.templateresolver.ClassLoaderTemplateResolver">
<property name="prefix" value="emailTemplates/" />
<property name="suffix" value=".html" />
<property name="cacheable" value="${cache.page.templates}"/>
<property name="cacheTTLMs" value="${cache.page.templates.ttl}" />
</bean>
If this is defined in the same way then it can be deleted.
Template engines
Email template engines
By default there was a template engine setup up for emails but it just added the template resolver mentioned in the last section so now that the template resolver was moved we don't need the template engine. So if in core/src/main/resources/applicationContext-email
the bean named blEmailTemplateEngine
looked like
<bean id="blEmailTemplateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
<property name="templateResolvers">
<set>
<ref bean="blEmailTemplateResolver" />
</set>
</property>
<property name="dialects">
<set>
<bean class="org.thymeleaf.spring4.dialect.SpringStandardDialect" />
<ref bean="blDialect" />
</set>
</property>
</bean>
then it can be removed. If there was any customizations then it should be left and no changes should be needed
View resolvers
By default there was a declaration of a site view resolver and admin view resolver declared in site/src/main/webapp/WEB-INF/applicationContext-servlet.xml
and admin/src/main/webapp/WEB-INF/applicationContext-servlet-admin.xml
respectively. These are now provided by default so they should be removed. Look for instances like this in site
:
<bean class="org.broadleafcommerce.common.web.BroadleafThymeleafViewResolver">
<property name="templateEngine" ref="blWebTemplateEngine" />
<property name="order" value="1" />
<property name="cache" value="${thymeleaf.view.resolver.cache}" />
<property name="fullPageLayout" value="layout/fullPageLayout" />
<property name="characterEncoding" value="UTF-8" />
</bean>
and this in admin
:
<bean class="org.broadleafcommerce.common.web.BroadleafThymeleafViewResolver">
<property name="templateEngine" ref="blAdminWebTemplateEngine" />
<property name="order" value="1" />
<property name="cache" value="${thymeleaf.view.resolver.cache}" />
<property name="characterEncoding" value="UTF-8" />
<property name="fullPageLayout" value="layout/fullPageLayout" />
<property name="layoutMap">
<map>
<entry key="login/" value="layout/loginLayout" />
<entry key="views/" value="NONE" />
<entry key="modules/modalContainer" value="NONE" />
</map>
</property>
</bean>
If there were changes then you simply need to add blThymeleafViewResolver
as the id for the site resolver and blAdminThymeleafViewResolver
as the id for the admin resolver to override the default definitions. Remove them (recommended) if you have no modifications.