Documentation

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

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 Spring ApplicationContext 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 in blWebTemplateEngine
  • blEmailTemplateResolvers - email resolvers, registered in blEmailTemplateEngine
  • blAdminWebTemplateResolvers - admin resolvers, registered in blAdminTemplateEngine

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.