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
VariableExpressionimplementation is registered in the SpringApplicationContextwith 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 inblWebTemplateEngineblEmailTemplateResolvers- email resolvers, registered inblEmailTemplateEngineblAdminWebTemplateResolvers- 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.