3.0 to 3.1 Migration Notes

These migration notes assumes that you are going from a stock Heat Clinic demo to the 3.1 demo. There might be addtional migration steps for your particular implementation of Broadleaf, please let us know on the forums or by submitting a pull request to this documentation site at

This document also assumes that you are on the latest 3.0 GA patch version of Broadleaf (like 3.0.8-GA). If you have not upgraded your site to be on the latest 3.0 patch version, please do so before continuing and see the optional migration docs for each 3.0 patch version.

Maven Updates

In the root pom.xml:

  1. Update the blc.version property to 3.1.0-GA:

  2. Update the version of the commons-dbcp to 1.4


Admin Updates

  1. Add the admin.css file to the blJsFileMap bean, underneath the admin.js entry. This looks like:

    <bean id="blJsFileMap" class="org.springframework.beans.factory.config.MapFactoryBean">
        <property name="sourceMap">
                <entry key="admin.js" value-ref="blJsFileList"/>
                <entry key="admin.css" value-ref="blCssFileList"/>

    Optional: since this no longer just represents JS files, you might want to rename this bean to something more appropriate like blResourceFileMap

  2. Update the mvc:resources definitions in applicationContext-servlet-admin to take into account the fact that some resources have been moved to common. The final definition of these entries should look like:

    <mvc:resources order="-10" location="classpath:/open_admin_style/img/, classpath:/common_style/img/" mapping="/img/**" />
    <mvc:resources order="-10" location="classpath:/open_admin_style/fonts/, classpath:/common_style/fonts/" mapping="/fonts/**" />
    <mvc:resources order="-10" location="WEB-INF/favicon.ico" mapping="/favicon.ico" />
    <mvc:resources order="-10" location="WEB-INF/robots.txt" mapping="/robots.txt" />

Core Updates

  1. Remove the custom class transformer designed to fix the max offer usage bug. This will effect you only if you are on Broadleaf 3.0.6-GA and above. This is no longer necessary in 3.1.0-GA and above.

Site Updates

  1. Move the blRequestFilter and blCustomerStateFilter into the blPostSecurityFilterChain located in applicationContext-filter.xml. The final version of this looks like:

    <bean id="blPostSecurityFilterChain" class="">
        <sec:filter-chain-map request-matcher="ant">
            <sec:filter-chain pattern="/**" filters="

    You should also remove the blRequestFilter from the blPreSecurityFilterChain (also in applicationContext-filter.xml) and remove blCustomerStateFilter located within the <sec:http> element in applicationContext-security.xml.

  2. Add the common fonts to applicationContext-servlet.xml:

    <mvc:resources order="-10" location="/img/, classpath:/common_style/img/" mapping="/img/**" />
    <mvc:resources order="-10" location="/fonts/, classpath:/common_style/fonts/" mapping="/fonts/**" />
    <mvc:resources order="-10" location="WEB-INF/favicon.ico" mapping="/favicon.ico" />

    Note: this is likely an optional step and only required if you depend on Broadleaf's version of FontAwesome and JQuery UI icons.

  3. The blc:head Thymeleaf processor is now deprecated with the upgrade to Thymeleaf 2.1. Replace all instances of code like:

        -    <blc:head pageTitle="Account - Broadleaf Demo - Heat Clinic" />

    with the following:

    <head th:include="/layout/partials/head (pageTitle='Account - Broadleaf Demo - Heat Clinic')"></head>

    The feature that allowed for parameterized includes (which eliminated the need for the head processor) is documented in the Thymeleaf 2.1 docs

  4. Remove the custom blUserDetailsService definition from `applicationContext-security.xml. This has been replaced by a component in the framework:

        -    <sec:jdbc-user-service data-source-ref="webDS"
        -        id="blUserDetailsService"
        -        users-by-username-query="SELECT USER_NAME,PASSWORD,TRUE FROM BLC_CUSTOMER WHERE USER_NAME=?"
        -        authorities-by-username-query="SELECT c.USER_NAME,r.ROLE_NAME from BLC_CUSTOMER c
        -                                          JOIN BLC_CUSTOMER_ROLE cr ON c.CUSTOMER_ID = cr.CUSTOMER_ID
        -                                          JOIN BLC_ROLE r ON cr.ROLE_ID = r.ROLE_ID
        -                                          WHERE USER_NAME=?" />

EHCache settings

New regions:

  1. blProducts (ProductAttribute, ProductBundle, Product, Sku, ProductOptionValue, ProductOption, SkuAttribute, SkuBundleItem, SkuFee)
  2. blCategories (Category, CategoryAttribute, CategoryProductXref, FeaturedProduct, CategorySearchFacet)
  3. blOffers (Offer, OfferItem, OfferRule)
  4. blCustomerElements (Customer)
  5. blConfigurationModuleElements (retrieving subtypes of AbstractModuleConfiguration)
  6. query.Offer (retrieving lists of offers via daos)

REST API Updates

New/Changed Methods

POST: /cart/items/{itemId}/options in

public OrderWrapper updateProductOptions(@Context HttpServletRequest request,
        @Context UriInfo uriInfo,
        @PathParam("itemId") Long itemId,
        @QueryParam("priceOrder") @DefaultValue("true") boolean priceOrder) {
    return super.updateProductOptions(request, uriInfo, itemId, priceOrder);

GET: /cart/checkout/payments in

public List<OrderPaymentWrapper> findPaymentsForOrder(@Context HttpServletRequest request) {
    return super.findPaymentsForOrder(request);

POST: /cart/checkout/payment in

public OrderPaymentWrapper addPaymentToOrder(@Context HttpServletRequest request,
                                             OrderPaymentWrapper wrapper) {
    return super.addPaymentToOrder(request, wrapper);

DELETE: /cart/checkout/payment in

public OrderWrapper removePaymentFromOrder(@Context HttpServletRequest request,
                                           OrderPaymentWrapper wrapper) {
    return super.removePaymentFromOrder(request, wrapper);

POST: /cart/checkout in

public OrderWrapper performCheckout(@Context HttpServletRequest request) {
    return super.performCheckout(request);

Note: this was modified to no longer require payments in the checkout invocation. Payments should be added to an order by an earlier invocation to /cart/checkout/payment

Deleted methods

/cart/checkout/payment/response in

To obtain these methods, add method to your

Workflow Updates

  1. The blPaymentsWorkflow along with all ancilliary workflows (like blAuthorizeWorkflow, blRefundWorkflow etc) has been removed. Any customizations or usage for these payment workflows should be migrated to the new way Broadleaf does payments in 3.1
  2. A new activity, blValidateProductOptionsActivity has been added with order 2000. This has bumped the ordering of the existing activities up by 1000. The final ordering of activities is:

    <bean p:order="1000" id="blVerifyCustomerMaxOfferUsesActivity" class="org.broadleafcommerce.core.offer.service.workflow.VerifyCustomerMaxOfferUsesActivity"/>
    <bean p:order="2000" id="blValidateProductOptionsActivity" class="org.broadleafcommerce.core.checkout.service.workflow.ValidateProductOptionsActivity"/>
    <bean p:order="3000" id="blValidateAndConfirmPaymentActivity" class="org.broadleafcommerce.core.checkout.service.workflow.ValidateAndConfirmPaymentActivity">
        <property name="rollbackHandler" ref="blConfirmPaymentsRollbackHandler" />
    <bean p:order="4000" id="blRecordOfferUsageActivity" class="org.broadleafcommerce.core.offer.service.workflow.RecordOfferUsageActivity">
        <property name="rollbackHandler" ref="blRecordOfferUsageRollbackHandler" />
    <bean p:order="5000" id="blCommitTaxActivity" class="org.broadleafcommerce.core.checkout.service.workflow.CommitTaxActivity">
        <property name="rollbackHandler" ref="blCommitTaxRollbackHandler" />
    <bean p:order="6000" id="blCompleteOrderActivity" class="org.broadleafcommerce.core.checkout.service.workflow.CompleteOrderActivity">
        <property name="rollbackHandler" ref="blCompleteOrderRollbackHandler" />

Thymeleaf 2.1 Updates

Braodleaf has changed the Thymeleaf version from 2.0 to 2.1. Depending on how many Thymeleaf processors you have in your codebase this migration step may vary. See the Thymeleaf documentation site for the changes. You might check our migration to Thymeleaf 2.1 for what we had to change in the framework.

Payment Module and Checkout Form Updates

We have completely rewritten the way that payments are treated in Broadleaf. We are still in the process of updating some of our existing payment modules. If there is a payment module written by Broadleaf that you need and has not been updated to the new 3.1 standards, please let us know at info AT

For more information on how to ensure that your payment module conforms to the new Broadleaf standards, see Checkout Page Design and Payment. You might also gain additional insight by looking at the null payment gateway module that we implemented within the 3.1 demo site.

Additional Miscellaneous Items

  1. The checkout confirmation email should be moved away from the order confirmation controller and instead should be a custom activity within the blCheckoutWorkflow
  2. Adding the disable-url-rewriting="true" attribute to the <sec:http> element in applicationContext-security.xml will disable any JSESSIONIDs appearing in URLs
  3. The ID field in admin list grids are no longer shown by default. You can re-enable this column with a showIds=true query parameter (e.g. /admin/product?showIds=true)
  4. The syntax for a custom Activity has changed from something like this:
public class MyCustomActivity extends BaseActivity<CheckoutContext> {

    public CheckoutContext execute(CheckoutContext context) throws Exception {


public class RecordOfferUsageActivity extends BaseActivity<ProcessContext<CheckoutSeed>> {

    public ProcessContext<CheckoutSeed> execute(ProcessContext<CheckoutSeed> context) throws Exception {

Broadleaf Framework Changes Requiring Migration

This section is designed for various components that you might be utilizing in Broadleaf that have been refactored or changed.

  1. ExtensionHandlers and ExtensionManagers have been moved into common
  2. FieldEnumeration and FieldEnumerationItem (along with the corresponding BLC_FIELD_ENUMERATION and BLC_FIELD_ENUMERATION_ITEM tables) used in CMS FieldDefinitions has been deprecated. This has instead been replaced by utilizing DataDrivenEnumeration instead. You should move any data that you have in BLC_FLD_ENUM into BLC_DATA_DRVN_ENUM and any data in BLC_FLD_ENUM_ITEM into BLC_DATA_DRVN_ENUM_VAL:


Database Changes

There are several DB changes related to the 3.0 to 3.1 upgrade. You can find the history of changes to the database in the Database Model.

We recommend you use a database management tool like Liquibase to manage DB versions. Here is a DB changelog file that was generated that compares a 3.0.x schema to a 3.1.x schema. If you aren't using Liquibase, please consider using it and see our tutorial for more details: Managing DB Versions Migrations With Liquibase

Alternatively, here is an example script of the changes that need to be applied for 3.1.
This script is based off of a Liquibase changelog Database diff. You will need to read the data migration section above and appropriately migrate the data if necessary. This script is intended to be non-destructive and does not contain any DROP statements. It is important to note that there will be certain tables that will no longer be used by the system.

TODO: provide instructions for how to go from the liquibase xml to a database-compatible dump (Oracle, Postgres, MySQL)

Data Migration

All Products should define a DEFAULT_SKU_ID in BLC_PRODUCT. This is a performance enhancement (as well as a requirement for Enterprise Broadleaf). Because of the way product and skus are modeled, having a real column reference on both sides removes an unnecessary sql call for every product retrieved.

Here is a liquibase snippet relating to this DB change:

    <changeSet author="liquibase (generated)" id="1391122037368-16">
        <addColumn tableName="BLC_PRODUCT">
            <column name="DEFAULT_SKU_ID" type="BIGINT(19)"/>
    <changeSet author="liquibase (generated)" id="1391122037368-56">
        <addForeignKeyConstraint baseColumnNames="DEFAULT_SKU_ID" baseTableName="BLC_PRODUCT" constraintName="FK5B95B7C96D386535" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="SKU_ID" referencedTableName="BLC_SKU"/>

All existing XREF tables that contain @EmbeddedId have now been refactored to define an explicit key. This is related to the issues discussed in this thread:

The following tables will be affected:


Here is a liquibase snippet relating to this DB change:

    <changeSet author="liquibase (generated)" id="1391122037368-13">
        <addColumn tableName="BLC_CATEGORY_PRODUCT_XREF">
            <column name="CATEGORY_PRODUCT_ID" type="BIGINT(19)">
                <constraints nullable="false"/>

    <changeSet author="liquibase (generated)" id="1391122037368-14">
        <addColumn tableName="BLC_CATEGORY_XREF">
            <column name="CATEGORY_XREF_ID" type="BIGINT(19)">
                <constraints nullable="false"/>

    <changeSet author="liquibase (generated)" id="1391122037368-32">
        <addColumn tableName="BLC_PRODUCT_OPTION_XREF">
            <column name="PRODUCT_OPTION_XREF_ID" type="BIGINT(19)">
                <constraints nullable="false"/>

    <changeSet author="liquibase (generated)" id="1391122037368-69">
        <createIndex indexName="PRIMARY" tableName="BLC_CATEGORY_PRODUCT_XREF" unique="true">
            <column name="CATEGORY_PRODUCT_ID"/>

    <changeSet author="liquibase (generated)" id="1391122037368-70">
        <createIndex indexName="PRIMARY" tableName="BLC_CATEGORY_XREF" unique="true">
            <column name="CATEGORY_XREF_ID"/>

    <changeSet author="liquibase (generated)" id="1391122037368-168">
        <dropPrimaryKey tableName="BLC_CATEGORY_PRODUCT_XREF"/>
    <changeSet author="liquibase (generated)" id="1391122037368-169">
        <addPrimaryKey columnNames="CATEGORY_PRODUCT_ID" constraintName="PRIMARY" tableName="BLC_CATEGORY_PRODUCT_XREF"/>

    <changeSet author="liquibase (generated)" id="1391122037368-170">
        <dropPrimaryKey tableName="BLC_CATEGORY_XREF"/>
    <changeSet author="liquibase (generated)" id="1391122037368-171">
        <addPrimaryKey columnNames="CATEGORY_XREF_ID" constraintName="PRIMARY" tableName="BLC_CATEGORY_XREF"/>

    <changeSet author="liquibase (generated)" id="1391122037368-44">
        <addPrimaryKey columnNames="PRODUCT_OPTION_XREF_ID" constraintName="PRIMARY" tableName="BLC_PRODUCT_OPTION_XREF"/>

    <changeSet author="liquibase (generated)" id="1391122037368-159">
        <modifyDataType columnName="DISPLAY_ORDER" newDataType="decimal(10,6)" tableName="BLC_CATEGORY_PRODUCT_XREF"/>
    <changeSet author="liquibase (generated)" id="1391122037368-160">
        <modifyDataType columnName="DISPLAY_ORDER" newDataType="decimal(10,6)" tableName="BLC_CATEGORY_XREF"/>

Data Migration for existing Payments

In the 3.1 codebase, we've completely refactored the way Payments are structured and persisted, so there are some data migrations if you intend to migrate from an earlier version.

You can view the new Order Payment model in the Database Model of the docs.

In general, we've made the model more flexible in terms of how Payments and Transactions are structured when integrating with Third Party Payment Gateways. There are a lot of intricasies involved as each Payment Gateway handles communication and transactions differently, so it was imperative to come up with a standardized and flexible solution that can best handle most solutions. You can read more about what all was done in the Payment Refactoctoring section of the docs.

Broadleaf 3.1 no longer uses the following tables:


Each gateway implentation in the 3.0 and earlier codebases persisted data in several different ways into the BLC_ORDER_PAYMENT_DETAILS, BLC_PAYINFO_ADDITIONAL_FIELDS, BLC_PAYMENT_ADDITIONAL_FIELDS depending on your
Payment Gateway Implementation. So, in order to do data migration for payments, some data analysis should be done in order to find the best mapping solution to the new tables.

The new tables include:


Please read the Payment Domain documentation to learn more about how Payment information should be stored in these new entities.

A good rule of thumb when migrating data for payments is that BLC_ORDER_PAYMENT_DETAILS -> BLC_ORDER_PAYMENT_TRANSACTION and both BLC_PAYINFO_ADDITIONAL_FIELDS and BLC_PAYMENT_ADDITIONAL_FIELDS are part of the response map associated with a particuar BLC_ORDER_PAYMENT_TRANSACTION in the BLC_TRANS_ADDITNL_FIELDS table. You may also wish to migrate BLC_PAYMENT_LOG entries as they are analagous to an entry in BLC_ORDER_PAYMENT_TRANSACTION

Here is a liquibase snippet relating to this DB change:

    <changeSet author="liquibase (generated)" id="1391184025689-5">
        <createTable tableName="BLC_ORDER_PAYMENT_TRANSACTION">
            <column name="PAYMENT_TRANSACTION_ID" type="BIGINT(19)">
                <constraints nullable="false"/>
            <column name="TRANSACTION_AMOUNT" type="DECIMAL(19, 2)"/>
            <column name="ARCHIVED" type="CHAR(1)"/>
            <column name="CUSTOMER_IP_ADDRESS" type="VARCHAR(255)"/>
            <column name="DATE_RECORDED" type="datetime"/>
            <column name="RAW_RESPONSE" type="LONGTEXT"/>
            <column name="SUCCESS" type="BIT(1)"/>
            <column name="TRANSACTION_TYPE" type="VARCHAR(255)"/>
            <column name="ORDER_PAYMENT" type="BIGINT(19)">
                <constraints nullable="false"/>
            <column name="PARENT_TRANSACTION" type="BIGINT(19)"/>

    <changeSet author="liquibase (generated)" id="1391184025689-12">
        <addColumn tableName="BLC_ORDER_PAYMENT">
            <column name="ARCHIVED" type="CHAR(1)"/>

    <changeSet author="liquibase (generated)" id="1391184025689-23">
        <addColumn tableName="BLC_ORDER_PAYMENT">
            <column name="GATEWAY_TYPE" type="VARCHAR(255)"/>

    <changeSet author="liquibase (generated)" id="1391184025689-28">
        <addColumn tableName="BLC_ORDER_PAYMENT">
            <column name="ORDER_PAYMENT_ID" type="BIGINT(19)">
                <constraints nullable="false"/>

    <changeSet author="liquibase (generated)" id="1391184025689-29">
        <addColumn tableName="BLC_PAYMENT_LOG">
            <column name="ORDER_PAYMENT_REF_NUM" type="VARCHAR(255)"/>

    <changeSet author="liquibase (generated)" id="1391184025689-42">
        <addPrimaryKey columnNames="PAYMENT_TRANSACTION_ID" constraintName="PRIMARY" tableName="BLC_ORDER_PAYMENT_TRANSACTION"/>

    <changeSet author="liquibase (generated)" id="1391184025689-52">
        <addForeignKeyConstraint baseColumnNames="PAYMENT_TRANSACTION_ID" baseTableName="BLC_TRANS_ADDITNL_FIELDS" constraintName="FK376DDE4B9E955B1D" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="PAYMENT_TRANSACTION_ID" referencedTableName="BLC_ORDER_PAYMENT_TRANSACTION"/>

    <changeSet author="liquibase (generated)" id="1391184025689-59">
        <addForeignKeyConstraint baseColumnNames="ORDER_PAYMENT" baseTableName="BLC_ORDER_PAYMENT_TRANSACTION" constraintName="FK86FDE7CE6A69DD9D" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="ORDER_PAYMENT_ID" referencedTableName="BLC_ORDER_PAYMENT"/>

    <changeSet author="liquibase (generated)" id="1391184025689-60">
        <addForeignKeyConstraint baseColumnNames="PARENT_TRANSACTION" baseTableName="BLC_ORDER_PAYMENT_TRANSACTION" constraintName="FK86FDE7CEE1B66C71" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="PAYMENT_TRANSACTION_ID" referencedTableName="BLC_ORDER_PAYMENT_TRANSACTION"/>

    <changeSet author="liquibase (generated)" id="1391184025689-67">
        <createIndex indexName="PAYMENTLOG_REFERENCE_INDEX" tableName="BLC_PAYMENT_LOG" unique="false">
            <column name="ORDER_PAYMENT_REF_NUM"/>

    <changeSet author="liquibase (generated)" id="1391184025689-70">
        <createIndex indexName="PRIMARY" tableName="BLC_ORDER_PAYMENT" unique="true">
            <column name="ORDER_PAYMENT_ID"/>

    <changeSet author="liquibase (generated)" id="1391184025689-171">
        <dropPrimaryKey tableName="BLC_ORDER_PAYMENT"/>
    <changeSet author="liquibase (generated)" id="1391184025689-172">
        <addPrimaryKey columnNames="ORDER_PAYMENT_ID" constraintName="PRIMARY" tableName="BLC_ORDER_PAYMENT"/>
    <changeSet author="liquibase (generated)" id="1391184025689-173">
        <dropIndex tableName="BLC_ORDER_PAYMENT"/>
    <changeSet author="liquibase (generated)" id="1391184025689-174">
        <createIndex indexName="ORDERPAYMENT_REFERENCE_INDEX" tableName="BLC_ORDER_PAYMENT">
            <column name="REFERENCE_NUMBER"/>