killbill-aplcache

Changes

.DS_Store 0(+0 -0)

account/pom.xml 2(+1 -1)

catalog/src/main/java/org/killbill/billing/catalog/dao/PlanPhaseKeysCollectionBinder.java 57(+0 -57)

invoice/pom.xml 2(+1 -1)

payment/src/main/java/org/killbill/billing/payment/dao/PaymentStateCollectionBinder.java 57(+0 -57)

payment/src/main/java/org/killbill/billing/payment/dao/StateCollectionBinder.java 58(+0 -58)

payment/src/main/java/org/killbill/billing/payment/dao/TransactionStatusCollectionBinder.java 57(+0 -57)

README.md 2(+1 -1)

tenant/pom.xml 2(+1 -1)

usage/pom.xml 2(+1 -1)

util/pom.xml 11(+10 -1)

util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoStringTemplate.java 145(+0 -145)

util/src/main/java/org/killbill/billing/util/tag/dao/UUIDCollectionBinder.java 54(+0 -54)

Details

.DS_Store 0(+0 -0)

diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/.DS_Store differ

account/pom.xml 2(+1 -1)

diff --git a/account/pom.xml b/account/pom.xml
index 8f1eaa0..5c2e8e8 100644
--- a/account/pom.xml
+++ b/account/pom.xml
@@ -79,7 +79,7 @@
         </dependency>
         <dependency>
             <groupId>org.antlr</groupId>
-            <artifactId>stringtemplate</artifactId>
+            <artifactId>ST4</artifactId>
             <scope>runtime</scope>
         </dependency>
         <dependency>
diff --git a/account/src/main/java/org/killbill/billing/account/dao/AccountEmailSqlDao.java b/account/src/main/java/org/killbill/billing/account/dao/AccountEmailSqlDao.java
index 80856ce..5108df8 100644
--- a/account/src/main/java/org/killbill/billing/account/dao/AccountEmailSqlDao.java
+++ b/account/src/main/java/org/killbill/billing/account/dao/AccountEmailSqlDao.java
@@ -20,7 +20,7 @@ import java.util.List;
 import java.util.UUID;
 
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 
@@ -30,17 +30,17 @@ import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.util.entity.dao.Audited;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface AccountEmailSqlDao extends EntitySqlDao<AccountEmailModelDao, AccountEmail> {
 
     @SqlUpdate
     @Audited(ChangeType.DELETE)
-    public void markEmailAsDeleted(@BindBean final AccountEmailModelDao accountEmail,
-                                   @BindBean final InternalCallContext context);
+    public void markEmailAsDeleted(@SmartBindBean final AccountEmailModelDao accountEmail,
+                                   @SmartBindBean final InternalCallContext context);
 
     @SqlQuery
     public List<AccountEmailModelDao> getEmailByAccountId(@Bind("accountId") final UUID accountId,
-                                                          @BindBean final InternalTenantContext context);
+                                                          @SmartBindBean final InternalTenantContext context);
 }
diff --git a/account/src/main/java/org/killbill/billing/account/dao/AccountSqlDao.java b/account/src/main/java/org/killbill/billing/account/dao/AccountSqlDao.java
index 77bea77..1506e64 100644
--- a/account/src/main/java/org/killbill/billing/account/dao/AccountSqlDao.java
+++ b/account/src/main/java/org/killbill/billing/account/dao/AccountSqlDao.java
@@ -27,44 +27,44 @@ import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.util.audit.ChangeType;
 import org.killbill.billing.util.entity.dao.Audited;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface AccountSqlDao extends EntitySqlDao<AccountModelDao, Account> {
 
     @SqlQuery
     public AccountModelDao getAccountByKey(@Bind("externalKey") final String key,
-                                           @BindBean final InternalTenantContext context);
+                                           @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     public UUID getIdFromKey(@Bind("externalKey") final String key,
-                             @BindBean final InternalTenantContext context);
+                             @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     public Integer getBCD(@Bind("id") String accountId,
-                          @BindBean final InternalTenantContext context);
+                          @SmartBindBean final InternalTenantContext context);
 
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
-    public void update(@BindBean final AccountModelDao account,
-                       @BindBean final InternalCallContext context);
+    public void update(@SmartBindBean final AccountModelDao account,
+                       @SmartBindBean final InternalCallContext context);
 
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
     public Object updatePaymentMethod(@Bind("id") String accountId,
                                       @Bind("paymentMethodId") String paymentMethodId,
-                                      @BindBean final InternalCallContext context);
+                                      @SmartBindBean final InternalCallContext context);
 
     @SqlQuery
     List<AccountModelDao> getAccountsByParentId(@Bind("parentAccountId") UUID parentAccountId,
-                                                @BindBean final InternalTenantContext context);
+                                                @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     public AccountModelDao luckySearch(@Bind("searchKey") final String searchKey,
-                                       @BindBean final InternalTenantContext context);
+                                       @SmartBindBean final InternalTenantContext context);
 
 }
diff --git a/account/src/main/resources/org/killbill/billing/account/dao/AccountEmailSqlDao.sql.stg b/account/src/main/resources/org/killbill/billing/account/dao/AccountEmailSqlDao.sql.stg
index fa5d62b..e54ad7d 100644
--- a/account/src/main/resources/org/killbill/billing/account/dao/AccountEmailSqlDao.sql.stg
+++ b/account/src/main/resources/org/killbill/billing/account/dao/AccountEmailSqlDao.sql.stg
@@ -1,4 +1,4 @@
-group AccountEmailSqlDao: EntitySqlDao;
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "account_emails"
 
diff --git a/account/src/main/resources/org/killbill/billing/account/dao/AccountSqlDao.sql.stg b/account/src/main/resources/org/killbill/billing/account/dao/AccountSqlDao.sql.stg
index 937b12f..c46855d 100644
--- a/account/src/main/resources/org/killbill/billing/account/dao/AccountSqlDao.sql.stg
+++ b/account/src/main/resources/org/killbill/billing/account/dao/AccountSqlDao.sql.stg
@@ -1,4 +1,4 @@
-group AccountSqlDao: EntitySqlDao;
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "accounts"
 
@@ -64,7 +64,7 @@ tableValues() ::= <<
 
 /** The accounts table doesn't have an account_record_id column (it's the record_id) **/
 accountRecordIdFieldWithComma(prefix) ::= ""
-accountRecordIdValueWithComma(prefix) ::= ""
+accountRecordIdValueWithComma() ::= ""
 
 update() ::= <<
 update accounts set
@@ -91,7 +91,7 @@ update accounts set
 , updated_date = :updatedDate
 , updated_by = :updatedBy
 where id = :id
-<AND_CHECK_TENANT()>
+<AND_CHECK_TENANT("")>
 ;
 >>
 
@@ -101,19 +101,19 @@ updatePaymentMethod() ::= <<
     SET payment_method_id = :paymentMethodId
     , updated_date = :updatedDate
     , updated_by = :updatedBy
-    WHERE id = :id <AND_CHECK_TENANT()>;
+    WHERE id = :id <AND_CHECK_TENANT("")>;
 >>
 
 getAccountByKey() ::= <<
-    select <allTableFields()>
+    select <allTableFields("")>
     from accounts
-    where external_key = :externalKey <AND_CHECK_TENANT()>;
+    where external_key = :externalKey <AND_CHECK_TENANT("")>;
 >>
 
 getBCD() ::= <<
     select billing_cycle_day_local
     from accounts
-    where id = :id <AND_CHECK_TENANT()>;
+    where id = :id <AND_CHECK_TENANT("")>;
 >>
 
 searchQuery(prefix) ::= <<
@@ -130,50 +130,50 @@ select
 <allTableFields("t.")>
 from <tableName()> t
 join (
-  select distinct <recordIdField()>
+  select distinct <recordIdField("")>
   from (
     (
-      select <recordIdField()>
+      select <recordIdField("")>
       from <tableName()>
-      where <idField()> = :searchKey
-      <andCheckSoftDeletionWithComma()>
-      <AND_CHECK_TENANT()>
+      where <idField("")> = :searchKey
+      <andCheckSoftDeletionWithComma("")>
+      <AND_CHECK_TENANT("")>
       limit 1
     )
     union all
     (
-      select <recordIdField()>
+      select <recordIdField("")>
       from <tableName()>
       where name = :searchKey
-      <andCheckSoftDeletionWithComma()>
-      <AND_CHECK_TENANT()>
+      <andCheckSoftDeletionWithComma("")>
+      <AND_CHECK_TENANT("")>
       limit 1
     )
     union all
     (
-      select <recordIdField()>
+      select <recordIdField("")>
       from <tableName()>
       where email = :searchKey
-      <andCheckSoftDeletionWithComma()>
-      <AND_CHECK_TENANT()>
+      <andCheckSoftDeletionWithComma("")>
+      <AND_CHECK_TENANT("")>
       limit 1
     )
     union all
     (
-      select <recordIdField()>
+      select <recordIdField("")>
       from <tableName()>
       where external_key = :searchKey
-      <andCheckSoftDeletionWithComma()>
-      <AND_CHECK_TENANT()>
+      <andCheckSoftDeletionWithComma("")>
+      <AND_CHECK_TENANT("")>
       limit 1
     )
     union all
     (
-      select <recordIdField()>
+      select <recordIdField("")>
       from <tableName()>
       where company_name = :searchKey
-      <andCheckSoftDeletionWithComma()>
-      <AND_CHECK_TENANT()>
+      <andCheckSoftDeletionWithComma("")>
+      <AND_CHECK_TENANT("")>
       limit 1
     )
   ) search_with_idx
@@ -185,14 +185,14 @@ limit 1
 getIdFromKey() ::= <<
     SELECT id
     FROM accounts
-    WHERE external_key = :externalKey <AND_CHECK_TENANT()>;
+    WHERE external_key = :externalKey <AND_CHECK_TENANT("")>;
 >>
 
 getAccountsByParentId() ::= <<
-    select <allTableFields()>
+    select <allTableFields("")>
     from accounts
     where parent_account_id = :parentAccountId
-    <AND_CHECK_TENANT()>
-    <defaultOrderBy()>
+    <AND_CHECK_TENANT("")>
+    <defaultOrderBy("")>
     ;
 >>
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
index 06e6817..2969715 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
@@ -435,7 +435,6 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
                 .isNotifiedForInvoices(false)
                 .externalKey(UUID.randomUUID().toString().substring(1, 8))
                 .currency(Currency.USD)
-                .paymentMethodId(UUID.randomUUID())
                 .timeZone(DateTimeZone.UTC);
         if (billingDay != null) {
             builder.billingCycleDayLocal(billingDay);
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPaymentWithControl.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPaymentWithControl.java
index f5b74e6..7879aad 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPaymentWithControl.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPaymentWithControl.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -39,6 +39,7 @@ import org.killbill.billing.control.plugin.api.PriorPaymentControlResult;
 import org.killbill.billing.osgi.api.OSGIServiceDescriptor;
 import org.killbill.billing.osgi.api.OSGIServiceRegistration;
 import org.killbill.billing.payment.api.Payment;
+import org.killbill.billing.payment.api.PaymentMethodPlugin;
 import org.killbill.billing.payment.api.PaymentOptions;
 import org.killbill.billing.payment.api.PluginProperty;
 import org.killbill.billing.payment.api.TransactionType;
@@ -108,6 +109,54 @@ public class TestPaymentWithControl extends TestIntegrationBase {
     }
 
     @Test(groups = "slow")
+    public void testAuthSuccessWithPaymentControlNullPaymentMethodId() throws Exception {
+        final AccountData accountData = getAccountData(1);
+        final Account account = accountUserApi.createAccount(accountData, callContext);
+
+        // Add non-default payment method
+        final PaymentMethodPlugin info = createPaymentMethodPlugin();
+        final UUID paymentMethodId = paymentApi.addPaymentMethod(account, UUID.randomUUID().toString(), BeatrixIntegrationModule.NON_OSGI_PLUGIN_NAME, false, info, PLUGIN_PROPERTIES, callContext);
+
+        testPaymentControlWithControl.setAdjustedPaymentMethodId(paymentMethodId);
+
+        busHandler.pushExpectedEvents(NextEvent.PAYMENT);
+        final Payment payment = paymentApi.createAuthorizationWithPaymentControl(account, null, null, BigDecimal.ONE, account.getCurrency(), null, null,
+                                                                                 properties, paymentOptions, callContext);
+        assertListenerStatus();
+
+        final Payment paymentWithAttempts = paymentApi.getPayment(payment.getId(), false, true, ImmutableList.<PluginProperty>of(), callContext);
+        Assert.assertEquals(paymentWithAttempts.getPaymentMethodId(), paymentMethodId);
+        Assert.assertEquals(paymentWithAttempts.getPaymentAttempts().size(), 1);
+        Assert.assertEquals(paymentWithAttempts.getPaymentAttempts().get(0).getPaymentMethodId(), paymentMethodId);
+        Assert.assertEquals(paymentWithAttempts.getPaymentAttempts().get(0).getStateName(), "SUCCESS");
+    }
+
+    @Test(groups = "slow")
+    public void testAuthFailureWithPaymentControlNullPaymentMethodId() throws Exception {
+        final AccountData accountData = getAccountData(1);
+        final Account account = accountUserApi.createAccount(accountData, callContext);
+
+        // Add non-default payment method
+        final PaymentMethodPlugin info = createPaymentMethodPlugin();
+        final UUID paymentMethodId = paymentApi.addPaymentMethod(account, UUID.randomUUID().toString(), BeatrixIntegrationModule.NON_OSGI_PLUGIN_NAME, false, info, PLUGIN_PROPERTIES, callContext);
+
+        testPaymentControlWithControl.setAdjustedPaymentMethodId(paymentMethodId);
+
+        paymentPlugin.makeNextPaymentFailWithError();
+
+        busHandler.pushExpectedEvents(NextEvent.PAYMENT_ERROR);
+        final Payment payment = paymentApi.createAuthorizationWithPaymentControl(account, null, null, BigDecimal.ONE, account.getCurrency(), null, null,
+                                                                                 properties, paymentOptions, callContext);
+        assertListenerStatus();
+
+        final Payment paymentWithAttempts = paymentApi.getPayment(payment.getId(), false, true, ImmutableList.<PluginProperty>of(), callContext);
+        Assert.assertEquals(paymentWithAttempts.getPaymentMethodId(), paymentMethodId);
+        Assert.assertEquals(paymentWithAttempts.getPaymentAttempts().size(), 1);
+        Assert.assertEquals(paymentWithAttempts.getPaymentAttempts().get(0).getPaymentMethodId(), paymentMethodId);
+        Assert.assertEquals(paymentWithAttempts.getPaymentAttempts().get(0).getStateName(), "ABORTED");
+    }
+
+    @Test(groups = "slow")
     public void testAuthCaptureWithPaymentControl() throws Exception {
 
         final AccountData accountData = getAccountData(1);
@@ -184,6 +233,8 @@ public class TestPaymentWithControl extends TestIntegrationBase {
 
         private final Map<String, Integer> calls;
 
+        private UUID adjustedPaymentMethodId = null;
+
         public TestPaymentControlPluginApi() {
             calls = new HashMap<String, Integer>();
         }
@@ -194,6 +245,11 @@ public class TestPaymentWithControl extends TestIntegrationBase {
 
         public void reset() {
             calls.clear();
+            adjustedPaymentMethodId = null;
+        }
+
+        public void setAdjustedPaymentMethodId(final UUID adjustedPaymentMethodId) {
+            this.adjustedPaymentMethodId = adjustedPaymentMethodId;
         }
 
         @Override
@@ -213,7 +269,7 @@ public class TestPaymentWithControl extends TestIntegrationBase {
                 }
                 @Override
                 public UUID getAdjustedPaymentMethodId() {
-                    return null;
+                    return adjustedPaymentMethodId;
                 }
                 @Override
                 public Iterable<PluginProperty> getAdjustedPluginProperties() {
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePhaseDefinitionSqlDao.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePhaseDefinitionSqlDao.java
index 19164aa..ea1c2d1 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePhaseDefinitionSqlDao.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePhaseDefinitionSqlDao.java
@@ -22,7 +22,7 @@ import java.util.List;
 
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
@@ -30,7 +30,7 @@ import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
 import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface CatalogOverridePhaseDefinitionSqlDao extends Transactional<CatalogOverridePhaseDefinitionSqlDao>, CloseMe {
 
     @SqlUpdate
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePlanDefinitionSqlDao.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePlanDefinitionSqlDao.java
index 8570039..47ac60c 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePlanDefinitionSqlDao.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePlanDefinitionSqlDao.java
@@ -19,7 +19,7 @@ package org.killbill.billing.catalog.dao;
 
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
@@ -27,7 +27,7 @@ import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
 import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface CatalogOverridePlanDefinitionSqlDao extends Transactional<CatalogOverridePlanDefinitionSqlDao>, CloseMe {
 
     @SqlUpdate
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePlanPhaseSqlDao.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePlanPhaseSqlDao.java
index 3993ddf..ae7d936 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePlanPhaseSqlDao.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePlanPhaseSqlDao.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -21,15 +21,16 @@ import java.util.Collection;
 
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
 import org.killbill.commons.jdbi.binder.SmartBindBean;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
 import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
+import org.skife.jdbi.v2.unstable.BindIn;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface CatalogOverridePlanPhaseSqlDao extends Transactional<CatalogOverridePlanPhaseSqlDao>, CloseMe {
 
     @SqlUpdate
@@ -41,7 +42,7 @@ public interface CatalogOverridePlanPhaseSqlDao extends Transactional<CatalogOve
                                                           @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
-    public Long getTargetPlanDefinition(@PlanPhaseKeysCollectionBinder final Collection<String> concatPhaseNumAndPhaseDefRecordId,
+    public Long getTargetPlanDefinition(@BindIn("keys") final Collection<String> concatPhaseNumAndPhaseDefRecordId,
                                         @Bind("targetCount") final Integer targetCount,
                                         @SmartBindBean final InternalTenantContext context);
 
diff --git a/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverridePhaseDefinitionSqlDao.sql.stg b/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverridePhaseDefinitionSqlDao.sql.stg
index e51ae47..7e987c9 100644
--- a/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverridePhaseDefinitionSqlDao.sql.stg
+++ b/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverridePhaseDefinitionSqlDao.sql.stg
@@ -1,5 +1,3 @@
-group CatalogOverridePhaseDefinitionSqlDao;
-
 tableName() ::= "catalog_override_phase_definition"
 
 
@@ -39,7 +37,7 @@ allTableValues() ::= <<
 
 create() ::= <<
 insert into <tableName()> (
-<tableFields()>
+<tableFields("")>
 )
 values (
 <tableValues()>
@@ -48,7 +46,7 @@ values (
 >>
 
 getByRecordId() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 from <tableName()>
 where record_id = :recordId
 and tenant_record_id = :tenantRecordId
@@ -56,7 +54,7 @@ and tenant_record_id = :tenantRecordId
 >>
 
 getByAttributes() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 from <tableName()>
 where parent_phase_name = :parentPhaseName
 and currency = :currency
diff --git a/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverridePlanDefinitionSqlDao.sql.stg b/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverridePlanDefinitionSqlDao.sql.stg
index 3024bc0..b9ae158 100644
--- a/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverridePlanDefinitionSqlDao.sql.stg
+++ b/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverridePlanDefinitionSqlDao.sql.stg
@@ -1,5 +1,3 @@
-group CatalogOverridePlanDefinitionSqlDao;
-
 tableName() ::= "catalog_override_plan_definition"
 
 tableFields(prefix) ::= <<
@@ -34,7 +32,7 @@ allTableValues() ::= <<
 
 create() ::= <<
 insert into <tableName()> (
-<tableFields()>
+<tableFields("")>
 )
 values (
 <tableValues()>
@@ -43,7 +41,7 @@ values (
 >>
 
 getByRecordId() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 from <tableName()>
 where record_id = :recordId
 and tenant_record_id = :tenantRecordId
diff --git a/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverridePlanPhaseSqlDao.sql.stg b/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverridePlanPhaseSqlDao.sql.stg
index be35a86..ba61278 100644
--- a/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverridePlanPhaseSqlDao.sql.stg
+++ b/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverridePlanPhaseSqlDao.sql.stg
@@ -1,6 +1,3 @@
-group CatalogOverridePlanPhaseSqlDao;
-
-
 tableName() ::= "catalog_override_plan_phase"
 
 
@@ -36,7 +33,7 @@ allTableValues() ::= <<
 
 create() ::= <<
 insert into <tableName()> (
-<tableFields()>
+<tableFields("")>
 )
 values (
 <tableValues()>
@@ -45,7 +42,7 @@ values (
 >>
 
 getByRecordId() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 from
 <tableName()>
 where record_id = :recordId
@@ -62,7 +59,7 @@ from (select
       from
       <tableName()>
       where
-      concat_ws(',', phase_number, phase_def_record_id) in (<keys: {key | :key_<i0>}; separator="," >)
+      concat_ws(',', phase_number, phase_def_record_id) in (<keys>)
       and tenant_record_id = :tenantRecordId
       group by target_plan_def_record_id) tmp
 where
diff --git a/entitlement/pom.xml b/entitlement/pom.xml
index 4373590..06b81a7 100644
--- a/entitlement/pom.xml
+++ b/entitlement/pom.xml
@@ -75,7 +75,7 @@
         </dependency>
         <dependency>
             <groupId>org.antlr</groupId>
-            <artifactId>stringtemplate</artifactId>
+            <artifactId>ST4</artifactId>
             <scope>runtime</scope>
         </dependency>
         <dependency>
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/dao/BlockingStateSqlDao.java b/entitlement/src/main/java/org/killbill/billing/entitlement/dao/BlockingStateSqlDao.java
index 95024c3..344a645 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/dao/BlockingStateSqlDao.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/dao/BlockingStateSqlDao.java
@@ -28,33 +28,33 @@ import org.killbill.billing.entitlement.api.BlockingState;
 import org.killbill.billing.util.audit.ChangeType;
 import org.killbill.billing.util.entity.dao.Audited;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface BlockingStateSqlDao extends EntitySqlDao<BlockingStateModelDao, BlockingState> {
 
     @SqlQuery
     public abstract BlockingStateModelDao getBlockingStateForService(@Bind("blockableId") UUID blockableId,
                                                                      @Bind("service") String serviceName,
                                                                      @Bind("effectiveDate") Date effectiveDate,
-                                                                     @BindBean final InternalTenantContext context);
+                                                                     @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     public abstract List<BlockingStateModelDao> getBlockingState(@Bind("blockableId") UUID blockableId,
                                                                  @Bind("effectiveDate") Date effectiveDate,
-                                                                 @BindBean final InternalTenantContext context);
+                                                                 @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     public abstract List<BlockingStateModelDao> getBlockingHistoryForService(@Bind("blockableId") UUID blockableId,
                                                                              @Bind("service") String serviceName,
-                                                                             @BindBean final InternalTenantContext context);
+                                                                             @SmartBindBean final InternalTenantContext context);
 
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
     public void unactiveEvent(@Bind("id") String id,
-                              @BindBean final InternalCallContext context);
+                              @SmartBindBean final InternalCallContext context);
 }
diff --git a/entitlement/src/main/resources/org/killbill/billing/entitlement/dao/BlockingStateSqlDao.sql.stg b/entitlement/src/main/resources/org/killbill/billing/entitlement/dao/BlockingStateSqlDao.sql.stg
index feeee40..9d78819 100644
--- a/entitlement/src/main/resources/org/killbill/billing/entitlement/dao/BlockingStateSqlDao.sql.stg
+++ b/entitlement/src/main/resources/org/killbill/billing/entitlement/dao/BlockingStateSqlDao.sql.stg
@@ -1,5 +1,4 @@
-group BlockingStateSqlDao: EntitySqlDao;
-
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "blocking_states"
 
@@ -45,14 +44,14 @@ tableValues() ::= <<
 
 getBlockingStateForService() ::= <<
 select
-<allTableFields()>
+<allTableFields("")>
 from
 <tableName()>
 where blockable_id = :blockableId
 and service = :service
 and effective_date \<= :effectiveDate
 and is_active
-<AND_CHECK_TENANT()>
+<AND_CHECK_TENANT("")>
 -- We want the current state, hence the order desc and limit 1
 order by effective_date desc, record_id desc
 limit 1
@@ -71,7 +70,7 @@ getBlockingState() ::= <<
          where blockable_id = :blockableId
          and effective_date \<= :effectiveDate
          and is_active
-         <AND_CHECK_TENANT()>
+         <AND_CHECK_TENANT("")>
          group by service
  ) tmp
  on t.record_id = tmp.record_id
@@ -81,14 +80,14 @@ getBlockingState() ::= <<
 
 getBlockingHistoryForService() ::= <<
 select
-<allTableFields()>
+<allTableFields("")>
 from
 <tableName()>
 where blockable_id = :blockableId
 and service = :service
 and is_active
-<AND_CHECK_TENANT()>
-<defaultOrderBy()>
+<AND_CHECK_TENANT("")>
+<defaultOrderBy("")>
 ;
 >>
 
@@ -97,6 +96,6 @@ update
 <tableName()>
 set is_active = false
 where id = :id
-<AND_CHECK_TENANT()>
+<AND_CHECK_TENANT("")>
 ;
 >>

invoice/pom.xml 2(+1 -1)

diff --git a/invoice/pom.xml b/invoice/pom.xml
index defab3b..85a0773 100644
--- a/invoice/pom.xml
+++ b/invoice/pom.xml
@@ -80,7 +80,7 @@
         </dependency>
         <dependency>
             <groupId>org.antlr</groupId>
-            <artifactId>stringtemplate</artifactId>
+            <artifactId>ST4</artifactId>
             <scope>runtime</scope>
         </dependency>
         <dependency>
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/calculator/InvoiceCalculatorUtils.java b/invoice/src/main/java/org/killbill/billing/invoice/calculator/InvoiceCalculatorUtils.java
index c7af0ef..88a88c3 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/calculator/InvoiceCalculatorUtils.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/calculator/InvoiceCalculatorUtils.java
@@ -69,13 +69,10 @@ public abstract class InvoiceCalculatorUtils {
                InvoiceItemType.RECURRING.equals(invoiceItem.getInvoiceItemType());
     }
 
-    public static BigDecimal computeInvoiceBalance(final Currency currency,
-                                                   @Nullable final Iterable<InvoiceItem> invoiceItems,
-                                                   @Nullable final Iterable<InvoicePayment> invoicePayments,
-                                                   boolean writtenOffOrMigrated) {
-        if (writtenOffOrMigrated) {
-            return BigDecimal.ZERO;
-        }
+    public static BigDecimal computeRawInvoiceBalance(final Currency currency,
+                                                      @Nullable final Iterable<InvoiceItem> invoiceItems,
+                                                      @Nullable final Iterable<InvoicePayment> invoicePayments) {
+
 
         final BigDecimal amountPaid = computeInvoiceAmountPaid(currency, invoicePayments)
                 .add(computeInvoiceAmountRefunded(currency, invoicePayments));
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/CBADao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/CBADao.java
index 48de156..162c204 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/CBADao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/CBADao.java
@@ -64,7 +64,7 @@ public class CBADao {
         if (balance.compareTo(BigDecimal.ZERO) < 0) {
             // Current balance is negative, we need to generate a credit (positive CBA amount)
             return buildCBAItem(invoice, balance, context);
-        } else if (balance.compareTo(BigDecimal.ZERO) > 0 && invoice.getStatus() == InvoiceStatus.COMMITTED) {
+        } else if (balance.compareTo(BigDecimal.ZERO) > 0 && invoice.getStatus() == InvoiceStatus.COMMITTED && !invoice.isWrittenOff()) {
             // Current balance is positive and the invoice is COMMITTED, we need to use some of the existing if available (negative CBA amount)
             // PERF: in some codepaths, the CBA maybe have already been computed
             BigDecimal accountCBA = accountCBAOrNull;
@@ -86,7 +86,7 @@ public class CBADao {
     private BigDecimal getInvoiceBalance(final InvoiceModelDao invoice) {
 
         final InvoiceModelDao parentInvoice = invoice.getParentInvoice();
-        if ((parentInvoice != null) && (InvoiceModelDaoHelper.getBalance(parentInvoice).compareTo(BigDecimal.ZERO) == 0)) {
+        if ((parentInvoice != null) && (InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(parentInvoice).compareTo(BigDecimal.ZERO) == 0)) {
             final Iterable<InvoiceItemModelDao> items = Iterables.filter(parentInvoice.getInvoiceItems(), new Predicate<InvoiceItemModelDao>() {
                 @Override
                 public boolean apply(@Nullable final InvoiceItemModelDao input) {
@@ -105,7 +105,7 @@ public class CBADao {
 
         }
 
-        return InvoiceModelDaoHelper.getBalance(invoice);
+        return InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(invoice);
     }
 
     // We let the code below rehydrate the invoice before we can add the CBA item
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
index 0afa55c..bd35813 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
@@ -439,7 +439,21 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                 BigDecimal accountBalance = BigDecimal.ZERO;
                 final List<InvoiceModelDao> invoices = invoiceDaoHelper.getAllInvoicesByAccountFromTransaction(invoicesTags, entitySqlDaoWrapperFactory, context);
                 for (final InvoiceModelDao cur : invoices) {
-                    accountBalance = accountBalance.add((new DefaultInvoice(cur)).getBalance());
+
+                    // Skip DRAFT invoices
+                    if (cur.getStatus().equals(InvoiceStatus.DRAFT)) {
+                        continue;
+                    }
+
+                    final boolean hasZeroParentBalance =
+                            cur.getParentInvoice() != null &&
+                            (cur.getParentInvoice().isWrittenOff() ||
+                             cur.getParentInvoice().getStatus() == InvoiceStatus.DRAFT ||
+                             InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(cur.getParentInvoice()).compareTo(BigDecimal.ZERO) == 0);
+
+
+                    // invoices that are WRITTEN_OFF or paid children invoices are excluded from balance computation but the cba summation needs to be included
+                    accountBalance = cur.isWrittenOff() || hasZeroParentBalance ? BigDecimal.ZERO : accountBalance.add(InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(cur));
                     cba = cba.add(InvoiceModelDaoHelper.getCBAAmount(cur));
                 }
                 return accountBalance.subtract(cba);
@@ -865,7 +879,10 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
                 // Retrieve the invoice and make sure it belongs to the right account
                 final InvoiceModelDao invoice = transactional.getById(invoiceId.toString(), context);
-                if (invoice == null || !invoice.getAccountId().equals(accountId)) {
+                if (invoice == null ||
+                    !invoice.getAccountId().equals(accountId) ||
+                    invoice.isMigrated() ||
+                    invoice.getStatus() == InvoiceStatus.DRAFT) {
                     throw new InvoiceApiException(ErrorCode.INVOICE_NOT_FOUND, invoiceId);
                 }
 
@@ -884,7 +901,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
                 // Verify the final invoice balance is not negative
                 invoiceDaoHelper.populateChildren(invoice, invoicesTags, entitySqlDaoWrapperFactory, context);
-                if (InvoiceModelDaoHelper.getBalance(invoice).compareTo(BigDecimal.ZERO) < 0) {
+                if (InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(invoice).compareTo(BigDecimal.ZERO) < 0) {
                     throw new InvoiceApiException(ErrorCode.INVOICE_WOULD_BE_NEGATIVE);
                 }
 
@@ -1089,9 +1106,10 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
     private void notifyBusOfInvoiceCreation(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final InvoiceModelDao invoice, final InternalCallContext context) {
         try {
-            final BigDecimal balance = InvoiceModelDaoHelper.getBalance(invoice);
+            // This is called for a new COMMITTED invoice (which cannot be writtenOff as it does not exist yet, so rawBalance == balance)
+            final BigDecimal rawBalance = InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(invoice);
             final DefaultInvoiceCreationEvent event = new DefaultInvoiceCreationEvent(invoice.getId(), invoice.getAccountId(),
-                                                                                                            balance, invoice.getCurrency(),
+                                                                                      rawBalance, invoice.getCurrency(),
                                                                                                             context.getAccountRecordId(), context.getTenantRecordId(),
                                                                                                             context.getUserToken());
             eventBus.postFromTransaction(event, entitySqlDaoWrapperFactory.getHandle().getConnection());
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceDaoHelper.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceDaoHelper.java
index cfd92a1..ecebd92 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceDaoHelper.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceDaoHelper.java
@@ -175,9 +175,10 @@ public class InvoiceDaoHelper {
             @Override
             public boolean apply(final InvoiceModelDao in) {
                 final InvoiceModelDao invoice = (in.getParentInvoice() == null) ? in : in.getParentInvoice();
-                final BigDecimal balance = InvoiceModelDaoHelper.getBalance(invoice);
+                final BigDecimal balance = InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(invoice);
                 log.debug("Computed balance={} for invoice={}", balance, in);
-                return InvoiceStatus.COMMITTED.equals(in.getStatus()) && (balance.compareTo(BigDecimal.ZERO) >= 1) &&
+                return InvoiceStatus.COMMITTED.equals(in.getStatus()) &&
+                       (balance.compareTo(BigDecimal.ZERO) >= 1 && !in.isWrittenOff()) &&
                        (upToDate == null || in.getTargetDate() == null || !in.getTargetDate().isAfter(upToDate));
             }
         });
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.java
index 8c7ded7..7a864d9 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.java
@@ -27,38 +27,38 @@ import org.killbill.billing.invoice.api.InvoiceItem;
 import org.killbill.billing.util.audit.ChangeType;
 import org.killbill.billing.util.entity.dao.Audited;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface InvoiceItemSqlDao extends EntitySqlDao<InvoiceItemModelDao, InvoiceItem> {
 
     @SqlQuery
     List<InvoiceItemModelDao> getInvoiceItemsByInvoice(@Bind("invoiceId") final String invoiceId,
-                                                       @BindBean final InternalTenantContext context);
+                                                       @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     List<InvoiceItemModelDao> getInvoiceItemsBySubscription(@Bind("subscriptionId") final String subscriptionId,
-                                                            @BindBean final InternalTenantContext context);
+                                                            @SmartBindBean final InternalTenantContext context);
 
 
     @SqlQuery
     List<InvoiceItemModelDao> getAdjustedOrRepairedInvoiceItemsByLinkedId(@Bind("linkedItemId") final String linkedItemId,
-                                                            @BindBean final InternalTenantContext context);
+                                                            @SmartBindBean final InternalTenantContext context);
 
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
     void updateAmount(@Bind("id") String invoiceItemId,
                       @Bind("amount")BigDecimal amount,
-                      @BindBean final InternalCallContext context);
+                      @SmartBindBean final InternalCallContext context);
 
     @SqlQuery
     List<InvoiceItemModelDao> getInvoiceItemsByParentInvoice(@Bind("parentInvoiceId") final String parentInvoiceId,
-                                                             @BindBean final InternalTenantContext context);
+                                                             @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
-    BigDecimal getAccountCBA(@BindBean final InternalTenantContext context);
+    BigDecimal getAccountCBA(@SmartBindBean final InternalTenantContext context);
 }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceModelDaoHelper.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceModelDaoHelper.java
index a240128..877e741 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceModelDaoHelper.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceModelDaoHelper.java
@@ -18,8 +18,6 @@ package org.killbill.billing.invoice.dao;
 
 import java.math.BigDecimal;
 
-import javax.annotation.Nullable;
-
 import org.killbill.billing.invoice.api.InvoiceItem;
 import org.killbill.billing.invoice.api.InvoicePayment;
 import org.killbill.billing.invoice.calculator.InvoiceCalculatorUtils;
@@ -33,22 +31,25 @@ public class InvoiceModelDaoHelper {
 
     private InvoiceModelDaoHelper() {}
 
-    public static BigDecimal getBalance(final InvoiceModelDao invoiceModelDao) {
-        return InvoiceCalculatorUtils.computeInvoiceBalance(invoiceModelDao.getCurrency(),
-                                                            Iterables.transform(invoiceModelDao.getInvoiceItems(), new Function<InvoiceItemModelDao, InvoiceItem>() {
-                                                                @Override
-                                                                public InvoiceItem apply(final InvoiceItemModelDao input) {
-                                                                    return InvoiceItemFactory.fromModelDao(input);
-                                                                }
-                                                            }),
-                                                            Iterables.transform(invoiceModelDao.getInvoicePayments(), new Function<InvoicePaymentModelDao, InvoicePayment>() {
-                                                                @Nullable
-                                                                @Override
-                                                                public InvoicePayment apply(final InvoicePaymentModelDao input) {
-                                                                    return new DefaultInvoicePayment(input);
-                                                                }
-                                                            }),
-                                                            invoiceModelDao.isMigrated() || invoiceModelDao.isWrittenOff());
+    public static BigDecimal getRawBalanceForRegularInvoice(final InvoiceModelDao invoiceModelDao) {
+
+        if (invoiceModelDao.isMigrated()) {
+            return BigDecimal.ZERO;
+        }
+
+        return InvoiceCalculatorUtils.computeRawInvoiceBalance(invoiceModelDao.getCurrency(),
+                                                               Iterables.transform(invoiceModelDao.getInvoiceItems(), new Function<InvoiceItemModelDao, InvoiceItem>() {
+                                                                   @Override
+                                                                   public InvoiceItem apply(final InvoiceItemModelDao input) {
+                                                                       return InvoiceItemFactory.fromModelDao(input);
+                                                                   }
+                                                               }),
+                                                               Iterables.transform(invoiceModelDao.getInvoicePayments(), new Function<InvoicePaymentModelDao, InvoicePayment>() {
+                                                                   @Override
+                                                                   public InvoicePayment apply(final InvoicePaymentModelDao input) {
+                                                                       return new DefaultInvoicePayment(input);
+                                                                   }
+                                                               }));
     }
 
     public static BigDecimal getCBAAmount(final InvoiceModelDao invoiceModelDao) {
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceParentChildrenSqlDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceParentChildrenSqlDao.java
index 2973f53..dbaa0a9 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceParentChildrenSqlDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceParentChildrenSqlDao.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -19,27 +19,26 @@ package org.killbill.billing.invoice.dao;
 
 import java.util.Collection;
 import java.util.List;
-import java.util.UUID;
 
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.invoice.api.InvoiceParentChild;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
-import org.killbill.billing.util.tag.dao.UUIDCollectionBinder;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.unstable.BindIn;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface InvoiceParentChildrenSqlDao extends EntitySqlDao<InvoiceParentChildModelDao, InvoiceParentChild> {
 
     @SqlQuery
     List<InvoiceParentChildModelDao> getChildInvoicesByParentInvoiceId(@Bind("parentInvoiceId") final String parentInvoiceId,
-                                                                       @BindBean final InternalTenantContext context);
+                                                                       @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
-    List<InvoiceParentChildModelDao> getParentChildMappingsByChildInvoiceIds(@UUIDCollectionBinder final Collection<String> childInvoiceIds,
-                                                                             @BindBean final InternalTenantContext context);
+    List<InvoiceParentChildModelDao> getParentChildMappingsByChildInvoiceIds(@BindIn("ids") final Collection<String> childInvoiceIds,
+                                                                             @SmartBindBean final InternalTenantContext context);
 
 }
 
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoicePaymentSqlDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoicePaymentSqlDao.java
index d763bd1..994eb58 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoicePaymentSqlDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoicePaymentSqlDao.java
@@ -27,47 +27,47 @@ import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.invoice.api.InvoicePayment;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface InvoicePaymentSqlDao extends EntitySqlDao<InvoicePaymentModelDao, InvoicePayment> {
 
 
     @SqlQuery
     public List<InvoicePaymentModelDao> getByPaymentId(@Bind("paymentId") final String paymentId,
-                                                       @BindBean final InternalTenantContext context);
+                                                       @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     public List<InvoicePaymentModelDao> getAllPaymentsForInvoiceIncludedInit(@Bind("invoiceId") final String invoiceId,
-                                                              @BindBean final InternalTenantContext context);
+                                                              @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     List<InvoicePaymentModelDao> getInvoicePayments(@Bind("paymentId") final String paymentId,
-                                                    @BindBean final InternalTenantContext context);
+                                                    @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     InvoicePaymentModelDao getPaymentForCookieId(@Bind("paymentCookieId") final String paymentCookieId,
-                                                 @BindBean final InternalTenantContext context);
+                                                 @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     BigDecimal getRemainingAmountPaid(@Bind("invoicePaymentId") final String invoicePaymentId,
-                                      @BindBean final InternalTenantContext context);
+                                      @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     UUID getAccountIdFromInvoicePaymentId(@Bind("invoicePaymentId") final String invoicePaymentId,
-                                          @BindBean final InternalTenantContext context);
+                                          @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     List<InvoicePaymentModelDao> getChargeBacksByAccountId(@Bind("accountId") final String accountId,
-                                                           @BindBean final InternalTenantContext context);
+                                                           @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     List<InvoicePaymentModelDao> getChargebacksByPaymentId(@Bind("paymentId") final String paymentId,
-                                                           @BindBean final InternalTenantContext context);
+                                                           @SmartBindBean final InternalTenantContext context);
 
     @SqlUpdate
     void updateAttempt(@Bind("recordId") Long recordId,
@@ -79,5 +79,5 @@ public interface InvoicePaymentSqlDao extends EntitySqlDao<InvoicePaymentModelDa
                        @Bind("paymentCookieId") final String paymentCookieId,
                        @Bind("linkedInvoicePaymentId") final String linkedInvoicePaymentId,
                        @Bind("success") final boolean success,
-                       @BindBean final InternalTenantContext context);
+                       @SmartBindBean final InternalTenantContext context);
 }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceSqlDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceSqlDao.java
index 9ed8f28..6d405b0 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceSqlDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceSqlDao.java
@@ -28,36 +28,36 @@ import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.util.audit.ChangeType;
 import org.killbill.billing.util.entity.dao.Audited;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
-import org.killbill.billing.util.tag.dao.UUIDCollectionBinder;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.unstable.BindIn;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface InvoiceSqlDao extends EntitySqlDao<InvoiceModelDao, Invoice> {
 
     @SqlQuery
     List<InvoiceModelDao> getInvoicesBySubscription(@Bind("subscriptionId") final String subscriptionId,
-                                                    @BindBean final InternalTenantContext context);
+                                                    @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     UUID getInvoiceIdByPaymentId(@Bind("paymentId") final String paymentId,
-                                 @BindBean final InternalTenantContext context);
+                                 @SmartBindBean final InternalTenantContext context);
 
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
     void updateStatus(@Bind("id") String invoiceId,
                       @Bind("status") String status,
-                      @BindBean final InternalCallContext context);
+                      @SmartBindBean final InternalCallContext context);
 
     @SqlQuery
     InvoiceModelDao getParentDraftInvoice(@Bind("accountId") final String parentAccountId,
-                                          @BindBean final InternalTenantContext context);
+                                          @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
-    List<InvoiceModelDao> getByIds(@UUIDCollectionBinder final Collection<String> invoiceIds,
-                                   @BindBean final InternalTenantContext context);
+    List<InvoiceModelDao> getByIds(@BindIn("ids") final Collection<String> invoiceIds,
+                                   @SmartBindBean final InternalTenantContext context);
 }
 
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
index a300bf1..d8fc889 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
@@ -861,7 +861,7 @@ public class InvoiceDispatcher {
 
         if (parentInvoiceModelDao == null) {
             throw new InvoiceApiException(ErrorCode.INVOICE_MISSING_PARENT_INVOICE, childInvoiceModelDao.getId());
-        } else if (InvoiceModelDaoHelper.getBalance(parentInvoiceModelDao).compareTo(BigDecimal.ZERO) == 0) {
+        } else if (InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(parentInvoiceModelDao).compareTo(BigDecimal.ZERO) == 0) {
             // ignore item adjustments for paid invoices.
             return;
         }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/model/DefaultInvoice.java b/invoice/src/main/java/org/killbill/billing/invoice/model/DefaultInvoice.java
index c041450..0541c07 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/model/DefaultInvoice.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/model/DefaultInvoice.java
@@ -251,12 +251,17 @@ public class DefaultInvoice extends EntityBase implements Invoice, Cloneable {
 
     @Override
     public BigDecimal getBalance() {
-        return getStatus().equals(InvoiceStatus.DRAFT) || hasZeroParentBalance() ?
-               BigDecimal.ZERO :
-               InvoiceCalculatorUtils.computeInvoiceBalance(currency, invoiceItems, payments, isWrittenOff() || isMigrationInvoice());
+        if (isWrittenOff() ||
+            isMigrationInvoice() ||
+            getStatus() == InvoiceStatus.DRAFT ||
+            hasZeroParentBalance()) {
+            return BigDecimal.ZERO;
+        } else {
+            return InvoiceCalculatorUtils.computeRawInvoiceBalance(currency, invoiceItems, payments);
+        }
     }
 
-    private boolean hasZeroParentBalance() {
+    public boolean hasZeroParentBalance() {
         return (parentInvoice != null) && (parentInvoice.getBalance().compareTo(BigDecimal.ZERO) == 0);
     }
 
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalUsageInArrear.java b/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalUsageInArrear.java
index c79db5c..26f5714 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalUsageInArrear.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalUsageInArrear.java
@@ -144,7 +144,9 @@ public class ContiguousIntervalUsageInArrear {
             numberOfPeriod++;
             nextBillCycleDate = bid.getFutureBillingDateFor(numberOfPeriod);
         }
-        if (closedInterval && endDate.isAfter(transitionTimes.get(transitionTimes.size() - 1))) {
+        if (closedInterval &&
+            transitionTimes.size() > 0 &&
+            endDate.isAfter(transitionTimes.get(transitionTimes.size() - 1))) {
             transitionTimes.add(endDate);
         }
         isBuilt.set(true);
diff --git a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.sql.stg b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.sql.stg
index c99d95c..c7596b4 100644
--- a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.sql.stg
+++ b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.sql.stg
@@ -1,4 +1,4 @@
-group InvoiceItemSqlDao: EntitySqlDao;
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "invoice_items"
 
@@ -46,27 +46,27 @@ tableValues() ::= <<
 
 
 getInvoiceItemsByInvoice() ::= <<
-  SELECT <allTableFields()>
+  SELECT <allTableFields("")>
   FROM <tableName()>
   WHERE invoice_id = :invoiceId
-  <AND_CHECK_TENANT()>
+  <AND_CHECK_TENANT("")>
   ;
 >>
 
 getInvoiceItemsBySubscription() ::= <<
-  SELECT <allTableFields()>
+  SELECT <allTableFields("")>
   FROM <tableName()>
   WHERE subscription_id = :subscriptionId
-  <AND_CHECK_TENANT()>
+  <AND_CHECK_TENANT("")>
   ;
 >>
 
 getAdjustedOrRepairedInvoiceItemsByLinkedId() ::= <<
-  SELECT <allTableFields()>
+  SELECT <allTableFields("")>
   FROM <tableName()>
   WHERE linked_item_id = :linkedItemId
   AND type IN ('ITEM_ADJ', 'REPAIR_ADJ')
-  <AND_CHECK_TENANT()>
+  <AND_CHECK_TENANT("")>
   ;
 >>
 
@@ -74,7 +74,7 @@ updateAmount() ::= <<
     UPDATE <tableName()>
     SET amount = :amount
     WHERE id = :id
-    <AND_CHECK_TENANT()>;
+    <AND_CHECK_TENANT("")>;
 >>
 
 getInvoiceItemsByParentInvoice() ::= <<
@@ -83,7 +83,7 @@ getInvoiceItemsByParentInvoice() ::= <<
   INNER JOIN invoice_parent_children invRel ON invRel.child_invoice_id = items.invoice_id
   WHERE invRel.parent_invoice_id = :parentInvoiceId
   <AND_CHECK_TENANT("items.")>
-  <defaultOrderBy()>
+  <defaultOrderBy("")>
   ;
 >>
 
diff --git a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceParentChildrenSqlDao.sql.stg b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceParentChildrenSqlDao.sql.stg
index 2a96b7a..93cd6e9 100644
--- a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceParentChildrenSqlDao.sql.stg
+++ b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceParentChildrenSqlDao.sql.stg
@@ -1,4 +1,4 @@
-group InvoiceParentChildrenSqlDao: EntitySqlDao;
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "invoice_parent_children"
 
@@ -29,17 +29,17 @@ allTableValues() ::= <<
 >>
 
 getChildInvoicesByParentInvoiceId() ::= <<
-   SELECT <allTableFields()>
+   SELECT <allTableFields("")>
    FROM <tableName()>
    WHERE parent_invoice_id = :parentInvoiceId
-   <AND_CHECK_TENANT()>
-   <defaultOrderBy()>
+   <AND_CHECK_TENANT("")>
+   <defaultOrderBy("")>
  >>
 
 getParentChildMappingsByChildInvoiceIds(ids) ::= <<
-   SELECT <allTableFields()>
+   SELECT <allTableFields("")>
    FROM <tableName()>
-   WHERE child_invoice_id in (<ids: {id | :id_<i0>}; separator="," >)
-   <AND_CHECK_TENANT()>
-   <defaultOrderBy()>
+   WHERE child_invoice_id in (<ids>)
+   <AND_CHECK_TENANT("")>
+   <defaultOrderBy("")>
  >>
diff --git a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
index 7fb6bb6..140ff05 100644
--- a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
+++ b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
@@ -1,4 +1,4 @@
-group InvoicePayment: EntitySqlDao;
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "invoice_payments"
 
@@ -45,41 +45,41 @@ AND payment_id IS NOT NULL
 >>
 
 getByPaymentId() ::= <<
-  SELECT <allTableFields()>
+  SELECT <allTableFields("")>
   FROM <tableName()>
   WHERE payment_id = :paymentId
-  <AND_CHECK_TENANT()>
-  <defaultOrderBy()>
+  <AND_CHECK_TENANT("")>
+  <defaultOrderBy("")>
   ;
 >>
 
 getPaymentForCookieId() ::= <<
-  SELECT <allTableFields()>
+  SELECT <allTableFields("")>
   FROM <tableName()>
   WHERE payment_cookie_id = :paymentCookieId
-  <AND_CHECK_TENANT()>
-  <defaultOrderBy()>
+  <AND_CHECK_TENANT("")>
+  <defaultOrderBy("")>
   LIMIT 1
   ;
 >>
 
 getAllPaymentsForInvoiceIncludedInit() ::= <<
-  SELECT <allTableFields()>
+  SELECT <allTableFields("")>
   FROM <tableName()>
   WHERE invoice_id = :invoiceId
-  <AND_CHECK_TENANT()>
-  <defaultOrderBy()>
+  <AND_CHECK_TENANT("")>
+  <defaultOrderBy("")>
   ;
 >>
 
 
 
 getInvoicePayments() ::= <<
-    SELECT <allTableFields()>
+    SELECT <allTableFields("")>
     FROM <tableName()>
     WHERE payment_id = :paymentId
-    <AND_CHECK_TENANT()>
-    <defaultOrderBy()>
+    <AND_CHECK_TENANT("")>
+    <defaultOrderBy("")>
     ;
 >>
 
@@ -88,7 +88,7 @@ getRemainingAmountPaid() ::= <<
     FROM <tableName()>
     WHERE (id = :invoicePaymentId OR linked_invoice_payment_id = :invoicePaymentId)
     AND success
-    <AND_CHECK_TENANT()>
+    <AND_CHECK_TENANT("")>
     ;
 >>
 
@@ -114,12 +114,12 @@ getChargeBacksByAccountId() ::= <<
 >>
 
 getChargebacksByPaymentId() ::= <<
-    SELECT <allTableFields()>
+    SELECT <allTableFields("")>
     FROM <tableName()>
     WHERE type = 'CHARGED_BACK'
     AND linked_invoice_payment_id IN (SELECT id FROM invoice_payments WHERE payment_id = :paymentId)
     AND success
-    <AND_CHECK_TENANT()>
+    <AND_CHECK_TENANT("")>
     ;
 >>
 
diff --git a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceSqlDao.sql.stg b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceSqlDao.sql.stg
index 812767f..ab962d9 100644
--- a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceSqlDao.sql.stg
+++ b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceSqlDao.sql.stg
@@ -1,4 +1,4 @@
-group InvoiceDao: EntitySqlDao;
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "invoices"
 
@@ -59,23 +59,23 @@ updateStatus() ::= <<
     UPDATE <tableName()>
     SET status = :status
     WHERE id = :id
-    <AND_CHECK_TENANT()>;
+    <AND_CHECK_TENANT("")>;
 >>
 
 getParentDraftInvoice() ::= <<
-  SELECT <allTableFields()>
+  SELECT <allTableFields("")>
     FROM <tableName()>
    WHERE account_id = :accountId
      AND status = 'DRAFT'
-   <AND_CHECK_TENANT()>
-   <defaultOrderBy()>
+   <AND_CHECK_TENANT("")>
+   <defaultOrderBy("")>
 >>
 
 getByIds(ids) ::= <<
 select
   <allTableFields("t.")>
 from <tableName()> t
-where <idField("t.")> in (<ids: {id | :id_<i0>}; separator="," >)
+where <idField("t.")> in (<ids>)
 <AND_CHECK_TENANT("t.")>
 ;
 >>
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java b/invoice/src/test/java/org/killbill/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
index f5849cd..4447c42 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
@@ -81,7 +81,7 @@ public class TestDefaultInvoiceMigrationApi extends InvoiceTestSuiteWithEmbedded
         Assert.assertEquals(invoice.getInvoiceItems().size(), 1);
         Assert.assertEquals(invoice.getInvoiceItems().get(0).getAmount().compareTo(MIGRATION_INVOICE_AMOUNT), 0);
         Assert.assertEquals(invoice.getInvoiceItems().get(0).getType(), InvoiceItemType.RECURRING);
-        Assert.assertEquals(InvoiceModelDaoHelper.getBalance(invoice).compareTo(BigDecimal.ZERO), 0);
+        Assert.assertEquals(InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(invoice).compareTo(BigDecimal.ZERO), 0);
         Assert.assertEquals(invoice.getCurrency(), MIGRATION_INVOICE_CURRENCY);
         Assert.assertTrue(invoice.isMigrated());
 
@@ -108,7 +108,7 @@ public class TestDefaultInvoiceMigrationApi extends InvoiceTestSuiteWithEmbedded
     public void testBalance() throws InvoiceApiException {
         final InvoiceModelDao migrationInvoice = invoiceDao.getById(migrationInvoiceId, internalCallContext);
         final InvoiceModelDao regularInvoice = invoiceDao.getById(regularInvoiceId, internalCallContext);
-        final BigDecimal balanceOfAllInvoices = InvoiceModelDaoHelper.getBalance(migrationInvoice).add(InvoiceModelDaoHelper.getBalance(regularInvoice));
+        final BigDecimal balanceOfAllInvoices = InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(migrationInvoice).add(InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(regularInvoice));
 
         final BigDecimal accountBalance = invoiceUserApi.getAccountBalance(accountId, callContext);
         Assert.assertEquals(accountBalance.compareTo(balanceOfAllInvoices), 0);
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/api/user/TestDefaultInvoiceUserApi.java b/invoice/src/test/java/org/killbill/billing/invoice/api/user/TestDefaultInvoiceUserApi.java
index f83ab5f..daabe13 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/api/user/TestDefaultInvoiceUserApi.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/api/user/TestDefaultInvoiceUserApi.java
@@ -364,6 +364,10 @@ public class TestDefaultInvoiceUserApi extends InvoiceTestSuiteWithEmbeddedDB {
         Assert.assertEquals(creditInvoice.getStatus(), InvoiceStatus.DRAFT);
         Assert.assertEquals(creditInvoiceItem.getInvoiceId(), creditInvoice.getId());
 
+        // Verify DRAFT invoice is not taken into consideration when computing accountBalance
+        final BigDecimal accountBalance2 = invoiceUserApi.getAccountBalance(accountId, callContext);
+        Assert.assertEquals(accountBalance2, accountBalance);
+
         // move invoice from DRAFT to COMMITTED
         invoiceUserApi.commitInvoice(creditInvoice.getId(), callContext);
         creditInvoice = invoiceUserApi.getInvoice(invoiceId, callContext);
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/api/user/TestInvoiceFlagBehaviors.java b/invoice/src/test/java/org/killbill/billing/invoice/api/user/TestInvoiceFlagBehaviors.java
new file mode 100644
index 0000000..6a8795f
--- /dev/null
+++ b/invoice/src/test/java/org/killbill/billing/invoice/api/user/TestInvoiceFlagBehaviors.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.invoice.api.user;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.UUID;
+
+import org.killbill.billing.ObjectType;
+import org.killbill.billing.account.api.Account;
+import org.killbill.billing.invoice.InvoiceTestSuiteWithEmbeddedDB;
+import org.killbill.billing.invoice.api.Invoice;
+import org.killbill.billing.invoice.api.InvoiceItem;
+import org.killbill.billing.invoice.api.InvoiceStatus;
+import org.killbill.billing.invoice.model.ExternalChargeInvoiceItem;
+import org.killbill.billing.invoice.model.FixedPriceInvoiceItem;
+import org.killbill.billing.util.tag.ControlTagType;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+
+import static org.testng.Assert.assertEquals;
+
+public class TestInvoiceFlagBehaviors extends InvoiceTestSuiteWithEmbeddedDB {
+
+    private UUID accountId;
+
+    @Override
+    @BeforeMethod(groups = "slow")
+    public void beforeMethod() throws Exception {
+        super.beforeMethod();
+        final Account account = invoiceUtil.createAccount(callContext);
+        accountId = account.getId();
+    }
+
+    @Test(groups = "slow", description = "Verify invoice/account balance with a WRITTEN_OFF invoice. Verify account credit is not used against such invoice")
+    public void testWrittenOffInvoiceBeforeAccountCredit() throws Exception {
+
+        // Create new invoice with one charge and expect account credit to be used
+        final List<InvoiceItem> items = invoiceUserApi.insertExternalCharges(accountId, null, ImmutableList.<InvoiceItem>of(new ExternalChargeInvoiceItem(UUID.randomUUID(), clock.getUTCNow(), null, accountId, null, null, null, BigDecimal.TEN, accountCurrency)), true, callContext);
+        assertEquals(items.size(), 1);
+
+        // Check both invoice and account balance is 10.00
+        final UUID invoiceId = items.get(0).getInvoiceId();
+
+        final Invoice invoice0 = invoiceUserApi.getInvoice(invoiceId, callContext);
+        assertEquals(invoice0.getBalance().compareTo(BigDecimal.TEN), 0);
+        final BigDecimal accountBalance0 = invoiceUserApi.getAccountBalance(accountId, callContext);
+        assertEquals(accountBalance0.compareTo(BigDecimal.TEN), 0);
+
+        final BigDecimal accountCBA0 = invoiceUserApi.getAccountCBA(accountId, callContext);
+        assertEquals(accountCBA0.compareTo(BigDecimal.ZERO), 0);
+
+        // Tag invoice with WRITTEN_OFF and expect balance to now show as Zero
+        tagUserApi.addTag(invoiceId, ObjectType.INVOICE, ControlTagType.WRITTEN_OFF.getId(), callContext);
+
+        // Check both invoice and account balance is NOW  0
+        final Invoice invoice1 = invoiceUserApi.getInvoice(invoiceId, callContext);
+        assertEquals(invoice1.getBalance().compareTo(BigDecimal.ZERO), 0);
+
+        final BigDecimal accountBalance1 = invoiceUserApi.getAccountBalance(accountId, callContext);
+        assertEquals(accountBalance1.compareTo(BigDecimal.ZERO), 0);
+
+        final BigDecimal accountCBA1 = invoiceUserApi.getAccountCBA(accountId, callContext);
+        assertEquals(accountCBA1.compareTo(BigDecimal.ZERO), 0);
+
+        // Add credit on the account
+        invoiceUserApi.insertCredit(accountId, BigDecimal.TEN, null, accountCurrency, true, null, callContext);
+
+        final Invoice invoice2 = invoiceUserApi.getInvoice(invoiceId, callContext);
+        assertEquals(invoice2.getBalance().compareTo(BigDecimal.ZERO), 0);
+        assertEquals(invoice2.getInvoiceItems().size(), 1);
+
+        final BigDecimal accountBalance2 = invoiceUserApi.getAccountBalance(accountId, callContext);
+        assertEquals(accountBalance2.compareTo(new BigDecimal("-10.00")), 0);
+
+        final BigDecimal accountCBA2 = invoiceUserApi.getAccountCBA(accountId, callContext);
+        assertEquals(accountCBA2.compareTo(BigDecimal.TEN), 0);
+
+
+    }
+
+    @Test(groups = "slow", description = "Verify invoice/account balance with a WRITTEN_OFF invoice. Verify behavior when WRITTEN_OFF tag is added after credit was added to invoice" )
+    public void testWrittenOffInvoiceWithAccountCredit() throws Exception {
+
+        // Add credit on the account
+        invoiceUserApi.insertCredit(accountId, BigDecimal.TEN, null, accountCurrency, true, null, callContext);
+
+        final BigDecimal accountBalance0 = invoiceUserApi.getAccountBalance(accountId, callContext);
+        assertEquals(accountBalance0.compareTo(new BigDecimal("-10.0")), 0);
+
+        final BigDecimal accountCBA0 = invoiceUserApi.getAccountCBA(accountId, callContext);
+        assertEquals(accountCBA0.compareTo(BigDecimal.TEN), 0);
+
+        // Create new invoice with one charge and expect account credit to be used
+        final List<InvoiceItem> items = invoiceUserApi.insertExternalCharges(accountId, null, ImmutableList.<InvoiceItem>of(new ExternalChargeInvoiceItem(UUID.randomUUID(), clock.getUTCNow(), null, accountId, null, null, null, new BigDecimal("13.5"), accountCurrency)), true, callContext);
+        assertEquals(items.size(), 1);
+
+        final BigDecimal accountBalance1 = invoiceUserApi.getAccountBalance(accountId, callContext);
+        assertEquals(accountBalance1.compareTo(new BigDecimal("3.5")), 0);
+
+        final BigDecimal accountCBA1 = invoiceUserApi.getAccountCBA(accountId, callContext);
+        assertEquals(accountCBA1.compareTo(BigDecimal.ZERO), 0);
+
+        // Tag invoice with WRITTEN_OFF and expect balance to now show as Zero
+        tagUserApi.addTag(items.get(0).getInvoiceId(), ObjectType.INVOICE, ControlTagType.WRITTEN_OFF.getId(), callContext);
+
+        final BigDecimal accountBalance2 = invoiceUserApi.getAccountBalance(accountId, callContext);
+        assertEquals(accountBalance2.compareTo(BigDecimal.ZERO), 0);
+
+        final BigDecimal accountCBA2 = invoiceUserApi.getAccountCBA(accountId, callContext);
+        assertEquals(accountCBA2.compareTo(BigDecimal.ZERO), 0);
+    }
+
+    @Test(groups = "slow", description = "Verify invoice/account balance with a WRITTEN_OFF invoice. Verify account credit is not added to a previously WRITTEN_OFF invoice." )
+    public void testWrittenOffInvoiceWithAccountCredit2() throws Exception {
+
+        // Add credit on the account
+        invoiceUserApi.insertCredit(accountId, BigDecimal.TEN, null, accountCurrency, true, null, callContext);
+
+        final BigDecimal accountBalance0 = invoiceUserApi.getAccountBalance(accountId, callContext);
+        assertEquals(accountBalance0.compareTo(new BigDecimal("-10.0")), 0);
+
+        final BigDecimal accountCBA0 = invoiceUserApi.getAccountCBA(accountId, callContext);
+        assertEquals(accountCBA0.compareTo(BigDecimal.TEN), 0);
+
+        // Create new invoice with one charge and expect account credit to be used
+        final List<InvoiceItem> items = invoiceUserApi.insertExternalCharges(accountId, null, ImmutableList.<InvoiceItem>of(new ExternalChargeInvoiceItem(UUID.randomUUID(), clock.getUTCNow(), null, accountId, null, null, null, new BigDecimal("4.0"), accountCurrency)), true, callContext);
+        assertEquals(items.size(), 1);
+
+        // Tag invoice with WRITTEN_OFF
+        final UUID invoiceId = items.get(0).getInvoiceId();
+        tagUserApi.addTag(invoiceId, ObjectType.INVOICE, ControlTagType.WRITTEN_OFF.getId(), callContext);
+
+        // Add another charge on the **same invoice** => Because it is WRITTEN_OFF, we expect the CBA logic to not apply any credit
+        final List<InvoiceItem> items2 = invoiceUserApi.insertExternalCharges(accountId, null, ImmutableList.<InvoiceItem>of(new ExternalChargeInvoiceItem(UUID.randomUUID(), clock.getUTCNow(), invoiceId, accountId, null, null, null, new BigDecimal("10.0"), accountCurrency)), true, callContext);
+        assertEquals(items2.size(), 1);
+
+        final BigDecimal accountBalance2 = invoiceUserApi.getAccountBalance(accountId, callContext);
+        assertEquals(accountBalance2.compareTo(new BigDecimal("-6.00")), 0);
+
+        final BigDecimal accountCBA2 = invoiceUserApi.getAccountCBA(accountId, callContext);
+        assertEquals(accountCBA2.compareTo(new BigDecimal("6.00")), 0);
+    }
+
+
+    @Test(groups = "slow", description = "Verify invoice/account balance with migrated invoice. Verify account credit is not consumed and that invoice/account balance does not take into account migrated invoice.")
+    public void testMigratedInvoiceWithAccountCredit() throws Exception {
+
+        // Add credit on the account
+        invoiceUserApi.insertCredit(accountId, BigDecimal.TEN, null, accountCurrency, true, null, callContext);
+
+        final UUID invoiceId = invoiceUserApi.createMigrationInvoice(accountId, null, ImmutableList.<InvoiceItem>of(new FixedPriceInvoiceItem(UUID.randomUUID(), clock.getUTCNow(), null, accountId, null, null, "foo", "bar", null, null, BigDecimal.ONE, accountCurrency)), callContext);
+
+        final Invoice invoice1 = invoiceUserApi.getInvoice(invoiceId, callContext);
+        assertEquals(invoice1.getBalance().compareTo(BigDecimal.ZERO), 0);
+
+        // Verify credit is **not applied** against migration invoice
+        final BigDecimal accountBalance0 = invoiceUserApi.getAccountBalance(accountId, callContext);
+        assertEquals(accountBalance0.compareTo(new BigDecimal("-10.0")), 0);
+
+        final BigDecimal accountCBA0 = invoiceUserApi.getAccountCBA(accountId, callContext);
+        assertEquals(accountCBA0.compareTo(BigDecimal.TEN), 0);
+
+    }
+
+    @Test(groups = "slow", description = "Verify invoice/account balance with DRAFT invoice. Verify that invoice/account balance are ZERO in DRAFT mode but becomes visible after it hasa been COMMITTED." )
+    public void testDraftInvoiceWithAccountCredit() throws Exception {
+
+        // Add credit on the account
+        invoiceUserApi.insertCredit(accountId, BigDecimal.TEN, null, accountCurrency, true, null, callContext);
+
+        // Create new invoice with one charge and expect account credit to be used
+        final List<InvoiceItem> items = invoiceUserApi.insertExternalCharges(accountId, null, ImmutableList.<InvoiceItem>of(new ExternalChargeInvoiceItem(UUID.randomUUID(), clock.getUTCNow(), null, accountId, null, null, null, new BigDecimal("4.0"), accountCurrency)), false, callContext);
+        assertEquals(items.size(), 1);
+
+        final UUID invoiceId = items.get(0).getInvoiceId();
+
+        final Invoice invoice1 = invoiceUserApi.getInvoice(invoiceId, callContext);
+        assertEquals(invoice1.getStatus(), InvoiceStatus.DRAFT);
+
+        // Verify CBA was *NOT* applied against DRAFT invoice
+        assertEquals(invoice1.getInvoiceItems().size(), 1);
+        // And balance is ZERO because DRAFT mode
+        assertEquals(invoice1.getBalance().compareTo(BigDecimal.ZERO), 0);
+
+        // Verify credit is not applied against migration invoice
+        final BigDecimal accountBalance0 = invoiceUserApi.getAccountBalance(accountId, callContext);
+        assertEquals(accountBalance0.compareTo(new BigDecimal("-10.0")), 0);
+
+        final BigDecimal accountCBA0 = invoiceUserApi.getAccountCBA(accountId, callContext);
+        assertEquals(accountCBA0.compareTo(BigDecimal.TEN), 0);
+
+        invoiceUserApi.commitInvoice(invoiceId, callContext);
+
+        final Invoice invoice2 = invoiceUserApi.getInvoice(invoiceId, callContext);
+        assertEquals(invoice2.getStatus(), InvoiceStatus.COMMITTED);
+
+        // Verify this time credit was applied against COMMITTED invoice
+        assertEquals(invoice2.getBalance().compareTo(BigDecimal.ZERO), 0);
+
+        final BigDecimal accountBalance1 = invoiceUserApi.getAccountBalance(accountId, callContext);
+        assertEquals(accountBalance1.compareTo(new BigDecimal("-6.0")), 0);
+
+        final BigDecimal accountCBA1 = invoiceUserApi.getAccountCBA(accountId, callContext);
+        assertEquals(accountCBA1.compareTo(new BigDecimal("6.0")), 0);
+    }
+
+}
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/dao/MockInvoiceDao.java b/invoice/src/test/java/org/killbill/billing/invoice/dao/MockInvoiceDao.java
index 8ddb1f2..0e1ea27 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/dao/MockInvoiceDao.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/dao/MockInvoiceDao.java
@@ -68,7 +68,7 @@ public class MockInvoiceDao extends MockEntityDaoBase<InvoiceModelDao, Invoice, 
         }
         try {
             eventBus.post(new DefaultInvoiceCreationEvent(invoice.getId(), invoice.getAccountId(),
-                                                          InvoiceModelDaoHelper.getBalance(invoice), invoice.getCurrency(),
+                                                          InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(invoice), invoice.getCurrency(),
                                                           context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()));
         } catch (final PersistentBus.EventBusException ex) {
             throw new RuntimeException(ex);
@@ -260,7 +260,7 @@ public class MockInvoiceDao extends MockEntityDaoBase<InvoiceModelDao, Invoice, 
 
         for (final InvoiceModelDao invoice : getAll(context)) {
             if (accountId.equals(invoice.getAccountId())) {
-                balance = balance.add(InvoiceModelDaoHelper.getBalance(invoice));
+                balance = balance.add(InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(invoice));
             }
         }
 
@@ -272,7 +272,7 @@ public class MockInvoiceDao extends MockEntityDaoBase<InvoiceModelDao, Invoice, 
         final List<InvoiceModelDao> unpaidInvoices = new ArrayList<InvoiceModelDao>();
 
         for (final InvoiceModelDao invoice : getAll(context)) {
-            if (accountId.equals(invoice.getAccountId()) && (InvoiceModelDaoHelper.getBalance(invoice).compareTo(BigDecimal.ZERO) > 0) && !invoice.isMigrated()) {
+            if (accountId.equals(invoice.getAccountId()) && (InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(invoice).compareTo(BigDecimal.ZERO) > 0) && !invoice.isMigrated()) {
                 unpaidInvoices.add(invoice);
             }
         }
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java b/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
index 1cb8bbf..9d7199a 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
@@ -127,7 +127,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         assertTrue(thisInvoice.getInvoiceDate().compareTo(invoiceDate) == 0);
         assertEquals(thisInvoice.getCurrency(), Currency.USD);
         assertEquals(thisInvoice.getInvoiceItems().size(), 0);
-        assertTrue(InvoiceModelDaoHelper.getBalance(thisInvoice).compareTo(BigDecimal.ZERO) == 0);
+        assertTrue(InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(thisInvoice).compareTo(BigDecimal.ZERO) == 0);
     }
 
     @Test(groups = "slow")
@@ -147,7 +147,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
 
         final InvoiceModelDao savedInvoice = invoiceDao.getById(invoiceId, context);
         assertNotNull(savedInvoice);
-        assertEquals(InvoiceModelDaoHelper.getBalance(savedInvoice).compareTo(new BigDecimal("21.00")), 0);
+        assertEquals(InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(savedInvoice).compareTo(new BigDecimal("21.00")), 0);
         assertEquals(savedInvoice.getInvoiceItems().size(), 1);
 
         final BigDecimal paymentAmount = new BigDecimal("11.00");
@@ -159,7 +159,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         final InvoiceModelDao retrievedInvoice = invoiceDao.getById(invoiceId, context);
         assertNotNull(retrievedInvoice);
         assertEquals(retrievedInvoice.getInvoiceItems().size(), 1);
-        assertEquals(InvoiceModelDaoHelper.getBalance(retrievedInvoice).compareTo(new BigDecimal("10.00")), 0);
+        assertEquals(InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(retrievedInvoice).compareTo(new BigDecimal("10.00")), 0);
     }
 
     @Test(groups = "slow")
@@ -668,16 +668,16 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         final RecurringInvoiceItem item2 = new RecurringInvoiceItem(invoice.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase B", startDate,
                                                                     endDate, amount, amount, Currency.USD);
         invoiceUtil.createInvoiceItem(item2, context);
-        BigDecimal balancePriorRefund = invoiceDao.getAccountBalance(accountId, context);
-        assertEquals(balancePriorRefund.compareTo(new BigDecimal("20.00")), 0);
+        BigDecimal accountBalance = invoiceDao.getAccountBalance(accountId, context);
+        assertEquals(accountBalance.compareTo(new BigDecimal("20.00")), 0);
 
         // Pay the whole thing
         final UUID paymentId = UUID.randomUUID();
         final BigDecimal payment1 = amount;
         final InvoicePayment payment = new DefaultInvoicePayment(InvoicePaymentType.ATTEMPT, paymentId, invoice.getId(), new DateTime(), payment1, Currency.USD, Currency.USD, null, true);
         invoiceUtil.createPayment(payment, context);
-        balancePriorRefund = invoiceDao.getAccountBalance(accountId, context);
-        assertEquals(balancePriorRefund.compareTo(new BigDecimal("0.00")), 0);
+        accountBalance = invoiceDao.getAccountBalance(accountId, context);
+        assertEquals(accountBalance.compareTo(new BigDecimal("0.00")), 0);
 
         // Repair the item (And add CBA item that should be generated)
         final InvoiceItem repairItem = new RepairAdjInvoiceItem(invoice.getId(), accountId, startDate, endDate, amount.negate(), Currency.USD, item2.getId());
@@ -691,13 +691,13 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         itemAdjustment.put(item2.getId(), null);
 
         invoiceDao.createRefund(paymentId, refundAmount, true, itemAdjustment, UUID.randomUUID().toString(), context);
-        balancePriorRefund = invoiceDao.getAccountBalance(accountId, context);
+        accountBalance = invoiceDao.getAccountBalance(accountId, context);
 
         final boolean partialRefund = refundAmount.compareTo(amount) < 0;
         final BigDecimal cba = invoiceDao.getAccountCBA(accountId, context);
         final InvoiceModelDao savedInvoice = invoiceDao.getById(invoice.getId(), context);
 
-        final BigDecimal expectedCba = balancePriorRefund.compareTo(BigDecimal.ZERO) < 0 ? balancePriorRefund.negate() : BigDecimal.ZERO;
+        final BigDecimal expectedCba = accountBalance.compareTo(BigDecimal.ZERO) < 0 ? accountBalance.negate() : BigDecimal.ZERO;
         assertEquals(cba.compareTo(expectedCba), 0);
 
         // Let's re-calculate them from invoice
@@ -706,12 +706,12 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
 
         if (partialRefund) {
             // IB = 20 (rec) - 20 (repair) + 20 (cba) - (20 -7) = 7;  AB = IB - CBA = 7 - 20 = -13
-            assertEquals(balancePriorRefund.compareTo(new BigDecimal("-13.0")), 0);
+            assertEquals(accountBalance.compareTo(new BigDecimal("-13.0")), 0);
             assertEquals(savedInvoice.getInvoiceItems().size(), 4);
             assertEquals(balanceAfterRefund.compareTo(new BigDecimal("-13.0")), 0);
             assertEquals(cbaAfterRefund.compareTo(expectedCba), 0);
         } else {
-            assertEquals(balancePriorRefund.compareTo(new BigDecimal("0.0")), 0);
+            assertEquals(accountBalance.compareTo(new BigDecimal("0.0")), 0);
             assertEquals(savedInvoice.getInvoiceItems().size(), 4);
             assertEquals(balanceAfterRefund.compareTo(BigDecimal.ZERO), 0);
             assertEquals(cbaAfterRefund.compareTo(expectedCba), 0);
@@ -983,7 +983,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         assertEquals(invoices.size(), 1);
 
         final InvoiceModelDao invoice = invoices.get(0);
-        assertTrue(InvoiceModelDaoHelper.getBalance(invoice).compareTo(BigDecimal.ZERO) == 0);
+        assertTrue(InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(invoice).compareTo(BigDecimal.ZERO) == 0);
         final List<InvoiceItemModelDao> invoiceItems = invoice.getInvoiceItems();
         assertEquals(invoiceItems.size(), 2);
         boolean foundCredit = false;
@@ -1058,7 +1058,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         assertEquals(invoices.size(), 1);
 
         final InvoiceModelDao invoice = invoices.get(0);
-        assertTrue(InvoiceModelDaoHelper.getBalance(invoice).compareTo(expectedBalance) == 0);
+        assertTrue(InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(invoice).compareTo(expectedBalance) == 0);
         final List<InvoiceItemModelDao> invoiceItems = invoice.getInvoiceItems();
         assertEquals(invoiceItems.size(), expectCBA ? 3 : 2);
         boolean foundCredit = false;
@@ -1236,10 +1236,10 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         invoiceUtil.createInvoice(invoice2, context);
 
         final InvoiceModelDao savedInvoice1 = invoiceDao.getById(invoice1.getId(), context);
-        assertEquals(InvoiceModelDaoHelper.getBalance(savedInvoice1), KillBillMoney.of(TEN, savedInvoice1.getCurrency()));
+        assertEquals(InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(savedInvoice1), KillBillMoney.of(TEN, savedInvoice1.getCurrency()));
 
         final InvoiceModelDao savedInvoice2 = invoiceDao.getById(invoice2.getId(), context);
-        assertEquals(InvoiceModelDaoHelper.getBalance(savedInvoice2), KillBillMoney.of(FIVE, savedInvoice2.getCurrency()));
+        assertEquals(InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(savedInvoice2), KillBillMoney.of(FIVE, savedInvoice2.getCurrency()));
     }
 
     @Test(groups = "slow")
@@ -1388,7 +1388,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
 
         assertNotNull(savedInvoice);
         assertEquals(savedInvoice.getInvoiceItems().size(), 2);
-        assertEquals(InvoiceModelDaoHelper.getBalance(savedInvoice).compareTo(cheapAmount), 0);
+        assertEquals(InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(savedInvoice).compareTo(cheapAmount), 0);
     }
 
     @Test(groups = "slow")
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
index dc90d85..e1df2df 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
@@ -316,7 +316,7 @@ public class TestInvoiceHelper {
 
     public void verifyInvoice(final UUID invoiceId, final double balance, final double cbaAmount, final InternalTenantContext context) throws InvoiceApiException {
         final InvoiceModelDao invoice = invoiceDao.getById(invoiceId, context);
-        Assert.assertEquals(InvoiceModelDaoHelper.getBalance(invoice).doubleValue(), balance);
+        Assert.assertEquals(InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(invoice).doubleValue(), balance);
         Assert.assertEquals(InvoiceModelDaoHelper.getCBAAmount(invoice).doubleValue(), cbaAmount);
     }
 
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/usage/TestContiguousIntervalConsumableInArrear.java b/invoice/src/test/java/org/killbill/billing/invoice/usage/TestContiguousIntervalConsumableInArrear.java
index 5614cc0..96e06b7 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/usage/TestContiguousIntervalConsumableInArrear.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/usage/TestContiguousIntervalConsumableInArrear.java
@@ -322,4 +322,35 @@ public class TestContiguousIntervalConsumableInArrear extends TestUsageInArrearB
         Assert.assertEquals(rolledUpUsage.get(1).getRolledUpUnits().get(1).getAmount(), new Long(21L));
     }
 
+
+
+    @Test(groups = "fast", description="See https://github.com/killbill/killbill/issues/706")
+    public void testWithRawUsageStartDateAfterEndDate() throws CatalogApiException {
+
+        final LocalDate startDate = new LocalDate(2014, 10, 16);
+        final LocalDate endDate = startDate;
+        final LocalDate targetDate = endDate;
+
+        final LocalDate rawUsageStartDate = new LocalDate(2015, 10, 16);
+
+        final List<RawUsage> rawUsages = new ArrayList<RawUsage>();
+        rawUsages.add(new DefaultRawUsage(subscriptionId, startDate, "unit", 130L));
+
+        final DefaultTieredBlock block = createDefaultTieredBlock("unit", 100, 10, BigDecimal.ONE);
+        final DefaultTier tier = createDefaultTierWithBlocks(block);
+        final DefaultUsage usage = createConsumableInArrearUsage(usageName, BillingPeriod.MONTHLY, TierBlockPolicy.ALL_TIERS, tier);
+
+
+        final BillingEvent event1 = createMockBillingEvent(startDate.toDateTimeAtStartOfDay(DateTimeZone.UTC),BillingPeriod.MONTHLY, Collections.<Usage>emptyList());
+        final BillingEvent event2 = createMockBillingEvent(new LocalDate(2014, 10, 16).toDateTimeAtStartOfDay(DateTimeZone.UTC), BillingPeriod.MONTHLY, Collections.<Usage>emptyList());
+
+
+        final ContiguousIntervalUsageInArrear intervalConsumableInArrear = new ContiguousIntervalUsageInArrear(usage, accountId, invoiceId, rawUsages, targetDate, rawUsageStartDate, internalCallContext);
+        intervalConsumableInArrear.addBillingEvent(event1);
+        intervalConsumableInArrear.addBillingEvent(event2);
+
+        final ContiguousIntervalUsageInArrear res = intervalConsumableInArrear.build(true);
+        assertEquals(res.getTransitionTimes().size(), 0);
+    }
+
 }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PaymentAttemptJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PaymentAttemptJson.java
index f8150da..17763cf 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PaymentAttemptJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PaymentAttemptJson.java
@@ -1,5 +1,6 @@
 /*
- * Copyright 2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -85,13 +86,14 @@ public class PaymentAttemptJson extends JsonBase {
 
     public PaymentAttemptJson(final PaymentAttempt paymentAttempt, final String paymentExternalKey, @Nullable final List<AuditLog> attemptsLogs) {
         this(paymentAttempt.getAccountId().toString(),
-             paymentAttempt.getPaymentMethodId().toString(),
+             // Could be null if aborted in the priorCall
+             paymentAttempt.getPaymentMethodId() != null ? paymentAttempt.getPaymentMethodId().toString() : null,
              paymentExternalKey,
              paymentAttempt.getTransactionId() != null ? paymentAttempt.getTransactionId().toString() : null,
              paymentAttempt.getTransactionExternalKey(),
              paymentAttempt.getTransactionType().toString(),
              paymentAttempt.getEffectiveDate(),
-             paymentAttempt.getStateName() != null ? paymentAttempt.getStateName() : null,
+             paymentAttempt.getStateName(),
              paymentAttempt.getAmount(),
              paymentAttempt.getCurrency() != null ? paymentAttempt.getCurrency().toString() : null,
              paymentAttempt.getPluginName(),
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionJson.java
index f65431f..8afb59e 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionJson.java
@@ -98,7 +98,7 @@ public class SubscriptionJson extends JsonBase {
         @JsonCreator
         public EventSubscriptionJson(@JsonProperty("eventId") final String eventId,
                                      @JsonProperty("billingPeriod") final String billingPeriod,
-                                     @JsonProperty("effectiveDt") final LocalDate effectiveDate,
+                                     @JsonProperty("effectiveDate") final LocalDate effectiveDate,
                                      @JsonProperty("plan") final String plan,
                                      @JsonProperty("product") final String product,
                                      @JsonProperty("priceList") final String priceList,
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
index add62fe..c5c98e8 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
@@ -422,7 +422,9 @@ public class PaymentResource extends ComboPaymentResource {
         verifyNonNullOrEmpty(json, "PaymentTransactionJson body should be specified");
         verifyNonNullOrEmpty(json.getAmount(), "PaymentTransactionJson amount needs to be set");
 
-        final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
+        final Iterable<PluginProperty> pluginPropertiesFromBody = extractPluginProperties(json.getProperties());
+        final Iterable<PluginProperty> pluginPropertiesFromQuery = extractPluginProperties(pluginPropertiesString);
+        final Iterable<PluginProperty> pluginProperties = Iterables.concat(pluginPropertiesFromQuery, pluginPropertiesFromBody);
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
         final Payment initialPayment = getPaymentByIdOrKey(paymentIdStr, json.getPaymentExternalKey(), pluginProperties, callContext);
 
@@ -500,8 +502,11 @@ public class PaymentResource extends ComboPaymentResource {
         verifyNonNullOrEmpty(json, "PaymentTransactionJson body should be specified");
         verifyNonNullOrEmpty(json.getAmount(), "PaymentTransactionJson amount needs to be set");
 
-        final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
+        final Iterable<PluginProperty> pluginPropertiesFromBody = extractPluginProperties(json.getProperties());
+        final Iterable<PluginProperty> pluginPropertiesFromQuery = extractPluginProperties(pluginPropertiesString);
+        final Iterable<PluginProperty> pluginProperties = Iterables.concat(pluginPropertiesFromQuery, pluginPropertiesFromBody);
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
+
         final Payment initialPayment = getPaymentByIdOrKey(paymentIdStr, json.getPaymentExternalKey(), pluginProperties, callContext);
 
         final Account account = accountUserApi.getAccountById(initialPayment.getAccountId(), callContext);
@@ -573,8 +578,11 @@ public class PaymentResource extends ComboPaymentResource {
                                          final String comment,
                                          final UriInfo uriInfo,
                                          final HttpServletRequest request) throws PaymentApiException, AccountApiException {
-        final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
+        final Iterable<PluginProperty> pluginPropertiesFromBody = extractPluginProperties(json != null ? json.getProperties() : null);
+        final Iterable<PluginProperty> pluginPropertiesFromQuery = extractPluginProperties(pluginPropertiesString);
+        final Iterable<PluginProperty> pluginProperties = Iterables.concat(pluginPropertiesFromQuery, pluginPropertiesFromBody);
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
+
         final Payment initialPayment = getPaymentByIdOrKey(paymentIdStr, json.getPaymentExternalKey(), pluginProperties, callContext);
 
         final Account account = accountUserApi.getAccountById(initialPayment.getAccountId(), callContext);
@@ -649,8 +657,11 @@ public class PaymentResource extends ComboPaymentResource {
         verifyNonNullOrEmpty(json, "PaymentTransactionJson body should be specified");
         verifyNonNullOrEmpty(json.getAmount(), "PaymentTransactionJson amount needs to be set");
 
-        final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
+        final Iterable<PluginProperty> pluginPropertiesFromBody = extractPluginProperties(json.getProperties());
+        final Iterable<PluginProperty> pluginPropertiesFromQuery = extractPluginProperties(pluginPropertiesString);
+        final Iterable<PluginProperty> pluginProperties = Iterables.concat(pluginPropertiesFromQuery, pluginPropertiesFromBody);
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
+
         final Payment initialPayment = getPaymentByIdOrKey(paymentIdStr, json.getPaymentExternalKey(), pluginProperties, callContext);
 
         final Account account = accountUserApi.getAccountById(initialPayment.getAccountId(), callContext);
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/janitor/CompletionTaskBase.java b/payment/src/main/java/org/killbill/billing/payment/core/janitor/CompletionTaskBase.java
index 409c770..29893e5 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/janitor/CompletionTaskBase.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/janitor/CompletionTaskBase.java
@@ -18,6 +18,7 @@
 package org.killbill.billing.payment.core.janitor;
 
 import java.io.IOException;
+import java.util.Iterator;
 
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
@@ -86,16 +87,25 @@ abstract class CompletionTaskBase<T> implements Runnable {
             log.info("Janitor was requested to stop");
             return;
         }
-        final Iterable<T> items = getItemsForIteration();
-        for (final T item : items) {
-            if (isStopped) {
-                log.info("Janitor was requested to stop");
-                return;
+
+        final Iterator<T> iterator = getItemsForIteration().iterator();
+        try {
+            while (iterator.hasNext()) {
+                final T item = iterator.next();
+                if (isStopped) {
+                    log.info("Janitor was requested to stop");
+                    return;
+                }
+                try {
+                    doIteration(item);
+                } catch (final Exception e) {
+                    log.warn(e.getMessage());
+                }
             }
-            try {
-                doIteration(item);
-            } catch (final IllegalStateException e) {
-                log.warn(e.getMessage());
+        } finally {
+            // In case the loop stops early, make sure to close the underlying DB connection
+            while (iterator.hasNext()) {
+                iterator.next();
             }
         }
     }
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PaymentPluginServiceRegistration.java b/payment/src/main/java/org/killbill/billing/payment/core/PaymentPluginServiceRegistration.java
index 016be05..f64e772 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PaymentPluginServiceRegistration.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PaymentPluginServiceRegistration.java
@@ -20,6 +20,7 @@ package org.killbill.billing.payment.core;
 import java.util.Set;
 import java.util.UUID;
 
+import javax.annotation.Nullable;
 import javax.inject.Inject;
 
 import org.killbill.billing.ErrorCode;
@@ -45,9 +46,11 @@ public class PaymentPluginServiceRegistration {
         return pluginRegistry.getAllServices();
     }
 
-    public PaymentMethodModelDao getPaymentMethodById(final UUID paymentMethodId, final boolean includedDeleted, final InternalTenantContext context) throws PaymentApiException {
+    public PaymentMethodModelDao getPaymentMethodById(@Nullable final UUID paymentMethodId, final boolean includedDeleted, final InternalTenantContext context) throws PaymentApiException {
         final PaymentMethodModelDao paymentMethodModel;
-        if (includedDeleted) {
+        if (paymentMethodId == null) {
+            paymentMethodModel = null;
+        } else if (includedDeleted) {
             paymentMethodModel = paymentDao.getPaymentMethodIncludedDeleted(paymentMethodId, context);
         } else {
             paymentMethodModel = paymentDao.getPaymentMethod(paymentMethodId, context);
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/control/DefaultControlCompleted.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/control/DefaultControlCompleted.java
index 0d3f97f..4f67980 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/control/DefaultControlCompleted.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/control/DefaultControlCompleted.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -62,7 +62,12 @@ public class DefaultControlCompleted implements EnteringStateCallback {
                                    null;
 
         // At this stage we can update the paymentAttempt state AND serialize the plugin properties. Control plugins will have had the opportunity to erase sensitive data if required.
-        retryablePaymentAutomatonRunner.getPaymentDao().updatePaymentAttemptWithProperties(attempt.getId(), transactionId, state.getName(), getSerializedProperties(), paymentStateContext.getInternalCallContext());
+        retryablePaymentAutomatonRunner.getPaymentDao().updatePaymentAttemptWithProperties(attempt.getId(),
+                                                                                           paymentStateContext.getPaymentMethodId(),
+                                                                                           transactionId,
+                                                                                           state.getName(),
+                                                                                           getSerializedProperties(),
+                                                                                           paymentStateContext.getInternalCallContext());
 
         if (retriedState.getName().equals(state.getName()) && !isUnknownTransaction()) {
             retryServiceScheduler.scheduleRetry(ObjectType.PAYMENT_ATTEMPT, attempt.getId(), attempt.getId(), attempt.getTenantRecordId(),
diff --git a/payment/src/main/java/org/killbill/billing/payment/dao/DefaultPaymentDao.java b/payment/src/main/java/org/killbill/billing/payment/dao/DefaultPaymentDao.java
index 22baff9..f06040a 100644
--- a/payment/src/main/java/org/killbill/billing/payment/dao/DefaultPaymentDao.java
+++ b/payment/src/main/java/org/killbill/billing/payment/dao/DefaultPaymentDao.java
@@ -126,14 +126,14 @@ public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, P
     }
 
     @Override
-    public void updatePaymentAttemptWithProperties(final UUID paymentAttemptId, final UUID transactionId, final String state, final byte[] pluginProperties, final InternalCallContext context) {
+    public void updatePaymentAttemptWithProperties(final UUID paymentAttemptId, final UUID paymentMethodId, final UUID transactionId, final String state, final byte[] pluginProperties, final InternalCallContext context) {
         transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
 
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
                 final String transactionIdStr = transactionId != null ? transactionId.toString() : null;
                 final PaymentAttemptSqlDao transactional = entitySqlDaoWrapperFactory.become(PaymentAttemptSqlDao.class);
-                transactional.updateAttemptWithProperties(paymentAttemptId.toString(), transactionIdStr, state, pluginProperties, contextWithUpdatedDate(context));
+                transactional.updateAttemptWithProperties(paymentAttemptId.toString(), paymentMethodId == null ? null : paymentMethodId.toString(), transactionIdStr, state, pluginProperties, contextWithUpdatedDate(context));
                 return null;
             }
         });
diff --git a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentAttemptSqlDao.java b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentAttemptSqlDao.java
index d9aef5d..5ef0bb6 100644
--- a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentAttemptSqlDao.java
+++ b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentAttemptSqlDao.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
  * License.  You may obtain a copy of the License at:
  *
@@ -26,14 +28,14 @@ import org.killbill.billing.util.audit.ChangeType;
 import org.killbill.billing.util.entity.Entity;
 import org.killbill.billing.util.entity.dao.Audited;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.customizers.Define;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface PaymentAttemptSqlDao extends EntitySqlDao<PaymentAttemptModelDao, Entity> {
 
     @SqlUpdate
@@ -41,23 +43,24 @@ public interface PaymentAttemptSqlDao extends EntitySqlDao<PaymentAttemptModelDa
     void updateAttempt(@Bind("id") final String attemptId,
                        @Bind("transactionId") final String transactionId,
                        @Bind("stateName") final String stateName,
-                       @BindBean final InternalCallContext context);
+                       @SmartBindBean final InternalCallContext context);
 
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
     void updateAttemptWithProperties(@Bind("id") final String attemptId,
+                                     @Bind("paymentMethodId") final String paymentMethodId,
                                      @Bind("transactionId") final String transactionId,
                                      @Bind("stateName") final String stateName,
                                      @Bind("pluginProperties") final byte[] pluginProperties,
-                                     @BindBean final InternalCallContext context);
+                                     @SmartBindBean final InternalCallContext context);
 
     @SqlQuery
     List<PaymentAttemptModelDao> getByTransactionExternalKey(@Bind("transactionExternalKey") final String transactionExternalKey,
-                                                             @BindBean final InternalTenantContext context);
+                                                             @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     List<PaymentAttemptModelDao> getByPaymentExternalKey(@Bind("paymentExternalKey") final String paymentExternalKey,
-                                                         @BindBean final InternalTenantContext context);
+                                                         @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     Long getCountByStateNameAcrossTenants(@Bind("stateName") final String stateName,
diff --git a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentDao.java b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentDao.java
index b7180e8..a2be2ae 100644
--- a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentDao.java
+++ b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentDao.java
@@ -41,7 +41,7 @@ public interface PaymentDao extends EntityDao<PaymentModelDao, Payment, PaymentA
 
     public void updatePaymentAttempt(UUID paymentAttemptId, UUID transactionId, String state, InternalCallContext context);
 
-    public void updatePaymentAttemptWithProperties(UUID paymentAttemptId, UUID transactionId, String state, final byte[] pluginProperties, InternalCallContext context);
+    public void updatePaymentAttemptWithProperties(UUID paymentAttemptId, UUID paymentMethodId, UUID transactionId, String state, final byte[] pluginProperties, InternalCallContext context);
 
     public Pagination<PaymentAttemptModelDao> getPaymentAttemptsByStateAcrossTenants(String stateName, DateTime createdBeforeDate, final Long offset, final Long limit);
 
diff --git a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentMethodSqlDao.java b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentMethodSqlDao.java
index da14f3e..5512781 100644
--- a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentMethodSqlDao.java
+++ b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentMethodSqlDao.java
@@ -22,7 +22,7 @@ import java.util.Iterator;
 import java.util.List;
 
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 
@@ -33,37 +33,37 @@ import org.killbill.billing.payment.api.PaymentMethod;
 import org.killbill.billing.util.audit.ChangeType;
 import org.killbill.billing.util.entity.dao.Audited;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.customizers.Define;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface PaymentMethodSqlDao extends EntitySqlDao<PaymentMethodModelDao, PaymentMethod> {
 
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
     void markPaymentMethodAsDeleted(@Bind("id") final String paymentMethodId,
-                                    @BindBean final InternalCallContext context);
+                                    @SmartBindBean final InternalCallContext context);
 
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
     void unmarkPaymentMethodAsDeleted(@Bind("id") final String paymentMethodId,
-                                      @BindBean final InternalCallContext context);
+                                      @SmartBindBean final InternalCallContext context);
 
     @SqlQuery
-    PaymentMethodModelDao getByExternalKey(@Bind("externalKey") String paymentMethodExternalKey, @BindBean InternalTenantContext context);
+    PaymentMethodModelDao getByExternalKey(@Bind("externalKey") String paymentMethodExternalKey, @SmartBindBean InternalTenantContext context);
 
     @SqlQuery
-    PaymentMethodModelDao getPaymentMethodByExternalKeyIncludedDeleted(@Bind("externalKey") String paymentMethodExternalKey, @BindBean InternalTenantContext context);
+    PaymentMethodModelDao getPaymentMethodByExternalKeyIncludedDeleted(@Bind("externalKey") String paymentMethodExternalKey, @SmartBindBean InternalTenantContext context);
 
     @SqlQuery
     PaymentMethodModelDao getPaymentMethodIncludedDelete(@Bind("id") final String paymentMethodId,
-                                                         @BindBean final InternalTenantContext context);
+                                                         @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
-    List<PaymentMethodModelDao> getForAccount(@BindBean final InternalTenantContext context);
+    List<PaymentMethodModelDao> getForAccount(@SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
-    List<PaymentMethodModelDao> getForAccountIncludedDelete(@BindBean final InternalTenantContext context);
+    List<PaymentMethodModelDao> getForAccountIncludedDelete(@SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     @SmartFetchSize(shouldStream = true)
@@ -71,10 +71,10 @@ public interface PaymentMethodSqlDao extends EntitySqlDao<PaymentMethodModelDao,
                                                            @Bind("offset") final Long offset,
                                                            @Bind("rowCount") final Long rowCount,
                                                            @Define("ordering") final String ordering,
-                                                           @BindBean final InternalTenantContext context);
+                                                           @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     public Long getCountByPluginName(@Bind("pluginName") final String pluginName,
-                                     @BindBean final InternalTenantContext context);
+                                     @SmartBindBean final InternalTenantContext context);
 
 }
diff --git a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentSqlDao.java b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentSqlDao.java
index ee8ad0f..e932660 100644
--- a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentSqlDao.java
+++ b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentSqlDao.java
@@ -1,7 +1,8 @@
 /*
- * Copyright 2014 Groupon, Inc
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
- * Groupon licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
  * License.  You may obtain a copy of the License at:
  *
@@ -27,56 +28,57 @@ import org.killbill.billing.payment.api.Payment;
 import org.killbill.billing.util.audit.ChangeType;
 import org.killbill.billing.util.entity.dao.Audited;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.killbill.commons.jdbi.statement.SmartFetchSize;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.customizers.Define;
+import org.skife.jdbi.v2.unstable.BindIn;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface PaymentSqlDao extends EntitySqlDao<PaymentModelDao, Payment> {
 
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
     void updatePaymentForNewTransaction(@Bind("id") final String paymentId,
-                                        @BindBean final InternalCallContext context);
+                                        @SmartBindBean final InternalCallContext context);
 
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
     Object updatePaymentStateName(@Bind("id") final String paymentId,
                                   @Bind("stateName") final String stateName,
-                                  @BindBean final InternalCallContext context);
+                                  @SmartBindBean final InternalCallContext context);
 
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
     Object updateLastSuccessPaymentStateName(@Bind("id") final String paymentId,
                                              @Bind("stateName") final String stateName,
                                              @Bind("lastSuccessStateName") final String lastSuccessStateName,
-                                             @BindBean final InternalCallContext context);
+                                             @SmartBindBean final InternalCallContext context);
 
     @SqlQuery
     public PaymentModelDao getPaymentByExternalKey(@Bind("externalKey") final String externalKey,
-                                                   @BindBean final InternalTenantContext context);
+                                                   @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
-    public List<PaymentModelDao> getPaymentsByStatesAcrossTenants(@StateCollectionBinder final Collection<String> states,
+    public List<PaymentModelDao> getPaymentsByStatesAcrossTenants(@BindIn("states") final Collection<String> states,
                                                                   @Bind("createdBeforeDate") final Date createdBeforeDate,
                                                                   @Bind("createdAfterDate") final Date createdAfterDate,
                                                                   @Bind("limit") final int limit);
 
     @SqlQuery
     @SmartFetchSize(shouldStream = true)
-    public Iterator<PaymentModelDao> searchByState(@PaymentStateCollectionBinder final Collection<String> paymentStates,
+    public Iterator<PaymentModelDao> searchByState(@BindIn("states") final Collection<String> paymentStates,
                                                    @Bind("offset") final Long offset,
                                                    @Bind("rowCount") final Long rowCount,
                                                    @Define("ordering") final String ordering,
-                                                   @BindBean final InternalTenantContext context);
+                                                   @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
-    public Long getSearchByStateCount(@PaymentStateCollectionBinder final Collection<String> paymentStates,
-                                      @BindBean final InternalTenantContext context);
+    public Long getSearchByStateCount(@BindIn("states") final Collection<String> paymentStates,
+                                      @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     @SmartFetchSize(shouldStream = true)
@@ -84,9 +86,9 @@ public interface PaymentSqlDao extends EntitySqlDao<PaymentModelDao, Payment> {
                                                      @Bind("offset") final Long offset,
                                                      @Bind("rowCount") final Long rowCount,
                                                      @Define("ordering") final String ordering,
-                                                     @BindBean final InternalTenantContext context);
+                                                     @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     public Long getCountByPluginName(@Bind("pluginName") final String pluginName,
-                                     @BindBean final InternalTenantContext context);
+                                     @SmartBindBean final InternalTenantContext context);
 }
diff --git a/payment/src/main/java/org/killbill/billing/payment/dao/TransactionSqlDao.java b/payment/src/main/java/org/killbill/billing/payment/dao/TransactionSqlDao.java
index ba8b739..b6666b7 100644
--- a/payment/src/main/java/org/killbill/billing/payment/dao/TransactionSqlDao.java
+++ b/payment/src/main/java/org/killbill/billing/payment/dao/TransactionSqlDao.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -30,14 +30,15 @@ import org.killbill.billing.payment.api.PaymentTransaction;
 import org.killbill.billing.util.audit.ChangeType;
 import org.killbill.billing.util.entity.dao.Audited;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.customizers.Define;
+import org.skife.jdbi.v2.unstable.BindIn;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface TransactionSqlDao extends EntitySqlDao<PaymentTransactionModelDao, PaymentTransaction> {
 
     @SqlUpdate
@@ -49,19 +50,19 @@ public interface TransactionSqlDao extends EntitySqlDao<PaymentTransactionModelD
                                    @Bind("transactionStatus") final String transactionStatus,
                                    @Bind("gatewayErrorCode") final String gatewayErrorCode,
                                    @Bind("gatewayErrorMsg") final String gatewayErrorMsg,
-                                   @BindBean final InternalCallContext context);
+                                   @SmartBindBean final InternalCallContext context);
 
     @SqlQuery
     List<PaymentTransactionModelDao> getPaymentTransactionsByExternalKey(@Bind("transactionExternalKey") final String transactionExternalKey,
-                                                                         @BindBean final InternalTenantContext context);
+                                                                         @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
-    Long getCountByTransactionStatusPriorDateAcrossTenants(@TransactionStatusCollectionBinder final Collection<String> statuses,
+    Long getCountByTransactionStatusPriorDateAcrossTenants(@BindIn("statuses") final Collection<String> statuses,
                                                            @Bind("createdBeforeDate") final Date createdBeforeDate,
                                                            @Bind("createdAfterDate") final Date createdAfterDate);
 
     @SqlQuery
-    Iterator<PaymentTransactionModelDao> getByTransactionStatusPriorDateAcrossTenants(@TransactionStatusCollectionBinder final Collection<String> statuses,
+    Iterator<PaymentTransactionModelDao> getByTransactionStatusPriorDateAcrossTenants(@BindIn("statuses") final Collection<String> statuses,
                                                                                       @Bind("createdBeforeDate") final Date createdBeforeDate,
                                                                                       @Bind("createdAfterDate") final Date createdAfterDate,
                                                                                       @Bind("offset") final Long offset,
@@ -70,7 +71,7 @@ public interface TransactionSqlDao extends EntitySqlDao<PaymentTransactionModelD
 
     @SqlQuery
     public List<PaymentTransactionModelDao> getByPaymentId(@Bind("paymentId") final UUID paymentId,
-                                                           @BindBean final InternalTenantContext context);
+                                                           @SmartBindBean final InternalTenantContext context);
 }
 
 
diff --git a/payment/src/main/resources/org/killbill/billing/payment/dao/PaymentAttemptSqlDao.sql.stg b/payment/src/main/resources/org/killbill/billing/payment/dao/PaymentAttemptSqlDao.sql.stg
index d8699fe..39dad12 100644
--- a/payment/src/main/resources/org/killbill/billing/payment/dao/PaymentAttemptSqlDao.sql.stg
+++ b/payment/src/main/resources/org/killbill/billing/payment/dao/PaymentAttemptSqlDao.sql.stg
@@ -1,4 +1,4 @@
-group PaymentAttemptSqlDao: EntitySqlDao;
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "payment_attempts"
 
@@ -49,7 +49,7 @@ from <tableName()>
 where transaction_external_key = :transactionExternalKey
 <andCheckSoftDeletionWithComma("")>
 <AND_CHECK_TENANT("")>
-<defaultOrderBy()>
+<defaultOrderBy("")>
 ;
 >>
 
@@ -59,8 +59,8 @@ select
 from <tableName()>
 where payment_external_key = :paymentExternalKey
 <andCheckSoftDeletionWithComma("")>
-<AND_CHECK_TENANT()>
-<defaultOrderBy()>
+<AND_CHECK_TENANT("")>
+<defaultOrderBy("")>
 ;
 >>
 
@@ -72,7 +72,7 @@ from <tableName()>
 where state_name = :stateName
 and created_date \< :createdBeforeDate
 <andCheckSoftDeletionWithComma("")>
-order by <recordIdField()> <ordering>
+order by <recordIdField("")> <ordering>
 limit :rowCount offset :offset
 ;
 >>
@@ -95,19 +95,20 @@ set state_name = :stateName
 , updated_by = :updatedBy
 , updated_date = :updatedDate
 where id = :id
-<AND_CHECK_TENANT()>
+<AND_CHECK_TENANT("")>
 ;
 >>
 
 updateAttemptWithProperties() ::= <<
 update <tableName()>
 set state_name = :stateName
+, payment_method_id = :paymentMethodId
 , transaction_id = :transactionId
 , plugin_properties = :pluginProperties
 , updated_by = :updatedBy
 , updated_date = :updatedDate
 where id = :id
-<AND_CHECK_TENANT()>
+<AND_CHECK_TENANT("")>
 ;
 >>
 
diff --git a/payment/src/main/resources/org/killbill/billing/payment/dao/PaymentMethodSqlDao.sql.stg b/payment/src/main/resources/org/killbill/billing/payment/dao/PaymentMethodSqlDao.sql.stg
index 67c65f1..a26b7dd 100644
--- a/payment/src/main/resources/org/killbill/billing/payment/dao/PaymentMethodSqlDao.sql.stg
+++ b/payment/src/main/resources/org/killbill/billing/payment/dao/PaymentMethodSqlDao.sql.stg
@@ -1,6 +1,4 @@
-group PaymentMethodSqlDao: EntitySqlDao;
-
-
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "payment_methods"
 
@@ -36,7 +34,7 @@ set is_active = false
 , updated_by = :updatedBy
 , updated_date = :updatedDate
 where  id = :id
-<AND_CHECK_TENANT()>
+<AND_CHECK_TENANT("")>
 ;
 >>
 
@@ -46,51 +44,51 @@ set is_active = true
 , updated_by = :updatedBy
 , updated_date = :updatedDate
 where  id = :id
-<AND_CHECK_TENANT()>
+<AND_CHECK_TENANT("")>
 ;
 >>
 
 getByExternalKey() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 from <tableName()>
 where external_key = :externalKey
-<andCheckSoftDeletionWithComma()>
-<AND_CHECK_TENANT()>
+<andCheckSoftDeletionWithComma("")>
+<AND_CHECK_TENANT("")>
 ;
 >>
 
 getPaymentMethodByExternalKeyIncludedDeleted() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 from <tableName()>
 where external_key = :externalKey
-<AND_CHECK_TENANT()>
+<AND_CHECK_TENANT("")>
 ;
 >>
 
 getPaymentMethodIncludedDelete(accountId) ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 from <tableName()>
 where id = :id
-<AND_CHECK_TENANT()>
+<AND_CHECK_TENANT("")>
 ;
 >>
 
 getForAccount() ::= <<
 select
-<allTableFields()>
+<allTableFields("")>
 from <tableName()>
-where <accountRecordIdField()> = :accountRecordId
-<andCheckSoftDeletionWithComma()>
-<AND_CHECK_TENANT()>
+where <accountRecordIdField("")> = :accountRecordId
+<andCheckSoftDeletionWithComma("")>
+<AND_CHECK_TENANT("")>
 ;
 >>
 
 getForAccountIncludedDelete() ::= <<
 select
-<allTableFields()>
+<allTableFields("")>
 from <tableName()>
-where <accountRecordIdField()> = :accountRecordId
-<AND_CHECK_TENANT()>
+where <accountRecordIdField("")> = :accountRecordId
+<AND_CHECK_TENANT("")>
 ;
 >>
 
diff --git a/payment/src/main/resources/org/killbill/billing/payment/dao/PaymentSqlDao.sql.stg b/payment/src/main/resources/org/killbill/billing/payment/dao/PaymentSqlDao.sql.stg
index b15a04b..395dfae 100644
--- a/payment/src/main/resources/org/killbill/billing/payment/dao/PaymentSqlDao.sql.stg
+++ b/payment/src/main/resources/org/killbill/billing/payment/dao/PaymentSqlDao.sql.stg
@@ -1,4 +1,4 @@
-group PaymentSqlDao: EntitySqlDao;
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "payments"
 
@@ -41,7 +41,7 @@ update <tableName()>
 set updated_by = :updatedBy
 , updated_date = :updatedDate
 where id = :id
-<AND_CHECK_TENANT()>
+<AND_CHECK_TENANT("")>
 ;
 >>
 
@@ -51,7 +51,7 @@ set state_name = :stateName
 , updated_by = :updatedBy
 , updated_date = :updatedDate
 where id = :id
-<AND_CHECK_TENANT()>
+<AND_CHECK_TENANT("")>
 ;
 >>
 
@@ -62,7 +62,7 @@ set state_name = :stateName
 , updated_by = :updatedBy
 , updated_date = :updatedDate
 where id = :id
-<AND_CHECK_TENANT()>
+<AND_CHECK_TENANT("")>
 ;
 >>
 
@@ -71,7 +71,7 @@ select
 <allTableFields("")>
 from <tableName()>
 where external_key = :externalKey
-<AND_CHECK_TENANT()>
+<AND_CHECK_TENANT("")>
 ;
 >>
 
@@ -87,12 +87,12 @@ select
 <allTableFields("t.")>
 from <tableName()> t
 join (
-  select <recordIdField()>
+  select <recordIdField("")>
   from <tableName()>
-  where state_name in (<states: {state | :state_<i0>}; separator="," >)
-  <AND_CHECK_TENANT()>
-  <andCheckSoftDeletionWithComma()>
-  order by <recordIdField()> <ordering>
+  where state_name in (<states>)
+  <AND_CHECK_TENANT("")>
+  <andCheckSoftDeletionWithComma("")>
+  order by <recordIdField("")> <ordering>
   limit :rowCount offset :offset
 ) optimization on <recordIdField("optimization.")> = <recordIdField("t.")>
 order by <recordIdField("t.")> <ordering>
@@ -103,7 +103,7 @@ getSearchByStateCount(states) ::= <<
 select
   count(1) as count
 from <tableName()> t
-where t.state_name in (<states: {state | :state_<i0>}; separator="," >)
+where t.state_name in (<states>)
 <andCheckSoftDeletionWithComma("t.")>
 <AND_CHECK_TENANT("t.")>
 ;
@@ -138,7 +138,7 @@ from <tableName()> t
 where
 created_date >= :createdAfterDate
 and created_date \< :createdBeforeDate
-and state_name in (<states: {state | :state_<i0>}; separator="," >)
+and state_name in (<states>)
 limit :limit
 ;
 >>
diff --git a/payment/src/main/resources/org/killbill/billing/payment/dao/TransactionSqlDao.sql.stg b/payment/src/main/resources/org/killbill/billing/payment/dao/TransactionSqlDao.sql.stg
index 1f19f0b..cbdc740 100644
--- a/payment/src/main/resources/org/killbill/billing/payment/dao/TransactionSqlDao.sql.stg
+++ b/payment/src/main/resources/org/killbill/billing/payment/dao/TransactionSqlDao.sql.stg
@@ -1,4 +1,4 @@
-group TransactionSqlDao: EntitySqlDao;
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "payment_transactions"
 
@@ -51,8 +51,8 @@ select
 <allTableFields("")>
 from <tableName()>
 where transaction_external_key = :transactionExternalKey
-<AND_CHECK_TENANT()>
-<defaultOrderBy()>
+<AND_CHECK_TENANT("")>
+<defaultOrderBy("")>
 ;
 >>
 
@@ -68,29 +68,29 @@ set transaction_status = :transactionStatus
 , updated_by = :updatedBy
 , updated_date = :updatedDate
 where id = :id
-<AND_CHECK_TENANT()>
+<AND_CHECK_TENANT("")>
 ;
 >>
 
 getByPaymentId() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 from <tableName()>
 where payment_id = :paymentId
-<AND_CHECK_TENANT()>
-<defaultOrderBy()>
+<AND_CHECK_TENANT("")>
+<defaultOrderBy("")>
 ;
 >>
 
 
 /* Does not include AND_CHECK_TENANT() since this is a global operation */
 getByTransactionStatusPriorDateAcrossTenants(statuses, ordering) ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 from <tableName()>
 where
 created_date >= :createdAfterDate
 and created_date \< :createdBeforeDate
-and transaction_status in (<statuses: {status | :status_<i0>}; separator="," >)
-order by <recordIdField()> <ordering>
+and transaction_status in (<statuses>)
+order by <recordIdField("")> <ordering>
 limit :rowCount offset :offset
 ;
 >>
@@ -102,7 +102,7 @@ from <tableName()>
 where
 created_date >= :createdAfterDate
 and created_date \< :createdBeforeDate
-and transaction_status in (<statuses: {status | :status_<i0>}; separator="," >)
+and transaction_status in (<statuses>)
 ;
 >>
 
diff --git a/payment/src/test/java/org/killbill/billing/payment/core/janitor/TestCompletionTaskBase.java b/payment/src/test/java/org/killbill/billing/payment/core/janitor/TestCompletionTaskBase.java
new file mode 100644
index 0000000..c32ea7f
--- /dev/null
+++ b/payment/src/test/java/org/killbill/billing/payment/core/janitor/TestCompletionTaskBase.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.payment.core.janitor;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.killbill.billing.account.api.AccountInternalApi;
+import org.killbill.billing.payment.PaymentTestSuiteWithEmbeddedDB;
+import org.killbill.billing.payment.api.PaymentApiException;
+import org.killbill.billing.payment.core.sm.PaymentControlStateMachineHelper;
+import org.killbill.billing.payment.core.sm.PaymentStateMachineHelper;
+import org.killbill.billing.payment.core.sm.PluginControlPaymentAutomatonRunner;
+import org.killbill.billing.payment.dao.PaymentAttemptModelDao;
+import org.killbill.billing.payment.dao.PaymentDao;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
+import org.killbill.billing.util.config.definition.PaymentConfig;
+import org.killbill.clock.Clock;
+import org.killbill.commons.locker.GlobalLocker;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+
+public class TestCompletionTaskBase extends PaymentTestSuiteWithEmbeddedDB {
+
+    @Test(groups = "slow", description = "https://github.com/killbill/killbill/issues/757")
+    public void testHandleRuntimeExceptions() throws PaymentApiException {
+        final List<PaymentAttemptModelDao> paymentAttemptModelDaos = ImmutableList.<PaymentAttemptModelDao>of(new PaymentAttemptModelDao(),
+                                                                                                              new PaymentAttemptModelDao());
+        final Iterator<PaymentAttemptModelDao> paymentAttemptModelDaoIterator = paymentAttemptModelDaos.iterator();
+        final Iterable<PaymentAttemptModelDao> itemsForIteration = new Iterable<PaymentAttemptModelDao>() {
+            @Override
+            public Iterator<PaymentAttemptModelDao> iterator() {
+                return paymentAttemptModelDaoIterator;
+            }
+        };
+        Assert.assertTrue(paymentAttemptModelDaoIterator.hasNext());
+
+        final Runnable incompletePaymentAttemptTaskWithException = new IncompletePaymentAttemptTaskWithException(itemsForIteration,
+                                                                                                                 internalCallContextFactory,
+                                                                                                                 paymentConfig,
+                                                                                                                 paymentDao,
+                                                                                                                 clock,
+                                                                                                                 paymentSMHelper,
+                                                                                                                 paymentControlStateMachineHelper,
+                                                                                                                 accountApi,
+                                                                                                                 pluginControlPaymentAutomatonRunner,
+                                                                                                                 locker);
+
+        incompletePaymentAttemptTaskWithException.run();
+
+        // Make sure we cycled through all entries
+        Assert.assertFalse(paymentAttemptModelDaoIterator.hasNext());
+    }
+
+    private final class IncompletePaymentAttemptTaskWithException extends IncompletePaymentAttemptTask {
+
+        private final Iterable<PaymentAttemptModelDao> itemsForIteration;
+
+        public IncompletePaymentAttemptTaskWithException(final Iterable<PaymentAttemptModelDao> itemsForIteration, final InternalCallContextFactory internalCallContextFactory, final PaymentConfig paymentConfig, final PaymentDao paymentDao, final Clock clock, final PaymentStateMachineHelper paymentStateMachineHelper, final PaymentControlStateMachineHelper retrySMHelper, final AccountInternalApi accountInternalApi, final PluginControlPaymentAutomatonRunner pluginControlledPaymentAutomatonRunner, final GlobalLocker locker) {
+            super(internalCallContextFactory, paymentConfig, paymentDao, clock, paymentStateMachineHelper, retrySMHelper, accountInternalApi, pluginControlledPaymentAutomatonRunner, locker);
+            this.itemsForIteration = itemsForIteration;
+        }
+
+        @Override
+        public Iterable<PaymentAttemptModelDao> getItemsForIteration() {
+            return itemsForIteration;
+        }
+
+        @Override
+        public void doIteration(final PaymentAttemptModelDao attempt) {
+            throw new NullPointerException("NPE for tests");
+        }
+    }
+}
diff --git a/payment/src/test/java/org/killbill/billing/payment/dao/MockPaymentDao.java b/payment/src/test/java/org/killbill/billing/payment/dao/MockPaymentDao.java
index f167975..b932f15 100644
--- a/payment/src/test/java/org/killbill/billing/payment/dao/MockPaymentDao.java
+++ b/payment/src/test/java/org/killbill/billing/payment/dao/MockPaymentDao.java
@@ -27,6 +27,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
+import javax.annotation.Nullable;
 import javax.inject.Inject;
 
 import org.joda.time.DateTime;
@@ -100,15 +101,18 @@ public class MockPaymentDao extends MockEntityDaoBase<PaymentModelDao, Payment, 
 
     @Override
     public void updatePaymentAttempt(final UUID paymentAttemptId, final UUID transactionId, final String state, final InternalCallContext context) {
-        updatePaymentAttemptWithProperties(paymentAttemptId, transactionId, state, null, context);
+        updatePaymentAttemptWithProperties(paymentAttemptId, null, transactionId, state, null, context);
     }
 
     @Override
-    public void updatePaymentAttemptWithProperties(final UUID paymentAttemptId, final UUID transactionId, final String state, final byte[] pluginProperties, final InternalCallContext context) {
+    public void updatePaymentAttemptWithProperties(final UUID paymentAttemptId, @Nullable final UUID paymentMethodId, final UUID transactionId, final String state, final byte[] pluginProperties, final InternalCallContext context) {
         boolean success = false;
         synchronized (this) {
             for (PaymentAttemptModelDao cur : attempts.values()) {
                 if (cur.getId().equals(paymentAttemptId)) {
+                    if (paymentMethodId != null) {
+                        cur.setPaymentMethodId(paymentMethodId);
+                    }
                     cur.setStateName(state);
                     cur.setTransactionId(transactionId);
                     if (pluginProperties != null) {
diff --git a/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java b/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java
index 113c147..8e0f0fe 100644
--- a/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java
+++ b/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java
@@ -564,7 +564,7 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
         properties.add(new PluginProperty("prop2", "value2", false));
 
         final byte [] serializedProperties = PluginPropertySerializer.serialize(properties);
-        paymentDao.updatePaymentAttemptWithProperties(rehydratedAttempt.getId(), transactionId, newStateName, serializedProperties, internalCallContext);
+        paymentDao.updatePaymentAttemptWithProperties(rehydratedAttempt.getId(), rehydratedAttempt.getPaymentMethodId(), transactionId, newStateName, serializedProperties, internalCallContext);
         final PaymentAttemptModelDao attempt2 = paymentDao.getPaymentAttempt(rehydratedAttempt.getId(), internalCallContext);
         assertEquals(attempt2.getStateName(), newStateName);
         assertEquals(attempt2.getTransactionId(), transactionId);
diff --git a/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteWithEmbeddedDB.java b/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteWithEmbeddedDB.java
index 0210596..cf7454d 100644
--- a/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteWithEmbeddedDB.java
+++ b/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteWithEmbeddedDB.java
@@ -33,7 +33,9 @@ import org.killbill.billing.payment.core.PaymentPluginServiceRegistration;
 import org.killbill.billing.payment.core.PaymentProcessor;
 import org.killbill.billing.payment.core.janitor.IncompletePaymentTransactionTask;
 import org.killbill.billing.payment.core.janitor.Janitor;
+import org.killbill.billing.payment.core.sm.PaymentControlStateMachineHelper;
 import org.killbill.billing.payment.core.sm.PaymentStateMachineHelper;
+import org.killbill.billing.payment.core.sm.PluginControlPaymentAutomatonRunner;
 import org.killbill.billing.payment.dao.PaymentDao;
 import org.killbill.billing.payment.glue.PaymentModule;
 import org.killbill.billing.payment.glue.TestPaymentModuleWithEmbeddedDB;
@@ -103,6 +105,10 @@ public abstract class PaymentTestSuiteWithEmbeddedDB extends GuicyKillbillTestSu
     protected IncompletePaymentTransactionTask incompletePaymentTransactionTask;
     @Inject
     protected GlobalLocker locker;
+    @Inject
+    protected PluginControlPaymentAutomatonRunner pluginControlPaymentAutomatonRunner;
+    @Inject
+    protected PaymentControlStateMachineHelper paymentControlStateMachineHelper;
 
     @Override
     protected KillbillConfigSource getConfigSource() {
diff --git a/payment/src/test/java/org/killbill/billing/payment/provider/MockPaymentControlProviderPlugin.java b/payment/src/test/java/org/killbill/billing/payment/provider/MockPaymentControlProviderPlugin.java
index 3719daf..f451943 100644
--- a/payment/src/test/java/org/killbill/billing/payment/provider/MockPaymentControlProviderPlugin.java
+++ b/payment/src/test/java/org/killbill/billing/payment/provider/MockPaymentControlProviderPlugin.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -17,6 +17,8 @@
 
 package org.killbill.billing.payment.provider;
 
+import java.util.UUID;
+
 import org.joda.time.DateTime;
 import org.killbill.billing.payment.api.PluginProperty;
 import org.killbill.billing.payment.retry.DefaultFailureCallResult;
@@ -33,6 +35,7 @@ public class MockPaymentControlProviderPlugin implements PaymentControlPluginApi
 
     public static final String PLUGIN_NAME = "MOCK_RETRY_PLUGIN";
 
+    private UUID adjustedPaymentMethodId;
     private boolean isAborted;
     private DateTime nextRetryDate;
     private Exception exception;
@@ -41,6 +44,11 @@ public class MockPaymentControlProviderPlugin implements PaymentControlPluginApi
     private boolean onSuccessCallExecuted;
     private boolean onFailureCallExecuted;
 
+    public MockPaymentControlProviderPlugin setAdjustedPaymentMethodId(final UUID adjustedPaymentMethodId) {
+        this.adjustedPaymentMethodId = adjustedPaymentMethodId;
+        return this;
+    }
+
     public MockPaymentControlProviderPlugin setAborted(final boolean isAborted) {
         this.isAborted = isAborted;
         return this;
@@ -69,7 +77,7 @@ public class MockPaymentControlProviderPlugin implements PaymentControlPluginApi
         } else if (exception instanceof RuntimeException) {
             throw (RuntimeException) exception;
         }
-        return new DefaultPriorPaymentControlResult(isAborted);
+        return new DefaultPriorPaymentControlResult(isAborted, adjustedPaymentMethodId, null, null, null);
     }
 
     @Override
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillBillEmbeddedDBProvider.java b/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillBillEmbeddedDBProvider.java
index b460401..a803057 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillBillEmbeddedDBProvider.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillBillEmbeddedDBProvider.java
@@ -34,6 +34,7 @@ public class KillBillEmbeddedDBProvider extends EmbeddedDBProvider {
         final Collection<String> ddlFiles = new LinkedList<String>();
         for (final String module : new String[]{"account",
                                                 "beatrix",
+                                                "catalog",
                                                 "entitlement",
                                                 "invoice",
                                                 "payment",
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java b/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java
index ff6de44..d05cc24 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillbillServerModule.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -66,8 +66,6 @@ import org.killbill.billing.subscription.glue.DefaultSubscriptionModule;
 import org.killbill.billing.tenant.glue.DefaultTenantModule;
 import org.killbill.billing.usage.glue.UsageModule;
 import org.killbill.billing.util.config.definition.NotificationConfig;
-import org.killbill.billing.util.dao.AuditLogModelDaoMapper;
-import org.killbill.billing.util.dao.RecordIdIdMappingsMapper;
 import org.killbill.billing.util.email.EmailModule;
 import org.killbill.billing.util.email.templates.TemplateModule;
 import org.killbill.billing.util.glue.AuditModule;
@@ -79,6 +77,7 @@ import org.killbill.billing.util.glue.ConfigModule;
 import org.killbill.billing.util.glue.CustomFieldModule;
 import org.killbill.billing.util.glue.ExportModule;
 import org.killbill.billing.util.glue.GlobalLockerModule;
+import org.killbill.billing.util.glue.IDBISetup;
 import org.killbill.billing.util.glue.KillBillShiroAopModule;
 import org.killbill.billing.util.glue.KillbillApiAopModule;
 import org.killbill.billing.util.glue.NodesModule;
@@ -86,11 +85,9 @@ import org.killbill.billing.util.glue.NonEntityDaoModule;
 import org.killbill.billing.util.glue.RecordIdModule;
 import org.killbill.billing.util.glue.SecurityModule;
 import org.killbill.billing.util.glue.TagStoreModule;
-import org.killbill.billing.util.security.shiro.dao.SessionModelDao;
 import org.killbill.clock.Clock;
 import org.killbill.clock.ClockMock;
 import org.killbill.commons.embeddeddb.EmbeddedDB;
-import org.killbill.commons.jdbi.mapper.LowerToCamelBeanMapperFactory;
 import org.skife.config.ConfigurationObjectFactory;
 import org.skife.jdbi.v2.ResultSetMapperFactory;
 import org.skife.jdbi.v2.tweak.ResultSetMapper;
@@ -124,11 +121,14 @@ public class KillbillServerModule extends KillbillPlatformModule {
         super.configureDao();
 
         final Multibinder<ResultSetMapperFactory> resultSetMapperFactorySetBinder = Multibinder.newSetBinder(binder(), ResultSetMapperFactory.class);
-        resultSetMapperFactorySetBinder.addBinding().toInstance(new LowerToCamelBeanMapperFactory(SessionModelDao.class));
+        for (final ResultSetMapperFactory resultSetMapperFactory : IDBISetup.mapperFactoriesToRegister()) {
+            resultSetMapperFactorySetBinder.addBinding().toInstance(resultSetMapperFactory);
+        }
 
         final Multibinder<ResultSetMapper> resultSetMapperSetBinder = Multibinder.newSetBinder(binder(), ResultSetMapper.class);
-        resultSetMapperSetBinder.addBinding().to(AuditLogModelDaoMapper.class).asEagerSingleton();
-        resultSetMapperSetBinder.addBinding().to(RecordIdIdMappingsMapper.class).asEagerSingleton();
+        for (final ResultSetMapper resultSetMapper : IDBISetup.mappersToRegister()) {
+            resultSetMapperSetBinder.addBinding().toInstance(resultSetMapper);
+        }
     }
 
     @Override
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
index 25517ab..319573b 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
@@ -29,6 +29,7 @@ import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.PriceListSet;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.client.KillBillClient;
+import org.killbill.billing.client.KillBillClientException;
 import org.killbill.billing.client.KillBillHttpClient;
 import org.killbill.billing.client.RequestOptions;
 import org.killbill.billing.client.model.Account;
@@ -119,11 +120,16 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
     protected Account createAccountWithExternalPaymentMethod() throws Exception {
         final Account input = createAccount();
 
+        createPaymentMethod(input, true);
+
+        return killBillClient.getAccount(input.getExternalKey(), requestOptions);
+    }
+
+    protected PaymentMethod createPaymentMethod(final Account input, final boolean isDefault) throws KillBillClientException {
         final PaymentMethodPluginDetail info = new PaymentMethodPluginDetail();
         final PaymentMethod paymentMethodJson = new PaymentMethod(null, UUIDs.randomUUID().toString(), input.getAccountId(),
-                                                                  true, ExternalPaymentProviderPlugin.PLUGIN_NAME, info);
-        killBillClient.createPaymentMethod(paymentMethodJson, requestOptions);
-        return killBillClient.getAccount(input.getExternalKey(), requestOptions);
+                                                                  isDefault, ExternalPaymentProviderPlugin.PLUGIN_NAME, info);
+        return killBillClient.createPaymentMethod(paymentMethodJson, requestOptions);
     }
 
     protected Account createAccount() throws Exception {
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
index 13b0fa4..69c17a0 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
@@ -19,6 +19,7 @@ package org.killbill.billing.jaxrs;
 
 import java.math.BigDecimal;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.UUID;
@@ -617,6 +618,29 @@ public class TestPayment extends TestJaxrsBase {
     }
 
     @Test(groups = "slow")
+    public void testComboAuthorizationControlWithNullPaymentMethodId() throws Exception {
+        final Account accountJson = createAccount();
+
+        // Non-default payment method
+        final PaymentMethod paymentMethod = createPaymentMethod(accountJson, false);
+        mockPaymentControlProviderPlugin.setAdjustedPaymentMethodId(paymentMethod.getPaymentMethodId());
+
+        accountJson.setAccountId(null);
+        final String paymentExternalKey = UUID.randomUUID().toString();
+
+        final PaymentTransaction authTransactionJson = new PaymentTransaction();
+        authTransactionJson.setPaymentExternalKey(paymentExternalKey);
+        authTransactionJson.setAmount(BigDecimal.TEN);
+        authTransactionJson.setTransactionType("AUTHORIZE");
+        final ComboPaymentTransaction comboPaymentTransaction = new ComboPaymentTransaction(accountJson, null, authTransactionJson, ImmutableList.<PluginProperty>of(), ImmutableList.<PluginProperty>of());
+
+        final Payment payment = killBillClient.createPayment(comboPaymentTransaction, ImmutableList.<String>of(MockPaymentControlProviderPlugin.PLUGIN_NAME), ImmutableMap.<String, String>of(), requestOptions);
+        verifyComboPayment(payment, paymentExternalKey, BigDecimal.TEN, BigDecimal.ZERO, BigDecimal.ZERO, 1, 1);
+
+        assertEquals(killBillClient.getPayment(payment.getPaymentId(), false, true, ImmutableMap.<String, String>of(), AuditLevel.NONE, requestOptions).getPaymentAttempts().size(), 1);
+    }
+
+    @Test(groups = "slow")
     public void testComboAuthorizationControlPluginException() throws Exception {
         final Account accountJson = getAccount();
         accountJson.setAccountId(null);
@@ -799,7 +823,7 @@ public class TestPayment extends TestJaxrsBase {
         assertEquals(payment.getRefundedAmount().compareTo(refundedAmount), 0);
         assertEquals(payment.getTransactions().size(), nbTransactions);
 
-        final Payments Payments = killBillClient.getPayments();
+        final Payments Payments = killBillClient.getPayments(requestOptions);
         assertEquals(Payments.size(), paymentNb);
         assertEquals(Payments.get(paymentNb - 1), payment);
     }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPaymentPluginProperties.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPaymentPluginProperties.java
index f31858f..3d87984 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPaymentPluginProperties.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPaymentPluginProperties.java
@@ -103,7 +103,7 @@ public class TestPaymentPluginProperties extends TestJaxrsBase {
             for (org.killbill.billing.payment.api.PluginProperty input : properties) {
                 boolean found  = false;
                 for (org.killbill.billing.payment.api.PluginProperty expect : expectedProperties) {
-                    if (expect.getKey().equals(input.getKey()) && expect.getValue().equals(expect.getValue())) {
+                    if (expect.getKey().equals(input.getKey()) && expect.getValue().equals(input.getValue())) {
                         found = true;
                         break;
                     }
@@ -111,10 +111,10 @@ public class TestPaymentPluginProperties extends TestJaxrsBase {
                 Assert.assertTrue(found);
             }
 
-            for (org.killbill.billing.payment.api.PluginProperty expect : properties) {
+            for (org.killbill.billing.payment.api.PluginProperty expect : expectedProperties) {
                 boolean found  = false;
-                for (org.killbill.billing.payment.api.PluginProperty input : expectedProperties) {
-                    if (expect.getKey().equals(input.getKey()) && expect.getValue().equals(expect.getValue())) {
+                for (org.killbill.billing.payment.api.PluginProperty input : properties) {
+                    if (expect.getKey().equals(input.getKey()) && expect.getValue().equals(input.getValue())) {
                         found = true;
                         break;
                     }
@@ -227,9 +227,25 @@ public class TestPaymentPluginProperties extends TestJaxrsBase {
         params.putAll(KillBillHttpClient.CONTROL_PLUGIN_NAME, ImmutableList.<String>of(PluginPropertiesVerificator.PLUGIN_NAME));
 
         final RequestOptions requestOptionsWithParams = basicRequestOptions.extend()
-                                                          .withQueryParams(params).build();
+                                                                           .withQueryParams(params).build();
 
         killBillClient.completePayment(completeTransactionByPaymentId, queryProperties, requestOptionsWithParams);
+
+        //Capture the payment
+        final PaymentTransaction captureTransaction = new PaymentTransaction();
+        captureTransaction.setPaymentId(initialPayment.getPaymentId());
+        captureTransaction.setProperties(bodyProperties);
+        captureTransaction.setAmount(BigDecimal.TEN);
+        captureTransaction.setCurrency(account.getCurrency());
+        killBillClient.captureAuthorization(captureTransaction, ImmutableList.<String>of(PluginPropertiesVerificator.PLUGIN_NAME), queryProperties, requestOptions);
+
+        //Refund the payment
+        final PaymentTransaction refundTransaction = new PaymentTransaction();
+        refundTransaction.setPaymentId(initialPayment.getPaymentId());
+        refundTransaction.setProperties(bodyProperties);
+        refundTransaction.setAmount(BigDecimal.TEN);
+        refundTransaction.setCurrency(account.getCurrency());
+        killBillClient.refundPayment(refundTransaction, ImmutableList.<String>of(PluginPropertiesVerificator.PLUGIN_NAME), queryProperties, requestOptions);
     }
 
     private Payment createVerifyTransaction(final Account account,

README.md 2(+1 -1)

diff --git a/README.md b/README.md
index c810485..3ffcee9 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 Kill Bill is the Open-Source Billing & Payment Platform.
 
-Among features:
+## Among features
 
 * Subscription engine, with plans management (trial, upgrade, downgrade, etc.), support of add-ons, bundles with multiple subscriptions
 * Invoicing engine, supporting different billing alignments, recurring and one-time charges, international tax, metered billing
diff --git a/subscription/pom.xml b/subscription/pom.xml
index e915aae..25811b5 100644
--- a/subscription/pom.xml
+++ b/subscription/pom.xml
@@ -75,7 +75,7 @@
         </dependency>
         <dependency>
             <groupId>org.antlr</groupId>
-            <artifactId>stringtemplate</artifactId>
+            <artifactId>ST4</artifactId>
             <scope>runtime</scope>
         </dependency>
         <dependency>
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/BundleSqlDao.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/BundleSqlDao.java
index 585e013..bc8f9f2 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/BundleSqlDao.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/BundleSqlDao.java
@@ -20,7 +20,7 @@ import java.util.Date;
 import java.util.List;
 
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 
@@ -31,33 +31,33 @@ import org.killbill.billing.subscription.engine.dao.model.SubscriptionBundleMode
 import org.killbill.billing.util.audit.ChangeType;
 import org.killbill.billing.util.entity.dao.Audited;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface BundleSqlDao extends EntitySqlDao<SubscriptionBundleModelDao, SubscriptionBaseBundle> {
 
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
     public void updateBundleExternalKey(@Bind("id") String id,
                                         @Bind("externalKey") String externalKey,
-                                        @BindBean final InternalCallContext context);
+                                        @SmartBindBean final InternalCallContext context);
 
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
     public void updateBundleLastSysTime(@Bind("id") String id,
                                         @Bind("lastSysUpdateDate") Date lastSysUpdate,
-                                        @BindBean final InternalCallContext context);
+                                        @SmartBindBean final InternalCallContext context);
 
     @SqlQuery
     public List<SubscriptionBundleModelDao> getBundlesFromAccountAndKey(@Bind("accountId") String accountId,
                                                                         @Bind("externalKey") String externalKey,
-                                                                        @BindBean final InternalTenantContext context);
+                                                                        @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     public List<SubscriptionBundleModelDao> getBundleFromAccount(@Bind("accountId") String accountId,
-                                                                 @BindBean final InternalTenantContext context);
+                                                                 @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     public List<SubscriptionBundleModelDao> getBundlesForKey(@Bind("externalKey") String externalKey,
-                                                             @BindBean final InternalTenantContext context);
+                                                             @SmartBindBean final InternalTenantContext context);
 }
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionEventSqlDao.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionEventSqlDao.java
index c47d482..0e195db 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionEventSqlDao.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionEventSqlDao.java
@@ -26,34 +26,34 @@ import org.killbill.billing.subscription.events.SubscriptionBaseEvent;
 import org.killbill.billing.util.audit.ChangeType;
 import org.killbill.billing.util.entity.dao.Audited;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface SubscriptionEventSqlDao extends EntitySqlDao<SubscriptionEventModelDao, SubscriptionBaseEvent> {
 
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
     public void unactiveEvent(@Bind("id") String id,
-                              @BindBean final InternalCallContext context);
+                              @SmartBindBean final InternalCallContext context);
 
     @SqlQuery
     public List<SubscriptionEventModelDao> getFutureActiveEventForSubscription(@Bind("subscriptionId") String subscriptionId,
                                                                                @Bind("now") Date now,
-                                                                               @BindBean final InternalTenantContext context);
+                                                                               @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     public List<SubscriptionEventModelDao> getFutureOrPresentActiveEventForSubscription(@Bind("subscriptionId") String subscriptionId,
                                                                                         @Bind("now") Date now,
-                                                                                        @BindBean final InternalTenantContext context);
+                                                                                        @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     public List<SubscriptionEventModelDao> getActiveEventsForSubscription(@Bind("subscriptionId") String subscriptionId,
-                                                                          @BindBean final InternalTenantContext context);
+                                                                          @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
-    public List<SubscriptionEventModelDao> getFutureActiveEventsForAccount(@Bind("now") Date now, @BindBean final InternalTenantContext context);
+    public List<SubscriptionEventModelDao> getFutureActiveEventsForAccount(@Bind("now") Date now, @SmartBindBean final InternalTenantContext context);
 }
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionSqlDao.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionSqlDao.java
index b47b5ba..c0c2495 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionSqlDao.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionSqlDao.java
@@ -20,7 +20,7 @@ import java.util.Date;
 import java.util.List;
 
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 
@@ -31,18 +31,18 @@ import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.util.entity.dao.Audited;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface SubscriptionSqlDao extends EntitySqlDao<SubscriptionModelDao, SubscriptionBase> {
 
     @SqlQuery
     public List<SubscriptionModelDao> getSubscriptionsFromBundleId(@Bind("bundleId") String bundleId,
-                                                                   @BindBean final InternalTenantContext context);
+                                                                   @SmartBindBean final InternalTenantContext context);
 
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
     public void updateChargedThroughDate(@Bind("id") String id, @Bind("chargedThroughDate") Date chargedThroughDate,
-                                         @BindBean final InternalCallContext context);
+                                         @SmartBindBean final InternalCallContext context);
 
 }
diff --git a/subscription/src/main/resources/org/killbill/billing/subscription/engine/dao/BundleSqlDao.sql.stg b/subscription/src/main/resources/org/killbill/billing/subscription/engine/dao/BundleSqlDao.sql.stg
index 4495409..9a5337c 100644
--- a/subscription/src/main/resources/org/killbill/billing/subscription/engine/dao/BundleSqlDao.sql.stg
+++ b/subscription/src/main/resources/org/killbill/billing/subscription/engine/dao/BundleSqlDao.sql.stg
@@ -1,4 +1,4 @@
-group BundleSqlDao: EntitySqlDao;
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "bundles"
 
@@ -32,7 +32,7 @@ last_sys_update_date = :lastSysUpdateDate
 , updated_by = :createdBy
 , updated_date = :updatedDate
 where id = :id
-<AND_CHECK_TENANT()>
+<AND_CHECK_TENANT("")>
 ;
 >>
 
@@ -43,38 +43,38 @@ external_key = :externalKey
 , updated_by = :createdBy
 , updated_date = :updatedDate
 where id = :id
-<AND_CHECK_TENANT()>
+<AND_CHECK_TENANT("")>
 ;
 >>
 
 getBundlesForKey() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 from bundles
 where
 external_key = :externalKey
-<AND_CHECK_TENANT()>
-<defaultOrderBy()>
+<AND_CHECK_TENANT("")>
+<defaultOrderBy("")>
 ;
 >>
 
 getBundlesFromAccountAndKey() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 from bundles
 where
 external_key = :externalKey
 and account_id = :accountId
-<AND_CHECK_TENANT()>
-<defaultOrderBy()>
+<AND_CHECK_TENANT("")>
+<defaultOrderBy("")>
 ;
 >>
 
 getBundleFromAccount() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 from bundles
 where
 account_id = :accountId
-<AND_CHECK_TENANT()>
-<defaultOrderBy()>
+<AND_CHECK_TENANT("")>
+<defaultOrderBy("")>
 ;
 >>
 
diff --git a/subscription/src/main/resources/org/killbill/billing/subscription/engine/dao/SubscriptionEventSqlDao.sql.stg b/subscription/src/main/resources/org/killbill/billing/subscription/engine/dao/SubscriptionEventSqlDao.sql.stg
index cfb3ec4..94d407f 100644
--- a/subscription/src/main/resources/org/killbill/billing/subscription/engine/dao/SubscriptionEventSqlDao.sql.stg
+++ b/subscription/src/main/resources/org/killbill/billing/subscription/engine/dao/SubscriptionEventSqlDao.sql.stg
@@ -1,4 +1,4 @@
-group EventSqlDao: EntitySqlDao;
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "subscription_events"
 
@@ -53,59 +53,59 @@ is_active = false
 , updated_date = :updatedDate
 where
 id = :id
-<AND_CHECK_TENANT()>
+<AND_CHECK_TENANT("")>
 ;
 >>
 
 getFutureActiveEventForSubscription() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 , record_id as total_ordering
 from <tableName()>
 where
 subscription_id = :subscriptionId
 and is_active = true
 and effective_date > :now
-<AND_CHECK_TENANT()>
-<defaultOrderBy()>
+<AND_CHECK_TENANT("")>
+<defaultOrderBy("")>
 ;
 >>
 
 
 getFutureOrPresentActiveEventForSubscription() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 , record_id as total_ordering
 from <tableName()>
 where
 subscription_id = :subscriptionId
 and is_active = true
 and effective_date >= :now
-<AND_CHECK_TENANT()>
-<defaultOrderBy()>
+<AND_CHECK_TENANT("")>
+<defaultOrderBy("")>
 ;
 >>
 
 getActiveEventsForSubscription() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 , record_id as total_ordering
 from <tableName()>
 where
 subscription_id = :subscriptionId
 and is_active = true
-<AND_CHECK_TENANT()>
-<defaultOrderBy()>
+<AND_CHECK_TENANT("")>
+<defaultOrderBy("")>
 ;
 >>
 
 getFutureActiveEventsForAccount() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 , record_id as total_ordering
 from <tableName()>
 where
 account_record_id = :accountRecordId
 and is_active = true
 and effective_date > :now
-<AND_CHECK_TENANT()>
-<defaultOrderBy()>
+<AND_CHECK_TENANT("")>
+<defaultOrderBy("")>
 ;
 >>
 
diff --git a/subscription/src/main/resources/org/killbill/billing/subscription/engine/dao/SubscriptionSqlDao.sql.stg b/subscription/src/main/resources/org/killbill/billing/subscription/engine/dao/SubscriptionSqlDao.sql.stg
index 47ae310..3f9388d 100644
--- a/subscription/src/main/resources/org/killbill/billing/subscription/engine/dao/SubscriptionSqlDao.sql.stg
+++ b/subscription/src/main/resources/org/killbill/billing/subscription/engine/dao/SubscriptionSqlDao.sql.stg
@@ -1,4 +1,4 @@
-group SubscriptionSqlDao: EntitySqlDao;
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "subscriptions"
 
@@ -31,11 +31,11 @@ tableValues() ::= <<
 
 getSubscriptionsFromBundleId() ::= <<
 select
-<allTableFields()>
+<allTableFields("")>
 from <tableName()>
 where bundle_id = :bundleId
-<AND_CHECK_TENANT()>
-<defaultOrderBy()>
+<AND_CHECK_TENANT("")>
+<defaultOrderBy("")>
 ;
 >>
 
@@ -46,6 +46,6 @@ charged_through_date = :chargedThroughDate
 , updated_by = :createdBy
 , updated_date = :updatedDate
 where id = :id
-<AND_CHECK_TENANT()>
+<AND_CHECK_TENANT("")>
 ;
 >>

tenant/pom.xml 2(+1 -1)

diff --git a/tenant/pom.xml b/tenant/pom.xml
index 644a027..103d84f 100644
--- a/tenant/pom.xml
+++ b/tenant/pom.xml
@@ -74,7 +74,7 @@
         </dependency>
         <dependency>
             <groupId>org.antlr</groupId>
-            <artifactId>stringtemplate</artifactId>
+            <artifactId>ST4</artifactId>
             <scope>runtime</scope>
         </dependency>
         <dependency>
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/dao/TenantBroadcastSqlDao.java b/tenant/src/main/java/org/killbill/billing/tenant/dao/TenantBroadcastSqlDao.java
index 1925151..281d07c 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/dao/TenantBroadcastSqlDao.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/dao/TenantBroadcastSqlDao.java
@@ -21,11 +21,11 @@ import java.util.List;
 
 import org.killbill.billing.util.entity.Entity;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface TenantBroadcastSqlDao extends EntitySqlDao<TenantBroadcastModelDao, Entity> {
 
     @SqlQuery
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/dao/TenantKVSqlDao.java b/tenant/src/main/java/org/killbill/billing/tenant/dao/TenantKVSqlDao.java
index c0cac34..fe99bea 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/dao/TenantKVSqlDao.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/dao/TenantKVSqlDao.java
@@ -24,32 +24,32 @@ import org.killbill.billing.tenant.api.TenantKV;
 import org.killbill.billing.util.audit.ChangeType;
 import org.killbill.billing.util.entity.dao.Audited;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface TenantKVSqlDao extends EntitySqlDao<TenantKVModelDao, TenantKV> {
 
     @SqlQuery
     public List<TenantKVModelDao> getTenantValueForKey(@Bind("tenantKey") final String key,
-                                                       @BindBean final InternalTenantContext context);
+                                                       @SmartBindBean final InternalTenantContext context);
 
 
     @SqlQuery
     public List<TenantKVModelDao> searchTenantKeyValues(@Bind("tenantKeyPrefix") final String tenantKeyPrefix,
-                                                       @BindBean final InternalTenantContext context);
+                                                       @SmartBindBean final InternalTenantContext context);
 
     @SqlUpdate
     @Audited(ChangeType.DELETE)
     public void markTenantKeyAsDeleted(@Bind("id")final String id,
-                                       @BindBean final InternalCallContext context);
+                                       @SmartBindBean final InternalCallContext context);
 
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
     public Object updateTenantValueKey(@Bind("id") final String id,
                                        @Bind("tenantValue") final String tenantValue,
-                                       @BindBean final InternalCallContext context);
+                                       @SmartBindBean final InternalCallContext context);
 }
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/dao/TenantSqlDao.java b/tenant/src/main/java/org/killbill/billing/tenant/dao/TenantSqlDao.java
index cf97271..ab4ded9 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/dao/TenantSqlDao.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/dao/TenantSqlDao.java
@@ -24,9 +24,9 @@ import org.skife.jdbi.v2.sqlobject.SqlQuery;
 
 import org.killbill.billing.tenant.api.Tenant;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface TenantSqlDao extends EntitySqlDao<TenantModelDao, Tenant> {
 
     @SqlQuery
diff --git a/tenant/src/main/resources/org/killbill/billing/tenant/dao/TenantBroadcastSqlDao.sql.stg b/tenant/src/main/resources/org/killbill/billing/tenant/dao/TenantBroadcastSqlDao.sql.stg
index b0e5bc3..b843665 100644
--- a/tenant/src/main/resources/org/killbill/billing/tenant/dao/TenantBroadcastSqlDao.sql.stg
+++ b/tenant/src/main/resources/org/killbill/billing/tenant/dao/TenantBroadcastSqlDao.sql.stg
@@ -1,4 +1,4 @@
-group TenantBroadcastSqlDao: EntitySqlDao;
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "tenant_broadcasts"
 
@@ -26,7 +26,7 @@ tableValues() ::= <<
 
 /* No account_record_id field */
 accountRecordIdFieldWithComma(prefix) ::= ""
-accountRecordIdValueWithComma(prefix) ::= ""
+accountRecordIdValueWithComma() ::= ""
 
 
 getLatestEntries() ::= <<
diff --git a/tenant/src/main/resources/org/killbill/billing/tenant/dao/TenantKVSqlDao.sql.stg b/tenant/src/main/resources/org/killbill/billing/tenant/dao/TenantKVSqlDao.sql.stg
index 9495969..19cfb11 100644
--- a/tenant/src/main/resources/org/killbill/billing/tenant/dao/TenantKVSqlDao.sql.stg
+++ b/tenant/src/main/resources/org/killbill/billing/tenant/dao/TenantKVSqlDao.sql.stg
@@ -1,4 +1,4 @@
-group TenantKVSqlDao: EntitySqlDao;
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "tenant_kvs"
 
diff --git a/tenant/src/main/resources/org/killbill/billing/tenant/dao/TenantSqlDao.sql.stg b/tenant/src/main/resources/org/killbill/billing/tenant/dao/TenantSqlDao.sql.stg
index 56c8986..25cfc6f 100644
--- a/tenant/src/main/resources/org/killbill/billing/tenant/dao/TenantSqlDao.sql.stg
+++ b/tenant/src/main/resources/org/killbill/billing/tenant/dao/TenantSqlDao.sql.stg
@@ -1,4 +1,4 @@
-group TenantDaoSql: EntitySqlDao;
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "tenants"
 
@@ -23,7 +23,7 @@ tableValues() ::= <<
 
 /* No account_record_id field */
 accountRecordIdFieldWithComma(prefix) ::= ""
-accountRecordIdValueWithComma(prefix) ::= ""
+accountRecordIdValueWithComma() ::= ""
 
 /* No tenant_record_id field */
 tenantRecordIdFieldWithComma(prefix) ::= ""
@@ -33,8 +33,8 @@ CHECK_TENANT(prefix) ::= "1 = 1"
 /* Override default create call to include secrets */
 create() ::= <<
 insert into <tableName()> (
-  <idField()>
-, <tableFields()>
+  <idField("")>
+, <tableFields("")>
 , api_secret
 , api_salt
 )

usage/pom.xml 2(+1 -1)

diff --git a/usage/pom.xml b/usage/pom.xml
index 25c9467..8cc8fdf 100644
--- a/usage/pom.xml
+++ b/usage/pom.xml
@@ -70,7 +70,7 @@
         </dependency>
         <dependency>
             <groupId>org.antlr</groupId>
-            <artifactId>stringtemplate</artifactId>
+            <artifactId>ST4</artifactId>
             <scope>runtime</scope>
         </dependency>
         <dependency>
diff --git a/usage/src/main/java/org/killbill/billing/usage/dao/RolledUpUsageSqlDao.java b/usage/src/main/java/org/killbill/billing/usage/dao/RolledUpUsageSqlDao.java
index 89fc3a2..e947fa5 100644
--- a/usage/src/main/java/org/killbill/billing/usage/dao/RolledUpUsageSqlDao.java
+++ b/usage/src/main/java/org/killbill/billing/usage/dao/RolledUpUsageSqlDao.java
@@ -27,17 +27,17 @@ import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.util.callcontext.InternalTenantContextBinder;
 import org.killbill.billing.util.entity.Entity;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.SqlBatch;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface RolledUpUsageSqlDao extends EntitySqlDao<RolledUpUsageModelDao, Entity> {
 
     @SqlBatch
-    void create(@BindBean Iterable<RolledUpUsageModelDao> usages,
+    void create(@SmartBindBean Iterable<RolledUpUsageModelDao> usages,
                 @InternalTenantContextBinder final InternalCallContext context);
 
     @SqlQuery
diff --git a/usage/src/main/resources/org/killbill/billing/usage/dao/RolledUpUsageSqlDao.sql.stg b/usage/src/main/resources/org/killbill/billing/usage/dao/RolledUpUsageSqlDao.sql.stg
index b1d739c..44db9b9 100644
--- a/usage/src/main/resources/org/killbill/billing/usage/dao/RolledUpUsageSqlDao.sql.stg
+++ b/usage/src/main/resources/org/killbill/billing/usage/dao/RolledUpUsageSqlDao.sql.stg
@@ -1,4 +1,4 @@
-group RolledUpUsageSqlDao : EntitySqlDao;
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "rolled_up_usage"
 
@@ -29,45 +29,45 @@ select
 from <tableName()>
 where subscription_id = :subscriptionId
 and tracking_id = :trackingId
-<AND_CHECK_TENANT()>
+<AND_CHECK_TENANT("")>
 limit 1
 ;
 >>
 
 getUsageForSubscription() ::= <<
 select
-  <allTableFields()>
+  <allTableFields("")>
 from <tableName()>
 where subscription_id = :subscriptionId
 and record_date >= :startDate
 and record_date \< :endDate
 and unit_type = :unitType
-<AND_CHECK_TENANT()>
-<defaultOrderBy()>
+<AND_CHECK_TENANT("")>
+<defaultOrderBy("")>
 ;
 >>
 
 getAllUsageForSubscription() ::= <<
 select
-  <allTableFields()>
+  <allTableFields("")>
 from <tableName()>
 where subscription_id = :subscriptionId
 and record_date >= :startDate
 and record_date \< :endDate
-<AND_CHECK_TENANT()>
-<defaultOrderBy()>
+<AND_CHECK_TENANT("")>
+<defaultOrderBy("")>
 ;
 >>
 
 getRawUsageForAccount() ::= <<
 select
-  <allTableFields()>
+  <allTableFields("")>
 from <tableName()>
 where account_record_id = :accountRecordId
 and record_date >= :startDate
 and record_date \< :endDate
-<AND_CHECK_TENANT()>
-<defaultOrderBy()>
+<AND_CHECK_TENANT("")>
+<defaultOrderBy("")>
 ;
 >>
 

util/pom.xml 11(+10 -1)

diff --git a/util/pom.xml b/util/pom.xml
index 6f3e019..6a5ed2c 100644
--- a/util/pom.xml
+++ b/util/pom.xml
@@ -74,6 +74,11 @@
             <artifactId>guice-multibindings</artifactId>
         </dependency>
         <dependency>
+            <groupId>com.ning</groupId>
+            <artifactId>compress-lzf</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>com.samskivert</groupId>
             <artifactId>jmustache</artifactId>
         </dependency>
@@ -130,7 +135,7 @@
         </dependency>
         <dependency>
             <groupId>org.antlr</groupId>
-            <artifactId>stringtemplate</artifactId>
+            <artifactId>ST4</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>
@@ -191,6 +196,10 @@
         </dependency>
         <dependency>
             <groupId>org.kill-bill.billing</groupId>
+            <artifactId>killbill-platform-lifecycle</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.kill-bill.billing</groupId>
             <artifactId>killbill-platform-osgi</artifactId>
         </dependency>
         <dependency>
diff --git a/util/src/main/java/org/killbill/billing/util/broadcast/dao/BroadcastSqlDao.java b/util/src/main/java/org/killbill/billing/util/broadcast/dao/BroadcastSqlDao.java
index 9efa110..fb6e7a5 100644
--- a/util/src/main/java/org/killbill/billing/util/broadcast/dao/BroadcastSqlDao.java
+++ b/util/src/main/java/org/killbill/billing/util/broadcast/dao/BroadcastSqlDao.java
@@ -19,17 +19,17 @@ package org.killbill.billing.util.broadcast.dao;
 
 import java.util.List;
 
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface BroadcastSqlDao {
 
     @SqlUpdate
-    public void create(@BindBean final BroadcastModelDao broadcastModelDao);
+    public void create(@SmartBindBean final BroadcastModelDao broadcastModelDao);
 
     @SqlQuery
     public List<BroadcastModelDao> getLatestEntries(@Bind("recordId") final Long recordId);
diff --git a/util/src/main/java/org/killbill/billing/util/broadcast/dao/DefaultBroadcastDao.java b/util/src/main/java/org/killbill/billing/util/broadcast/dao/DefaultBroadcastDao.java
index 6d7f32a..8ceda0e 100644
--- a/util/src/main/java/org/killbill/billing/util/broadcast/dao/DefaultBroadcastDao.java
+++ b/util/src/main/java/org/killbill/billing/util/broadcast/dao/DefaultBroadcastDao.java
@@ -39,8 +39,6 @@ public class DefaultBroadcastDao implements BroadcastDao {
     public DefaultBroadcastDao(final IDBI dbi, final Clock clock) {
         this.dbi = dbi;
         this.clock = clock;
-        ((DBI) dbi).registerMapper(new LowerToCamelBeanMapperFactory(BroadcastModelDao.class));
-
     }
 
     @Override
diff --git a/util/src/main/java/org/killbill/billing/util/customfield/dao/CustomFieldSqlDao.java b/util/src/main/java/org/killbill/billing/util/customfield/dao/CustomFieldSqlDao.java
index 53e589e..f75fd4b 100644
--- a/util/src/main/java/org/killbill/billing/util/customfield/dao/CustomFieldSqlDao.java
+++ b/util/src/main/java/org/killbill/billing/util/customfield/dao/CustomFieldSqlDao.java
@@ -20,7 +20,7 @@ import java.util.List;
 import java.util.UUID;
 
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 
@@ -31,18 +31,18 @@ import org.killbill.billing.util.audit.ChangeType;
 import org.killbill.billing.util.customfield.CustomField;
 import org.killbill.billing.util.entity.dao.Audited;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface CustomFieldSqlDao extends EntitySqlDao<CustomFieldModelDao, CustomField> {
 
     @SqlUpdate
     @Audited(ChangeType.DELETE)
     void markTagAsDeleted(@Bind("id") String customFieldId,
-                          @BindBean InternalCallContext context);
+                          @SmartBindBean InternalCallContext context);
 
     @SqlQuery
     List<CustomFieldModelDao> getCustomFieldsForObject(@Bind("objectId") UUID objectId,
                                                        @Bind("objectType") ObjectType objectType,
-                                                       @BindBean InternalTenantContext internalTenantContext);
+                                                       @SmartBindBean InternalTenantContext internalTenantContext);
 }
diff --git a/util/src/main/java/org/killbill/billing/util/dao/AuditSqlDao.java b/util/src/main/java/org/killbill/billing/util/dao/AuditSqlDao.java
index 7ca13e0..e9cf5b8 100644
--- a/util/src/main/java/org/killbill/billing/util/dao/AuditSqlDao.java
+++ b/util/src/main/java/org/killbill/billing/util/dao/AuditSqlDao.java
@@ -21,8 +21,9 @@ package org.killbill.billing.util.dao;
 import java.util.Iterator;
 import java.util.List;
 
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.customizers.Define;
@@ -34,7 +35,6 @@ import org.killbill.billing.util.audit.dao.AuditLogModelDao;
 import org.killbill.billing.util.cache.Cachable;
 import org.killbill.billing.util.cache.Cachable.CacheType;
 import org.killbill.billing.util.cache.CachableKey;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
 
 /**
  * Note 1: cache invalidation has to happen for audit logs (which is tricky in the multi-nodes scenario).
@@ -45,33 +45,33 @@ import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
  * <p/>
  * Note 2: in the queries below, tableName always refers to the TableName enum, not the actual table name (TableName.getTableName()).
  */
-@EntitySqlDaoStringTemplate("/org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg")
+@KillBillSqlDaoStringTemplate("/org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg")
 // Note: @RegisterMapper annotation won't work here as we build the SqlObject via EntitySqlDao (annotations won't be inherited for JDBI)
 public interface AuditSqlDao {
 
     @SqlUpdate
-    public void insertAuditFromTransaction(@BindBean final EntityAudit audit,
-                                           @BindBean final InternalCallContext context);
+    public void insertAuditFromTransaction(@SmartBindBean final EntityAudit audit,
+                                           @SmartBindBean final InternalCallContext context);
 
     @SqlQuery
     @SmartFetchSize(shouldStream = true)
-    public Iterator<AuditLogModelDao> getAuditLogsForAccountRecordId(@BindBean final InternalTenantContext context);
+    public Iterator<AuditLogModelDao> getAuditLogsForAccountRecordId(@SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     @SmartFetchSize(shouldStream = true)
     public Iterator<AuditLogModelDao> getAuditLogsForTableNameAndAccountRecordId(@Bind("tableName") final String tableName,
-                                                                                 @BindBean final InternalTenantContext context);
+                                                                                 @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     @Cachable(CacheType.AUDIT_LOG)
     public List<AuditLogModelDao> getAuditLogsForTargetRecordId(@CachableKey(1) @Bind("tableName") final String tableName,
                                                                 @CachableKey(2) @Bind("targetRecordId") final long targetRecordId,
-                                                                @BindBean final InternalTenantContext context);
+                                                                @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     @Cachable(CacheType.AUDIT_LOG_VIA_HISTORY)
     public List<AuditLogModelDao> getAuditLogsViaHistoryForTargetRecordId(@CachableKey(1) @Bind("tableName") final String historyTableName, /* Uppercased - used to find entries in audit_log table */
                                                                           @CachableKey(2) @Define("historyTableName") final String actualHistoryTableName, /* Actual table name, used in the inner join query */
                                                                           @CachableKey(3) @Bind("targetRecordId") final long targetRecordId,
-                                                                          @BindBean final InternalTenantContext context);
+                                                                          @SmartBindBean final InternalTenantContext context);
 }
diff --git a/util/src/main/java/org/killbill/billing/util/dao/EntityHistoryBinder.java b/util/src/main/java/org/killbill/billing/util/dao/EntityHistoryBinder.java
index e5afcf6..42d7ceb 100644
--- a/util/src/main/java/org/killbill/billing/util/dao/EntityHistoryBinder.java
+++ b/util/src/main/java/org/killbill/billing/util/dao/EntityHistoryBinder.java
@@ -53,7 +53,7 @@ public @interface EntityHistoryBinder {
                 @Override
                 public void bind(final SQLStatement<?> q, final EntityHistoryBinder bind, final EntityHistoryModelDao<M, E> history) {
                     try {
-                        // Emulate @BindBean
+                        // Emulate @SmartBindBean
                         final M arg = history.getEntity();
                         final BeanInfo infos = Introspector.getBeanInfo(arg.getClass());
                         final PropertyDescriptor[] props = infos.getPropertyDescriptors();
diff --git a/util/src/main/java/org/killbill/billing/util/dao/HistorySqlDao.java b/util/src/main/java/org/killbill/billing/util/dao/HistorySqlDao.java
index 5f6d2d1..e1f7cee 100644
--- a/util/src/main/java/org/killbill/billing/util/dao/HistorySqlDao.java
+++ b/util/src/main/java/org/killbill/billing/util/dao/HistorySqlDao.java
@@ -24,7 +24,7 @@ import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.util.entity.Entity;
 import org.killbill.billing.util.entity.dao.EntityModelDao;
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.GetGeneratedKeys;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
@@ -33,9 +33,9 @@ public interface HistorySqlDao<M extends EntityModelDao<E>, E extends Entity> {
 
     @SqlQuery
     public List<EntityHistoryModelDao<M, E>> getHistoryForTargetRecordId(@Bind("targetRecordId") final long targetRecordId,
-                                                                         @BindBean InternalCallContext context);
+                                                                         @SmartBindBean InternalCallContext context);
     @SqlUpdate
     @GetGeneratedKeys
     public Long addHistoryFromTransaction(@EntityHistoryBinder EntityHistoryModelDao<M, E> history,
-                                          @BindBean InternalCallContext context);
+                                          @SmartBindBean InternalCallContext context);
 }
diff --git a/util/src/main/java/org/killbill/billing/util/dao/NonEntitySqlDao.java b/util/src/main/java/org/killbill/billing/util/dao/NonEntitySqlDao.java
index 798b334..650f052 100644
--- a/util/src/main/java/org/killbill/billing/util/dao/NonEntitySqlDao.java
+++ b/util/src/main/java/org/killbill/billing/util/dao/NonEntitySqlDao.java
@@ -21,15 +21,15 @@ package org.killbill.billing.util.dao;
 import java.util.UUID;
 
 import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.customizers.Define;
 import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
 import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface NonEntitySqlDao extends Transactional<NonEntitySqlDao>, CloseMe {
 
     @SqlQuery
@@ -62,19 +62,19 @@ public interface NonEntitySqlDao extends Transactional<NonEntitySqlDao>, CloseMe
     @SqlQuery
     public Iterable<RecordIdIdMappings> getHistoryRecordIdIdMappings(@Define("tableName") String tableName,
                                                                      @Define("historyTableName") String historyTableName,
-                                                                     @BindBean final InternalTenantContext context);
+                                                                     @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     public Iterable<RecordIdIdMappings> getHistoryRecordIdIdMappingsForAccountsTable(@Define("tableName") String tableName,
                                                                                      @Define("historyTableName") String historyTableName,
-                                                                                     @BindBean final InternalTenantContext context);
+                                                                                     @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     public Iterable<RecordIdIdMappings> getHistoryRecordIdIdMappingsForTablesWithoutAccountRecordId(@Define("tableName") String tableName,
                                                                                                     @Define("historyTableName") String historyTableName,
-                                                                                                    @BindBean final InternalTenantContext context);
+                                                                                                    @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     public Iterable<RecordIdIdMappings> getRecordIdIdMappings(@Define("tableName") String tableName,
-                                                              @BindBean final InternalTenantContext context);
+                                                              @SmartBindBean final InternalTenantContext context);
 }
diff --git a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDao.java b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDao.java
index ede762c..a4ddb91 100644
--- a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDao.java
+++ b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDao.java
@@ -32,40 +32,41 @@ import org.killbill.billing.util.dao.AuditSqlDao;
 import org.killbill.billing.util.dao.HistorySqlDao;
 import org.killbill.billing.util.entity.Entity;
 import org.killbill.commons.jdbi.statement.SmartFetchSize;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.customizers.Define;
 import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
 import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface EntitySqlDao<M extends EntityModelDao<E>, E extends Entity> extends AuditSqlDao, HistorySqlDao<M, E>, Transactional<EntitySqlDao<M, E>>, CloseMe {
 
     @SqlUpdate
     @Audited(ChangeType.INSERT)
-    public Object create(@BindBean final M entity,
-                         @BindBean final InternalCallContext context) throws EntityPersistenceException;
+    public Object create(@SmartBindBean final M entity,
+                         @SmartBindBean final InternalCallContext context) throws EntityPersistenceException;
 
     @SqlQuery
     public M getById(@Bind("id") final String id,
-                     @BindBean final InternalTenantContext context);
+                     @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     public M getByRecordId(@Bind("recordId") final Long recordId,
-                           @BindBean final InternalTenantContext context);
+                           @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
-    public List<M> getByAccountRecordId(@BindBean final InternalTenantContext context);
+    public List<M> getByAccountRecordId(@SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
-    public List<M> getByAccountRecordIdIncludedDeleted(@BindBean final InternalTenantContext context);
+    public List<M> getByAccountRecordIdIncludedDeleted(@SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     @Cachable(CacheType.RECORD_ID)
     public Long getRecordId(@CachableKey(1) @Bind("id") final String id,
-                            @BindBean final InternalTenantContext context);
+                            @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     @SmartFetchSize(shouldStream = true)
@@ -74,16 +75,16 @@ public interface EntitySqlDao<M extends EntityModelDao<E>, E extends Entity> ext
                               @Bind("offset") final Long offset,
                               @Bind("rowCount") final Long rowCount,
                               @Define("ordering") final String ordering,
-                              @BindBean final InternalTenantContext context);
+                              @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     public Long getSearchCount(@Bind("searchKey") final String searchKey,
                                @Bind("likeSearchKey") final String likeSearchKey,
-                               @BindBean final InternalTenantContext context);
+                               @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     @SmartFetchSize(shouldStream = true)
-    public Iterator<M> getAll(@BindBean final InternalTenantContext context);
+    public Iterator<M> getAll(@SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
     @SmartFetchSize(shouldStream = true)
@@ -91,11 +92,11 @@ public interface EntitySqlDao<M extends EntityModelDao<E>, E extends Entity> ext
                            @Bind("rowCount") final Long rowCount,
                            @Define("orderBy") final String orderBy,
                            @Define("ordering") final String ordering,
-                           @BindBean final InternalTenantContext context);
+                           @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
-    public Long getCount(@BindBean final InternalTenantContext context);
+    public Long getCount(@SmartBindBean final InternalTenantContext context);
 
     @SqlUpdate
-    public void test(@BindBean final InternalTenantContext context);
+    public void test(@SmartBindBean final InternalTenantContext context);
 }
diff --git a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
index 654d0da..f6ba247 100644
--- a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
+++ b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
@@ -32,6 +32,7 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
 
 import javax.annotation.Nullable;
 
@@ -51,7 +52,6 @@ import org.killbill.billing.util.dao.EntityHistoryModelDao;
 import org.killbill.billing.util.dao.NonEntityDao;
 import org.killbill.billing.util.dao.TableName;
 import org.killbill.billing.util.entity.Entity;
-import org.killbill.billing.util.tag.dao.UUIDCollectionBinder;
 import org.killbill.clock.Clock;
 import org.killbill.commons.profiling.Profiling;
 import org.killbill.commons.profiling.Profiling.WithProfilingCallback;
@@ -62,6 +62,7 @@ import org.skife.jdbi.v2.StatementContext;
 import org.skife.jdbi.v2.exceptions.DBIException;
 import org.skife.jdbi.v2.exceptions.StatementException;
 import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.unstable.BindIn;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -84,6 +85,8 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>, 
 
     private final Logger logger = LoggerFactory.getLogger(EntitySqlDaoWrapperInvocationHandler.class);
 
+    private final Map<String, Annotation[][]> parameterAnnotationsByMethod = new ConcurrentHashMap<String, Annotation[][]>();
+
     private final Class<S> sqlDaoClass;
     private final S sqlDao;
     private final Handle handle;
@@ -227,7 +230,7 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>, 
         if (cache != null && objectType != null) {
             // Find all arguments marked with @CachableKey
             final Map<Integer, Object> keyPieces = new LinkedHashMap<Integer, Object>();
-            final Annotation[][] annotations = method.getParameterAnnotations();
+            final Annotation[][] annotations = getAnnotations(method);
             for (int i = 0; i < annotations.length; i++) {
                 for (int j = 0; j < annotations[i].length; j++) {
                     final Annotation annotation = annotations[i][j];
@@ -408,7 +411,8 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>, 
     }
 
     private List<String> retrieveEntityIdsFromArguments(final Method method, final Object[] args) {
-        final Annotation[][] parameterAnnotations = method.getParameterAnnotations();
+        final Annotation[][] parameterAnnotations = getAnnotations(method);
+
         int i = -1;
         for (final Object arg : args) {
             i++;
@@ -430,7 +434,7 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>, 
             for (final Annotation annotation : parameterAnnotations[i]) {
                 if (arg instanceof String && Bind.class.equals(annotation.annotationType()) && ("id").equals(((Bind) annotation).value())) {
                     return ImmutableList.<String>of((String) arg);
-                } else if (arg instanceof Collection && UUIDCollectionBinder.class.equals(annotation.annotationType())) {
+                } else if (arg instanceof Collection && BindIn.class.equals(annotation.annotationType()) && ("ids").equals(((BindIn) annotation).value())) {
                     return ImmutableList.<String>copyOf((Collection) arg);
                 }
             }
@@ -438,6 +442,19 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>, 
         return ImmutableList.<String>of();
     }
 
+    private Annotation[][] getAnnotations(final Method method) {
+        // Expensive to compute
+        final String methodString = method.toString();
+
+        // Method.getParameterAnnotations() generates lots of garbage objects
+        Annotation[][] parameterAnnotations = parameterAnnotationsByMethod.get(methodString);
+        if (parameterAnnotations == null) {
+            parameterAnnotations = method.getParameterAnnotations();
+            parameterAnnotationsByMethod.put(methodString, parameterAnnotations);
+        }
+        return parameterAnnotations;
+    }
+
     private Builder<String> extractEntityIdsFromBatchArgument(final Iterable arg) {
         final Iterator iterator = arg.iterator();
         final Builder<String> entityIds = new Builder<String>();
diff --git a/util/src/main/java/org/killbill/billing/util/export/dao/DatabaseExportDao.java b/util/src/main/java/org/killbill/billing/util/export/dao/DatabaseExportDao.java
index 1f37627..0f99263 100644
--- a/util/src/main/java/org/killbill/billing/util/export/dao/DatabaseExportDao.java
+++ b/util/src/main/java/org/killbill/billing/util/export/dao/DatabaseExportDao.java
@@ -16,6 +16,7 @@
 
 package org.killbill.billing.util.export.dao;
 
+import java.sql.Blob;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -160,6 +161,17 @@ public class DatabaseExportDao {
                 try {
                     while (iterator.hasNext()) {
                         final Map<String, Object> row = iterator.next();
+
+                        for (final String k : row.keySet()) {
+                            final Object value = row.get(k);
+                            // For h2, transform a JdbcBlob into a byte[]
+                            // See also LowerToCamelBeanMapper
+                            if (value instanceof Blob) {
+                                final Blob blob = (Blob) value;
+                                row.put(k, blob.getBytes(0, (int) blob.length()));
+                            }
+                        }
+
                         out.write(row);
                     }
                 } finally {
diff --git a/util/src/main/java/org/killbill/billing/util/glue/IDBISetup.java b/util/src/main/java/org/killbill/billing/util/glue/IDBISetup.java
new file mode 100644
index 0000000..0e78d66
--- /dev/null
+++ b/util/src/main/java/org/killbill/billing/util/glue/IDBISetup.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.util.glue;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.List;
+
+import org.killbill.billing.lifecycle.ServiceFinder;
+import org.killbill.billing.util.broadcast.dao.BroadcastModelDao;
+import org.killbill.billing.util.dao.AuditLogModelDaoMapper;
+import org.killbill.billing.util.dao.EntityHistoryModelDaoMapperFactory;
+import org.killbill.billing.util.dao.RecordIdIdMappingsMapper;
+import org.killbill.billing.util.entity.Entity;
+import org.killbill.billing.util.entity.dao.EntitySqlDao;
+import org.killbill.billing.util.nodes.dao.NodeInfoModelDao;
+import org.killbill.billing.util.security.shiro.dao.RolesPermissionsModelDao;
+import org.killbill.billing.util.security.shiro.dao.SessionModelDao;
+import org.killbill.billing.util.security.shiro.dao.UserModelDao;
+import org.killbill.billing.util.security.shiro.dao.UserRolesModelDao;
+import org.killbill.billing.util.validation.dao.DatabaseSchemaSqlDao;
+import org.killbill.bus.dao.BusEventModelDao;
+import org.killbill.commons.jdbi.mapper.LowerToCamelBeanMapperFactory;
+import org.killbill.notificationq.dao.NotificationEventModelDao;
+import org.skife.jdbi.v2.ResultSetMapperFactory;
+import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
+import org.skife.jdbi.v2.tweak.ResultSetMapper;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+
+public class IDBISetup {
+
+    public static List<? extends ResultSetMapperFactory> mapperFactoriesToRegister() {
+        final Builder<ResultSetMapperFactory> builder = ImmutableList.<ResultSetMapperFactory>builder();
+        builder.add(new LowerToCamelBeanMapperFactory(SessionModelDao.class));
+        builder.add(new LowerToCamelBeanMapperFactory(BroadcastModelDao.class));
+        builder.add(new LowerToCamelBeanMapperFactory(NodeInfoModelDao.class));
+        builder.add(new LowerToCamelBeanMapperFactory(UserModelDao.class));
+        builder.add(new LowerToCamelBeanMapperFactory(UserRolesModelDao.class));
+        builder.add(new LowerToCamelBeanMapperFactory(RolesPermissionsModelDao.class));
+        builder.add(new LowerToCamelBeanMapperFactory(BusEventModelDao.class));
+        builder.add(new LowerToCamelBeanMapperFactory(NotificationEventModelDao.class));
+
+        final ServiceFinder<EntitySqlDao> serviceFinder = new ServiceFinder<EntitySqlDao>(IDBISetup.class.getClassLoader(), EntitySqlDao.class.getName());
+        for (final Class<? extends EntitySqlDao> sqlObjectType : serviceFinder.getServices()) {
+            // Find the model class associated with this sqlObjectType (which is a SqlDao class) to register its mapper
+            // If a custom mapper is defined via @RegisterMapper, don't register our generic one
+            if (sqlObjectType.getGenericInterfaces() != null &&
+                sqlObjectType.getAnnotation(RegisterMapper.class) == null) {
+                for (int i = 0; i < sqlObjectType.getGenericInterfaces().length; i++) {
+                    if (sqlObjectType.getGenericInterfaces()[i] instanceof ParameterizedType) {
+                        final ParameterizedType type = (ParameterizedType) sqlObjectType.getGenericInterfaces()[i];
+                        for (int j = 0; j < type.getActualTypeArguments().length; j++) {
+                            final Type modelType = type.getActualTypeArguments()[j];
+                            if (modelType instanceof Class) {
+                                final Class modelClazz = (Class) modelType;
+                                if (Entity.class.isAssignableFrom(modelClazz)) {
+                                    builder.add(new LowerToCamelBeanMapperFactory(modelClazz));
+                                    builder.add(new EntityHistoryModelDaoMapperFactory(modelClazz, sqlObjectType));
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return builder.build();
+    }
+
+    public static List<? extends ResultSetMapper> mappersToRegister() {
+        return ImmutableList.<ResultSetMapper>builder()
+                .add(new AuditLogModelDaoMapper())
+                .add(new RecordIdIdMappingsMapper())
+                .add(new DatabaseSchemaSqlDao.ColumnInfoMapper())
+                .build();
+    }
+}
diff --git a/util/src/main/java/org/killbill/billing/util/nodes/dao/DefaultNodeInfoDao.java b/util/src/main/java/org/killbill/billing/util/nodes/dao/DefaultNodeInfoDao.java
index 8d1c264..2c951ba 100644
--- a/util/src/main/java/org/killbill/billing/util/nodes/dao/DefaultNodeInfoDao.java
+++ b/util/src/main/java/org/killbill/billing/util/nodes/dao/DefaultNodeInfoDao.java
@@ -39,8 +39,6 @@ public class DefaultNodeInfoDao implements NodeInfoDao {
     public DefaultNodeInfoDao(final IDBI dbi, final Clock clock) {
         this.dbi = dbi;
         this.clock = clock;
-        ((DBI) dbi).registerMapper(new LowerToCamelBeanMapperFactory(NodeInfoModelDao.class));
-
     }
 
     @Override
diff --git a/util/src/main/java/org/killbill/billing/util/nodes/dao/NodeInfoSqlDao.java b/util/src/main/java/org/killbill/billing/util/nodes/dao/NodeInfoSqlDao.java
index ceedde4..e2be7f8 100644
--- a/util/src/main/java/org/killbill/billing/util/nodes/dao/NodeInfoSqlDao.java
+++ b/util/src/main/java/org/killbill/billing/util/nodes/dao/NodeInfoSqlDao.java
@@ -20,17 +20,17 @@ package org.killbill.billing.util.nodes.dao;
 import java.util.Date;
 import java.util.List;
 
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface NodeInfoSqlDao {
 
     @SqlUpdate
-    public void create(@BindBean final NodeInfoModelDao nodeInfo);
+    public void create(@SmartBindBean final NodeInfoModelDao nodeInfo);
 
     @SqlUpdate
     public void updateNodeInfo(@Bind("nodeName") final String nodeName, @Bind("nodeInfo") final String nodeInfo, @Bind("updatedDate") final Date updatedDate);
diff --git a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/DefaultUserDao.java b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/DefaultUserDao.java
index 7dc71e7..013f859 100644
--- a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/DefaultUserDao.java
+++ b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/DefaultUserDao.java
@@ -54,9 +54,6 @@ public class DefaultUserDao implements UserDao {
         this.dbi = dbi;
         this.clock = clock;
         this.securityConfig = securityConfig;
-        ((DBI) dbi).registerMapper(new LowerToCamelBeanMapperFactory(UserModelDao.class));
-        ((DBI) dbi).registerMapper(new LowerToCamelBeanMapperFactory(UserRolesModelDao.class));
-        ((DBI) dbi).registerMapper(new LowerToCamelBeanMapperFactory(RolesPermissionsModelDao.class));
     }
 
     @Override
diff --git a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/JDBCSessionSqlDao.java b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/JDBCSessionSqlDao.java
index f277430..409f2a3 100644
--- a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/JDBCSessionSqlDao.java
+++ b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/JDBCSessionSqlDao.java
@@ -18,14 +18,14 @@
 
 package org.killbill.billing.util.security.shiro.dao;
 
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface JDBCSessionSqlDao extends Transactional<JDBCSessionSqlDao> {
 
     @SqlQuery
diff --git a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.java b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.java
index 029b268..dccee99 100644
--- a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.java
+++ b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.java
@@ -19,14 +19,14 @@ package org.killbill.billing.util.security.shiro.dao;
 
 import java.util.List;
 
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface RolesPermissionsSqlDao extends Transactional<RolesPermissionsSqlDao> {
 
     @SqlQuery
diff --git a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/UserRolesSqlDao.java b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/UserRolesSqlDao.java
index 8c25d9b..e413146 100644
--- a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/UserRolesSqlDao.java
+++ b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/UserRolesSqlDao.java
@@ -20,14 +20,14 @@ package org.killbill.billing.util.security.shiro.dao;
 import java.util.Date;
 import java.util.List;
 
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface UserRolesSqlDao extends Transactional<UserRolesSqlDao> {
 
     @SqlQuery
diff --git a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/UsersSqlDao.java b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/UsersSqlDao.java
index 6c7cd31..d9c659e 100644
--- a/util/src/main/java/org/killbill/billing/util/security/shiro/dao/UsersSqlDao.java
+++ b/util/src/main/java/org/killbill/billing/util/security/shiro/dao/UsersSqlDao.java
@@ -19,14 +19,14 @@ package org.killbill.billing.util.security.shiro.dao;
 
 import java.util.Date;
 
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface UsersSqlDao extends Transactional<UsersSqlDao> {
 
     @SqlQuery
diff --git a/util/src/main/java/org/killbill/billing/util/tag/dao/TagDefinitionSqlDao.java b/util/src/main/java/org/killbill/billing/util/tag/dao/TagDefinitionSqlDao.java
index 076ef0d..929fa42 100644
--- a/util/src/main/java/org/killbill/billing/util/tag/dao/TagDefinitionSqlDao.java
+++ b/util/src/main/java/org/killbill/billing/util/tag/dao/TagDefinitionSqlDao.java
@@ -1,7 +1,9 @@
 /*
- * Copyright 2010-2011 Ning, Inc.
+ * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
  * License.  You may obtain a copy of the License at:
  *
@@ -19,36 +21,36 @@ package org.killbill.billing.util.tag.dao;
 import java.util.Collection;
 import java.util.List;
 
-import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
-import org.skife.jdbi.v2.sqlobject.SqlQuery;
-import org.skife.jdbi.v2.sqlobject.SqlUpdate;
-
-import org.killbill.billing.util.audit.ChangeType;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.util.audit.ChangeType;
 import org.killbill.billing.util.entity.dao.Audited;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
 import org.killbill.billing.util.tag.TagDefinition;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.unstable.BindIn;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface TagDefinitionSqlDao extends EntitySqlDao<TagDefinitionModelDao, TagDefinition> {
 
     @SqlQuery
     public TagDefinitionModelDao getByName(@Bind("name") final String definitionName,
-                                           @BindBean final InternalTenantContext context);
+                                           @SmartBindBean final InternalTenantContext context);
 
     @SqlUpdate
     @Audited(ChangeType.DELETE)
     public void markTagDefinitionAsDeleted(@Bind("id") final String definitionId,
-                                           @BindBean final InternalCallContext context);
+                                           @SmartBindBean final InternalCallContext context);
 
     @SqlQuery
     public int tagDefinitionUsageCount(@Bind("id") final String definitionId,
-                                       @BindBean final InternalTenantContext context);
+                                       @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
-    public List<TagDefinitionModelDao> getByIds(@UUIDCollectionBinder final Collection<String> definitionIds,
-                                                @BindBean final InternalTenantContext context);
+    public List<TagDefinitionModelDao> getByIds(@BindIn("ids") final Collection<String> definitionIds,
+                                                @SmartBindBean final InternalTenantContext context);
 }
diff --git a/util/src/main/java/org/killbill/billing/util/tag/dao/TagSqlDao.java b/util/src/main/java/org/killbill/billing/util/tag/dao/TagSqlDao.java
index d1f0b67..257d5c3 100644
--- a/util/src/main/java/org/killbill/billing/util/tag/dao/TagSqlDao.java
+++ b/util/src/main/java/org/killbill/billing/util/tag/dao/TagSqlDao.java
@@ -20,7 +20,7 @@ import java.util.List;
 import java.util.UUID;
 
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 
@@ -30,24 +30,24 @@ import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.util.audit.ChangeType;
 import org.killbill.billing.util.entity.dao.Audited;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.killbill.billing.util.tag.Tag;
 
-@EntitySqlDaoStringTemplate
+@KillBillSqlDaoStringTemplate
 public interface TagSqlDao extends EntitySqlDao<TagModelDao, Tag> {
 
     @SqlUpdate
     @Audited(ChangeType.DELETE)
     void markTagAsDeleted(@Bind("id") String tagId,
-                          @BindBean InternalCallContext context);
+                          @SmartBindBean InternalCallContext context);
 
     @SqlQuery
     List<TagModelDao> getTagsForObject(@Bind("objectId") UUID objectId,
                                        @Bind("objectType") ObjectType objectType,
-                                       @BindBean InternalTenantContext internalTenantContext);
+                                       @SmartBindBean InternalTenantContext internalTenantContext);
 
     @SqlQuery
     List<TagModelDao> getTagsForObjectIncludedDeleted(@Bind("objectId") UUID objectId,
                                                       @Bind("objectType") ObjectType objectType,
-                                                      @BindBean InternalTenantContext internalTenantContext);
+                                                      @SmartBindBean InternalTenantContext internalTenantContext);
 }
diff --git a/util/src/main/java/org/killbill/billing/util/validation/dao/DatabaseSchemaSqlDao.java b/util/src/main/java/org/killbill/billing/util/validation/dao/DatabaseSchemaSqlDao.java
index 78e6d0f..aedee08 100644
--- a/util/src/main/java/org/killbill/billing/util/validation/dao/DatabaseSchemaSqlDao.java
+++ b/util/src/main/java/org/killbill/billing/util/validation/dao/DatabaseSchemaSqlDao.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -24,16 +24,14 @@ import java.util.List;
 
 import javax.annotation.Nullable;
 
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.killbill.billing.util.validation.DefaultColumnInfo;
 import org.skife.jdbi.v2.StatementContext;
 import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
-import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
 import org.skife.jdbi.v2.tweak.ResultSetMapper;
 
-@EntitySqlDaoStringTemplate
-@RegisterMapper(DatabaseSchemaSqlDao.ColumnInfoMapper.class)
+@KillBillSqlDaoStringTemplate
 public interface DatabaseSchemaSqlDao {
 
     @SqlQuery
diff --git a/util/src/main/resources/org/killbill/billing/util/broadcast/dao/BroadcastSqlDao.sql.stg b/util/src/main/resources/org/killbill/billing/util/broadcast/dao/BroadcastSqlDao.sql.stg
index 49fa45a..a26bac2 100644
--- a/util/src/main/resources/org/killbill/billing/util/broadcast/dao/BroadcastSqlDao.sql.stg
+++ b/util/src/main/resources/org/killbill/billing/util/broadcast/dao/BroadcastSqlDao.sql.stg
@@ -1,5 +1,3 @@
-group BroadcastSqlDao;
-
 tableName() ::= "service_broadcasts"
 
 
@@ -29,9 +27,13 @@ allTableValues() ::= <<
 , <tableValues()>
 >>
 
+defaultOrderBy(prefix) ::= <<
+order by <prefix>record_id ASC
+>>
+
 create() ::= <<
 insert into <tableName()> (
-<tableFields()>
+<tableFields("")>
 )
 values (
 <tableValues()>
diff --git a/util/src/main/resources/org/killbill/billing/util/customfield/dao/CustomFieldSqlDao.sql.stg b/util/src/main/resources/org/killbill/billing/util/customfield/dao/CustomFieldSqlDao.sql.stg
index af3948a..ca8defa 100644
--- a/util/src/main/resources/org/killbill/billing/util/customfield/dao/CustomFieldSqlDao.sql.stg
+++ b/util/src/main/resources/org/killbill/billing/util/customfield/dao/CustomFieldSqlDao.sql.stg
@@ -1,4 +1,4 @@
-group CustomFieldSqlDao: EntitySqlDao;
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 andCheckSoftDeletionWithComma(prefix) ::= "and <prefix>is_active"
 
@@ -41,14 +41,14 @@ where <idField("")> = :id
 
 getCustomFieldsForObject() ::= <<
 select
-<allTableFields()>
+<allTableFields("")>
 from <tableName()>
 where
 object_id = :objectId
 and object_type = :objectType
 and is_active
-<AND_CHECK_TENANT()>
-<defaultOrderBy()>
+<AND_CHECK_TENANT("")>
+<defaultOrderBy("")>
 ;
 >>
 
diff --git a/util/src/main/resources/org/killbill/billing/util/dao/NonEntitySqlDao.sql.stg b/util/src/main/resources/org/killbill/billing/util/dao/NonEntitySqlDao.sql.stg
index b7e4d4b..6b6972f 100644
--- a/util/src/main/resources/org/killbill/billing/util/dao/NonEntitySqlDao.sql.stg
+++ b/util/src/main/resources/org/killbill/billing/util/dao/NonEntitySqlDao.sql.stg
@@ -1,5 +1,3 @@
-group NonEntitySqlDao;
-
 getRecordIdFromObject(tableName) ::= <<
 select
   record_id
diff --git a/util/src/main/resources/org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg b/util/src/main/resources/org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg
index 2d96592..26faf51 100644
--- a/util/src/main/resources/org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg
+++ b/util/src/main/resources/org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg
@@ -1,6 +1,3 @@
-group EntitySqlDao;
-
-
 /******************   To override in each EntitySqlDao template file *****************************/
 
 tableName() ::= ""
@@ -152,10 +149,10 @@ select
 <allTableFields("t.")>
 from <tableName()> t
 join (
-  select <recordIdField()>
+  select <recordIdField("")>
   from <tableName()>
-  where <CHECK_TENANT()>
-  <andCheckSoftDeletionWithComma()>
+  where <CHECK_TENANT("")>
+  <andCheckSoftDeletionWithComma("")>
   order by <orderBy> <ordering>
   limit :rowCount offset :offset
 ) optimization on <recordIdField("optimization.")> = <recordIdField("t.")>
@@ -292,10 +289,10 @@ where (<searchQuery("t.")>)
 
 create() ::= <<
 insert into <tableName()> (
-  <idField()>
-, <tableFields()>
-<accountRecordIdFieldWithComma()>
-<tenantRecordIdFieldWithComma()>
+  <idField("")>
+, <tableFields("")>
+<accountRecordIdFieldWithComma("")>
+<tenantRecordIdFieldWithComma("")>
 )
 values (
   <idValue()>
@@ -338,7 +335,7 @@ auditTableValues() ::= <<
 
 getHistoryForTargetRecordId() ::= <<
 select
-  <idField()>
+  <idField("")>
 , <historyTableFields("t.")>
 <accountRecordIdFieldWithComma("t.")>
 <tenantRecordIdFieldWithComma("t.")>
@@ -351,10 +348,10 @@ order by <recordIdField("t.")> ASC
 
 addHistoryFromTransaction() ::= <<
 insert into <historyTableName()> (
-  <idField()>
-, <historyTableFields()>
-<accountRecordIdFieldWithComma()>
-<tenantRecordIdFieldWithComma()>
+  <idField("")>
+, <historyTableFields("")>
+<accountRecordIdFieldWithComma("")>
+<tenantRecordIdFieldWithComma("")>
 )
 values (
   <idValue()>
@@ -368,7 +365,7 @@ values (
 
 insertAuditFromTransaction() ::= <<
 insert into <auditTableName()> (
-<auditTableFields()>
+<auditTableFields("")>
 )
 values (
 <auditTableValues()>
diff --git a/util/src/main/resources/org/killbill/billing/util/nodes/dao/NodeInfoSqlDao.sql.stg b/util/src/main/resources/org/killbill/billing/util/nodes/dao/NodeInfoSqlDao.sql.stg
index 312c45d..87463e6 100644
--- a/util/src/main/resources/org/killbill/billing/util/nodes/dao/NodeInfoSqlDao.sql.stg
+++ b/util/src/main/resources/org/killbill/billing/util/nodes/dao/NodeInfoSqlDao.sql.stg
@@ -1,5 +1,3 @@
-group NodeInfoSqlDao;
-
 tableName() ::= "node_infos"
 
 tableFields(prefix) ::= <<
@@ -31,7 +29,7 @@ allTableValues() ::= <<
 
 create() ::= <<
 insert into <tableName()> (
-<tableFields()>
+<tableFields("")>
 )
 values (
 <tableValues()>
@@ -40,7 +38,7 @@ values (
 >>
 
 getByNodeName() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 from <tableName()>
 where node_name = :nodeName
 and is_active
@@ -48,7 +46,7 @@ and is_active
 >>
 
 getAll() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 from <tableName()>
 where is_active
 order by node_name asc
@@ -68,4 +66,4 @@ delete
 from <tableName()>
 where node_name = :nodeName
 ;
->>
\ No newline at end of file
+>>
diff --git a/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/JDBCSessionSqlDao.sql.stg b/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/JDBCSessionSqlDao.sql.stg
index b002312..e6091e5 100644
--- a/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/JDBCSessionSqlDao.sql.stg
+++ b/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/JDBCSessionSqlDao.sql.stg
@@ -1,5 +1,3 @@
-group JDBCSessionSqlDao;
-
 read() ::= <<
 select
   record_id
diff --git a/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.sql.stg b/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.sql.stg
index 5da1774..febc7ee 100644
--- a/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.sql.stg
+++ b/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/RolesPermissionsSqlDao.sql.stg
@@ -1,6 +1,3 @@
-group RolesPermissionsSqlDao;
-
-
 tableName() ::= "roles_permissions"
 
 tableFields(prefix) ::= <<
@@ -37,7 +34,7 @@ allTableValues() ::= <<
 
 create() ::= <<
 insert into <tableName()> (
-<tableFields()>
+<tableFields("")>
 )
 values (
 <tableValues()>
@@ -46,7 +43,7 @@ values (
 >>
 
 getByRecordId() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 from <tableName()>
 where record_id = :recordId
 and is_active
@@ -55,7 +52,7 @@ and is_active
 
 
 getByRoleName() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 from <tableName()>
 where role_name = :roleName
 and is_active
diff --git a/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/UserRolesSqlDao.sql.stg b/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/UserRolesSqlDao.sql.stg
index 0c9fe1c..3d4d327 100644
--- a/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/UserRolesSqlDao.sql.stg
+++ b/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/UserRolesSqlDao.sql.stg
@@ -1,5 +1,3 @@
-group UserRolesSqlDao;
-
 tableName() ::= "user_roles"
 
 tableFields(prefix) ::= <<
@@ -36,7 +34,7 @@ allTableValues() ::= <<
 
 create() ::= <<
 insert into <tableName()> (
-<tableFields()>
+<tableFields("")>
 )
 values (
 <tableValues()>
@@ -45,7 +43,7 @@ values (
 >>
 
 getByRecordId() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 from <tableName()>
 where record_id = :recordId
 and is_active
@@ -53,7 +51,7 @@ and is_active
 >>
 
 getByUsername() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 from <tableName()>
 where username = :username
 and is_active
diff --git a/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/UsersSqlDao.sql.stg b/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/UsersSqlDao.sql.stg
index 07bd4d5..94a6882 100644
--- a/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/UsersSqlDao.sql.stg
+++ b/util/src/main/resources/org/killbill/billing/util/security/shiro/dao/UsersSqlDao.sql.stg
@@ -1,5 +1,3 @@
-group UsersSqlDao;
-
 tableName() ::= "users"
 
 tableFields(prefix) ::= <<
@@ -38,7 +36,7 @@ allTableValues() ::= <<
 
 create() ::= <<
 insert into <tableName()> (
-<tableFields()>
+<tableFields("")>
 )
 values (
 <tableValues()>
@@ -47,7 +45,7 @@ values (
 >>
 
 getByRecordId() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 from <tableName()>
 where record_id = :recordId
 and is_active
@@ -55,7 +53,7 @@ and is_active
 >>
 
 getByUsername() ::= <<
-select <allTableFields()>
+select <allTableFields("")>
 from <tableName()>
 where username = :username
 and is_active
diff --git a/util/src/main/resources/org/killbill/billing/util/tag/dao/TagDefinitionSqlDao.sql.stg b/util/src/main/resources/org/killbill/billing/util/tag/dao/TagDefinitionSqlDao.sql.stg
index a1efb99..cc1f546 100644
--- a/util/src/main/resources/org/killbill/billing/util/tag/dao/TagDefinitionSqlDao.sql.stg
+++ b/util/src/main/resources/org/killbill/billing/util/tag/dao/TagDefinitionSqlDao.sql.stg
@@ -1,4 +1,4 @@
-group TagDefinitionDao: EntitySqlDao;
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "tag_definitions"
 
@@ -63,7 +63,7 @@ select
   <allTableFields("t.")>
 from <tableName()> t
 where t.is_active
-and <idField("t.")> in (<ids: {id | :id_<i0>}; separator="," >)
+and <idField("t.")> in (<ids>)
 <AND_CHECK_TENANT("t.")>
 ;
 >>
diff --git a/util/src/main/resources/org/killbill/billing/util/tag/dao/TagSqlDao.sql.stg b/util/src/main/resources/org/killbill/billing/util/tag/dao/TagSqlDao.sql.stg
index 177ec5b..6f4d604 100644
--- a/util/src/main/resources/org/killbill/billing/util/tag/dao/TagSqlDao.sql.stg
+++ b/util/src/main/resources/org/killbill/billing/util/tag/dao/TagSqlDao.sql.stg
@@ -1,4 +1,4 @@
-group TagDao: EntitySqlDao;
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "tags"
 
diff --git a/util/src/main/resources/org/killbill/billing/util/validation/dao/DatabaseSchemaSqlDao.sql.stg b/util/src/main/resources/org/killbill/billing/util/validation/dao/DatabaseSchemaSqlDao.sql.stg
index e14db44..075fa67 100644
--- a/util/src/main/resources/org/killbill/billing/util/validation/dao/DatabaseSchemaSqlDao.sql.stg
+++ b/util/src/main/resources/org/killbill/billing/util/validation/dao/DatabaseSchemaSqlDao.sql.stg
@@ -1,5 +1,3 @@
-group DatabaseSchemaSqlDao;
-
 getSchemaInfo(schemaName) ::= <<
     SELECT TABLE_NAME, COLUMN_NAME, IS_NULLABLE, DATA_TYPE,
     CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, NUMERIC_SCALE
diff --git a/util/src/test/java/org/killbill/billing/DBTestingHelper.java b/util/src/test/java/org/killbill/billing/DBTestingHelper.java
index 7023039..7046879 100644
--- a/util/src/test/java/org/killbill/billing/DBTestingHelper.java
+++ b/util/src/test/java/org/killbill/billing/DBTestingHelper.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -24,14 +24,13 @@ import java.util.Enumeration;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.killbill.billing.platform.test.PlatformDBTestingHelper;
-import org.killbill.billing.util.dao.AuditLogModelDaoMapper;
-import org.killbill.billing.util.dao.RecordIdIdMappingsMapper;
+import org.killbill.billing.util.glue.IDBISetup;
 import org.killbill.billing.util.io.IOUtils;
-import org.killbill.billing.util.security.shiro.dao.SessionModelDao;
 import org.killbill.commons.embeddeddb.EmbeddedDB;
-import org.killbill.commons.jdbi.mapper.LowerToCamelBeanMapperFactory;
 import org.skife.jdbi.v2.DBI;
 import org.skife.jdbi.v2.IDBI;
+import org.skife.jdbi.v2.ResultSetMapperFactory;
+import org.skife.jdbi.v2.tweak.ResultSetMapper;
 
 import com.google.common.base.MoreObjects;
 
@@ -58,9 +57,13 @@ public class DBTestingHelper extends PlatformDBTestingHelper {
         final DBI dbi = (DBI) super.getDBI();
         // Register KB specific mappers
         if (initialized.compareAndSet(false, true)) {
-            dbi.registerMapper(new AuditLogModelDaoMapper());
-            dbi.registerMapper(new RecordIdIdMappingsMapper());
-            dbi.registerMapper(new LowerToCamelBeanMapperFactory(SessionModelDao.class));
+            for (final ResultSetMapperFactory resultSetMapperFactory : IDBISetup.mapperFactoriesToRegister()) {
+                dbi.registerMapper(resultSetMapperFactory);
+            }
+
+            for (final ResultSetMapper resultSetMapper : IDBISetup.mappersToRegister()) {
+                dbi.registerMapper(resultSetMapper);
+            }
         }
         return dbi;
     }
diff --git a/util/src/test/java/org/killbill/billing/util/dao/TestStringTemplateInheritance.java b/util/src/test/java/org/killbill/billing/util/dao/TestStringTemplateInheritance.java
index a93add6..588d765 100644
--- a/util/src/test/java/org/killbill/billing/util/dao/TestStringTemplateInheritance.java
+++ b/util/src/test/java/org/killbill/billing/util/dao/TestStringTemplateInheritance.java
@@ -16,123 +16,61 @@
 
 package org.killbill.billing.util.dao;
 
-import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.util.regex.Pattern;
 
-import org.antlr.stringtemplate.StringTemplateGroup;
 import org.killbill.billing.util.UtilTestSuiteNoDB;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.STGroupFile;
 import org.testng.Assert;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
-import com.google.common.collect.ImmutableMap;
-
 public class TestStringTemplateInheritance extends UtilTestSuiteNoDB {
 
-    InputStream entityStream;
-    InputStream kombuchaStream;
-
-    @Override
-    @BeforeMethod(groups = "fast")
-    public void beforeMethod() throws Exception {
-        super.beforeMethod();
-        entityStream = this.getClass().getResourceAsStream("/org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg");
-        kombuchaStream = this.getClass().getResourceAsStream("/org/killbill/billing/util/dao/Kombucha.sql.stg");
-    }
-
-    @Override
-    @AfterMethod(groups = "fast")
-    public void afterMethod() throws Exception {
-        super.afterMethod();
-        if (entityStream != null) {
-            entityStream.close();
-        }
-        if (kombuchaStream != null) {
-            kombuchaStream.close();
-        }
-    }
-
     @Test(groups = "fast")
     public void testCheckQueries() throws Exception {
-        // From http://www.antlr.org/wiki/display/ST/ST+condensed+--+Templates+and+groups#STcondensed--Templatesandgroups-Withsupergroupfile:
-        //     there is no mechanism for automatically loading a mentioned super-group file
-        new StringTemplateGroup(new InputStreamReader(entityStream));
-
-        final StringTemplateGroup kombucha = new StringTemplateGroup(new InputStreamReader(kombuchaStream));
+        final STGroup kombucha = new STGroupFile(this.getClass().getResource("/org/killbill/billing/util/dao/Kombucha.sql.stg"), "UTF-8", '<', '>');
 
         // Verify non inherited template
-        Assert.assertEquals(kombucha.getInstanceOf("isIsTimeForKombucha").toString(), "select hour(current_timestamp(0)) = 17 as is_time;");
+        Assert.assertEquals(kombucha.getInstanceOf("isIsTimeForKombucha").render(), "select hour(current_timestamp(0)) = 17 as is_time;");
 
         // Verify inherited templates
-        assertPattern(kombucha.getInstanceOf("getById").toString(), "select\r?\n" +
-                                                                    "  t.record_id\r?\n" +
-                                                                    ", t.id\r?\n" +
-                                                                    ", t.tea\r?\n" +
-                                                                    ", t.mushroom\r?\n" +
-                                                                    ", t.sugar\r?\n" +
-                                                                    ", t.account_record_id\r?\n" +
-                                                                    ", t.tenant_record_id\r?\n" +
-                                                                    "from kombucha t\r?\n" +
-                                                                    "where t.id = :id\r?\n" +
-                                                                    "and t.tenant_record_id = :tenantRecordId\r?\n" +
-                                                                    ";");
-        assertPattern(kombucha.getInstanceOf("getByRecordId").toString(), "select\r?\n" +
-                                                                          "  t.record_id\r?\n" +
-                                                                          ", t.id\r?\n" +
-                                                                          ", t.tea\r?\n" +
-                                                                          ", t.mushroom\r?\n" +
-                                                                          ", t.sugar\r?\n" +
-                                                                          ", t.account_record_id\r?\n" +
-                                                                          ", t.tenant_record_id\r?\n" +
-                                                                          "from kombucha t\r?\n" +
-                                                                          "where t.record_id = :recordId\r?\n" +
-                                                                          "and t.tenant_record_id = :tenantRecordId\r?\n" +
-                                                                          ";");
-        assertPattern(kombucha.getInstanceOf("getRecordId").toString(), "select\r?\n" +
+        assertPattern(kombucha.getInstanceOf("getById").render(), "select\r?\n" +
+                                                                  "  t.record_id\r?\n" +
+                                                                  ", t.id\r?\n" +
+                                                                  ", t.tea\r?\n" +
+                                                                  ", t.mushroom\r?\n" +
+                                                                  ", t.sugar\r?\n" +
+                                                                  ", t.account_record_id\r?\n" +
+                                                                  ", t.tenant_record_id\r?\n" +
+                                                                  "from kombucha t\r?\n" +
+                                                                  "where t.id = :id\r?\n" +
+                                                                  "and t.tenant_record_id = :tenantRecordId\r?\n" +
+                                                                  ";");
+        assertPattern(kombucha.getInstanceOf("getByRecordId").render(), "select\r?\n" +
                                                                         "  t.record_id\r?\n" +
+                                                                        ", t.id\r?\n" +
+                                                                        ", t.tea\r?\n" +
+                                                                        ", t.mushroom\r?\n" +
+                                                                        ", t.sugar\r?\n" +
+                                                                        ", t.account_record_id\r?\n" +
+                                                                        ", t.tenant_record_id\r?\n" +
                                                                         "from kombucha t\r?\n" +
-                                                                        "where t.id = :id\r?\n" +
+                                                                        "where t.record_id = :recordId\r?\n" +
                                                                         "and t.tenant_record_id = :tenantRecordId\r?\n" +
                                                                         ";");
-        assertPattern(kombucha.getInstanceOf("getHistoryRecordId").toString(), "select\r?\n" +
-                                                                               "  max\\(t.record_id\\)\r?\n" +
-                                                                               "from kombucha_history t\r?\n" +
-                                                                               "where t.target_record_id = :targetRecordId\r?\n" +
-                                                                               "and t.tenant_record_id = :tenantRecordId\r?\n" +
-                                                                               ";");
-        assertPattern(kombucha.getInstanceOf("getAll").toString(), "select\r?\n" +
-                                                                   "  t.record_id\r?\n" +
-                                                                   ", t.id\r?\n" +
-                                                                   ", t.tea\r?\n" +
-                                                                   ", t.mushroom\r?\n" +
-                                                                   ", t.sugar\r?\n" +
-                                                                   ", t.account_record_id\r?\n" +
-                                                                   ", t.tenant_record_id\r?\n" +
-                                                                   "from kombucha t\r?\n" +
-                                                                   "where t.tenant_record_id = :tenantRecordId\r?\n" +
-                                                                   "order by t.record_id ASC\r?\n" +
-                                                                   ";");
-        assertPattern(kombucha.getInstanceOf("get", ImmutableMap.<String, String>of("orderBy", "record_id", "offset", "3", "rowCount", "12", "ordering", "ASC")).toString(), "select\r?\n" +
-                                                                                                                                                                             "  t.record_id\r?\n" +
-                                                                                                                                                                             ", t.id\r?\n" +
-                                                                                                                                                                             ", t.tea\r?\n" +
-                                                                                                                                                                             ", t.mushroom\r?\n" +
-                                                                                                                                                                             ", t.sugar\r?\n" +
-                                                                                                                                                                             ", t.account_record_id\r?\n" +
-                                                                                                                                                                             ", t.tenant_record_id\r?\n" +
-                                                                                                                                                                             "from kombucha t\r?\n" +
-                                                                                                                                                                             "join \\(\r?\n" +
-                                                                                                                                                                             "  select record_id\r?\n" +
-                                                                                                                                                                             "  from kombucha\r?\n" +
-                                                                                                                                                                             "  where tenant_record_id = :tenantRecordId\r?\n" +
-                                                                                                                                                                             "  order by record_id ASC\r?\n" +
-                                                                                                                                                                             "  limit :rowCount offset :offset\r?\n" +
-                                                                                                                                                                             "\\) optimization on optimization.record_id = t.record_id\r?\n" +
-                                                                                                                                                                             "order by t.record_id ASC\r?\n" +
-                                                                                                                                                                             ";");
-        assertPattern(kombucha.getInstanceOf("test").toString(), "select\r?\n" +
+        assertPattern(kombucha.getInstanceOf("getRecordId").render(), "select\r?\n" +
+                                                                      "  t.record_id\r?\n" +
+                                                                      "from kombucha t\r?\n" +
+                                                                      "where t.id = :id\r?\n" +
+                                                                      "and t.tenant_record_id = :tenantRecordId\r?\n" +
+                                                                      ";");
+        assertPattern(kombucha.getInstanceOf("getHistoryRecordId").render(), "select\r?\n" +
+                                                                             "  max\\(t.record_id\\)\r?\n" +
+                                                                             "from kombucha_history t\r?\n" +
+                                                                             "where t.target_record_id = :targetRecordId\r?\n" +
+                                                                             "and t.tenant_record_id = :tenantRecordId\r?\n" +
+                                                                             ";");
+        assertPattern(kombucha.getInstanceOf("getAll").render(), "select\r?\n" +
                                                                  "  t.record_id\r?\n" +
                                                                  ", t.id\r?\n" +
                                                                  ", t.tea\r?\n" +
@@ -142,57 +80,92 @@ public class TestStringTemplateInheritance extends UtilTestSuiteNoDB {
                                                                  ", t.tenant_record_id\r?\n" +
                                                                  "from kombucha t\r?\n" +
                                                                  "where t.tenant_record_id = :tenantRecordId\r?\n" +
-                                                                 "limit 1\r?\n" +
+                                                                 "order by t.record_id ASC\r?\n" +
                                                                  ";");
-        assertPattern(kombucha.getInstanceOf("addHistoryFromTransaction").toString(), "insert into kombucha_history \\(\r?\n" +
-                                                                                      "  id\r?\n" +
-                                                                                      ", target_record_id\r?\n" +
-                                                                                      ", change_type\r?\n" +
-                                                                                      ", tea\r?\n" +
-                                                                                      ", mushroom\r?\n" +
-                                                                                      ", sugar\r?\n" +
-                                                                                      ", account_record_id\r?\n" +
-                                                                                      ", tenant_record_id\r?\n" +
-                                                                                      "\\)\r?\n" +
-                                                                                      "values \\(\r?\n" +
-                                                                                      "  :id\r?\n" +
-                                                                                      ", :targetRecordId\r?\n" +
-                                                                                      ", :changeType\r?\n" +
-                                                                                      ",   :tea\r?\n" +
-                                                                                      ", :mushroom\r?\n" +
-                                                                                      ", :sugar\r?\n" +
-                                                                                      ", :accountRecordId\r?\n" +
-                                                                                      ", :tenantRecordId\r?\n" +
-                                                                                      "\\)\r?\n" +
-                                                                                      ";");
+        assertPattern(kombucha.getInstanceOf("get")
+                              .add("orderBy", "record_id")
+                              .add("offset", "3")
+                              .add("rowCount", "12")
+                              .add("ordering", "ASC")
+                              .render(), "select\r?\n" +
+                                         "  t.record_id\r?\n" +
+                                         ", t.id\r?\n" +
+                                         ", t.tea\r?\n" +
+                                         ", t.mushroom\r?\n" +
+                                         ", t.sugar\r?\n" +
+                                         ", t.account_record_id\r?\n" +
+                                         ", t.tenant_record_id\r?\n" +
+                                         "from kombucha t\r?\n" +
+                                         "join \\(\r?\n" +
+                                         "  select record_id\r?\n" +
+                                         "  from kombucha\r?\n" +
+                                         "  where tenant_record_id = :tenantRecordId\r?\n" +
+                                         "  order by record_id ASC\r?\n" +
+                                         "  limit :rowCount offset :offset\r?\n" +
+                                         "\\) optimization on optimization.record_id = t.record_id\r?\n" +
+                                         "order by t.record_id ASC\r?\n" +
+                                         ";");
+        assertPattern(kombucha.getInstanceOf("test").render(), "select\r?\n" +
+                                                               "  t.record_id\r?\n" +
+                                                               ", t.id\r?\n" +
+                                                               ", t.tea\r?\n" +
+                                                               ", t.mushroom\r?\n" +
+                                                               ", t.sugar\r?\n" +
+                                                               ", t.account_record_id\r?\n" +
+                                                               ", t.tenant_record_id\r?\n" +
+                                                               "from kombucha t\r?\n" +
+                                                               "where t.tenant_record_id = :tenantRecordId\r?\n" +
+                                                               "limit 1\r?\n" +
+                                                               ";");
+        assertPattern(kombucha.getInstanceOf("addHistoryFromTransaction").render(), "insert into kombucha_history \\(\r?\n" +
+                                                                                    "  id\r?\n" +
+                                                                                    ", target_record_id\r?\n" +
+                                                                                    ", change_type\r?\n" +
+                                                                                    ", tea\r?\n" +
+                                                                                    ", mushroom\r?\n" +
+                                                                                    ", sugar\r?\n" +
+                                                                                    ", account_record_id\r?\n" +
+                                                                                    ", tenant_record_id\r?\n" +
+                                                                                    "\\)\r?\n" +
+                                                                                    "values \\(\r?\n" +
+                                                                                    "  :id\r?\n" +
+                                                                                    ", :targetRecordId\r?\n" +
+                                                                                    ", :changeType\r?\n" +
+                                                                                    ", :tea\r?\n" +
+                                                                                    ", :mushroom\r?\n" +
+                                                                                    ", :sugar\r?\n" +
+                                                                                    ", :accountRecordId\r?\n" +
+                                                                                    ", :tenantRecordId\r?\n" +
+                                                                                    "\\)\r?\n" +
+                                                                                    ";");
 
-        assertPattern(kombucha.getInstanceOf("insertAuditFromTransaction").toString(), "insert into audit_log \\(\r?\n" +
-                                                                                       "id\r?\n" +
-                                                                                       ", table_name\r?\n" +
-                                                                                       ", target_record_id\r?\n" +
-                                                                                       ", change_type\r?\n" +
-                                                                                       ", created_by\r?\n" +
-                                                                                       ", reason_code\r?\n" +
-                                                                                       ", comments\r?\n" +
-                                                                                       ", user_token\r?\n" +
-                                                                                       ", created_date\r?\n" +
-                                                                                       ", account_record_id\r?\n" +
-                                                                                       ", tenant_record_id\r?\n" +
-                                                                                       "\\)\r?\n" +
-                                                                                       "values \\(\r?\n" +
-                                                                                       "  :id\r?\n" +
-                                                                                       ", :tableName\r?\n" +
-                                                                                       ", :targetRecordId\r?\n" +
-                                                                                       ", :changeType\r?\n" +
-                                                                                       ", :createdBy\r?\n" +
-                                                                                       ", :reasonCode\r?\n" +
-                                                                                       ", :comments\r?\n" +
-                                                                                       ", :userToken\r?\n" +
-                                                                                       ", :createdDate\r?\n" +
-                                                                                       ", :accountRecordId\r?\n" +
-                                                                                       ", :tenantRecordId\r?\n" +
-                                                                                       "\\)\r?\n" +
-                                                                                       ";");
+        assertPattern(kombucha.getInstanceOf("insertAuditFromTransaction").render(), "insert into audit_log \\(\r?\n" +
+                                                                                     "id\r?\n" +
+                                                                                     ", table_name\r?\n" +
+                                                                                     ", target_record_id\r?\n" +
+                                                                                     ", change_type\r?\n" +
+                                                                                     ", created_by\r?\n" +
+                                                                                     ", reason_code\r?\n" +
+                                                                                     ", comments\r?\n" +
+                                                                                     ", user_token\r?\n" +
+                                                                                     ", created_date\r?\n" +
+                                                                                     ", account_record_id\r?\n" +
+                                                                                     ", tenant_record_id\r?\n" +
+                                                                                     "\\)\r?\n" +
+                                                                                     "values \\(\r?\n" +
+                                                                                     "  :id\r?\n" +
+                                                                                     ", :tableName\r?\n" +
+                                                                                     ", :targetRecordId\r?\n" +
+                                                                                     ", :changeType\r?\n" +
+                                                                                     ", :createdBy\r?\n" +
+                                                                                     ", :reasonCode\r?\n" +
+                                                                                     ", :comments\r?\n" +
+                                                                                     ", :userToken\r?\n" +
+                                                                                     ", :createdDate\r?\n" +
+                                                                                     ", :accountRecordId\r?\n" +
+                                                                                     ", :tenantRecordId\r?\n" +
+                                                                                     "\\)\r?\n" +
+                                                                                     ";");
     }
 
     private void assertPattern(final String actual, final String expected) {
diff --git a/util/src/test/java/org/killbill/billing/util/dao/TestStringTemplateInheritanceWithJdbi.java b/util/src/test/java/org/killbill/billing/util/dao/TestStringTemplateInheritanceWithJdbi.java
index 02c6361..d2dc3a1 100644
--- a/util/src/test/java/org/killbill/billing/util/dao/TestStringTemplateInheritanceWithJdbi.java
+++ b/util/src/test/java/org/killbill/billing/util/dao/TestStringTemplateInheritanceWithJdbi.java
@@ -24,7 +24,7 @@ import org.killbill.billing.util.UtilTestSuiteWithEmbeddedDB;
 import org.killbill.billing.util.entity.Entity;
 import org.killbill.billing.util.entity.dao.EntityModelDao;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
-import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 
 public class TestStringTemplateInheritanceWithJdbi extends UtilTestSuiteWithEmbeddedDB {
 
@@ -32,7 +32,7 @@ public class TestStringTemplateInheritanceWithJdbi extends UtilTestSuiteWithEmbe
 
     private static interface KombuchaModelDao extends EntityModelDao<Kombucha> {}
 
-    @EntitySqlDaoStringTemplate("/org/killbill/billing/util/dao/Kombucha.sql.stg")
+    @KillBillSqlDaoStringTemplate("/org/killbill/billing/util/dao/Kombucha.sql.stg")
     private static interface KombuchaSqlDao extends EntitySqlDao<KombuchaModelDao, Kombucha> {
 
         @SqlQuery
diff --git a/util/src/test/java/org/killbill/billing/util/export/dao/TestDatabaseExportDao.java b/util/src/test/java/org/killbill/billing/util/export/dao/TestDatabaseExportDao.java
index e9b497f..01fe087 100644
--- a/util/src/test/java/org/killbill/billing/util/export/dao/TestDatabaseExportDao.java
+++ b/util/src/test/java/org/killbill/billing/util/export/dao/TestDatabaseExportDao.java
@@ -1,7 +1,9 @@
 /*
- * Copyright 2010-2012 Ning, Inc.
+ * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
  * License.  You may obtain a copy of the License at:
  *
@@ -30,6 +32,8 @@ import org.killbill.billing.util.UtilTestSuiteWithEmbeddedDB;
 import org.killbill.billing.util.api.DatabaseExportOutputStream;
 import org.killbill.billing.util.validation.dao.DatabaseSchemaDao;
 
+import com.ning.compress.lzf.LZFEncoder;
+
 public class TestDatabaseExportDao extends UtilTestSuiteWithEmbeddedDB {
 
     @Test(groups = "slow")
@@ -48,6 +52,7 @@ public class TestDatabaseExportDao extends UtilTestSuiteWithEmbeddedDB {
         final Date updatedDate = new Date(382910622000L);
         final String updatedBy = UUID.randomUUID().toString().substring(0, 4);
 
+        final byte[] properties = LZFEncoder.encode(new byte[] { 'c', 'a', 'f', 'e' });
         final String tableNameA = "test_database_export_dao_a";
         final String tableNameB = "test_database_export_dao_b";
         dbi.withHandle(new HandleCallback<Void>() {
@@ -56,6 +61,7 @@ public class TestDatabaseExportDao extends UtilTestSuiteWithEmbeddedDB {
                 handle.execute("drop table if exists " + tableNameA);
                 handle.execute("create table " + tableNameA + "(record_id serial unique," +
                                "a_column char default 'a'," +
+                               "blob_column mediumblob," +
                                "account_record_id bigint /*! unsigned */ not null," +
                                "tenant_record_id bigint /*! unsigned */ not null default 0," +
                                "primary key(record_id));");
@@ -65,8 +71,8 @@ public class TestDatabaseExportDao extends UtilTestSuiteWithEmbeddedDB {
                                "account_record_id bigint /*! unsigned */ not null," +
                                "tenant_record_id bigint /*! unsigned */ not null default 0," +
                                "primary key(record_id));");
-                handle.execute("insert into " + tableNameA + " (account_record_id, tenant_record_id) values (?, ?)",
-                               internalCallContext.getAccountRecordId(), internalCallContext.getTenantRecordId());
+                handle.execute("insert into " + tableNameA + " (blob_column, account_record_id, tenant_record_id) values (?, ?, ?)",
+                               properties, internalCallContext.getAccountRecordId(), internalCallContext.getTenantRecordId());
                 handle.execute("insert into " + tableNameB + " (account_record_id, tenant_record_id) values (?, ?)",
                                internalCallContext.getAccountRecordId(), internalCallContext.getTenantRecordId());
 
@@ -83,8 +89,8 @@ public class TestDatabaseExportDao extends UtilTestSuiteWithEmbeddedDB {
         Assert.assertEquals(newDump, "-- accounts record_id|id|external_key|email|name|first_name_length|currency|billing_cycle_day_local|payment_method_id|time_zone|locale|address1|address2|company_name|city|state_or_province|country|postal_code|phone|migrated|is_notified_for_invoices|created_date|created_by|updated_date|updated_by|tenant_record_id\n" +
                                      String.format("%s|%s||%s|%s|%s||||||||||||||false|%s|%s|%s|%s|%s|%s", internalCallContext.getAccountRecordId(), accountId, accountEmail, accountName, firstNameLength,
                                                    isNotifiedForInvoices, "1970-05-24T18:33:02.000+0000", createdBy, "1982-02-18T20:03:42.000+0000", updatedBy, internalCallContext.getTenantRecordId()) + "\n" +
-                                     "-- " + tableNameA + " record_id|a_column|account_record_id|tenant_record_id\n" +
-                                     "1|a|" + internalCallContext.getAccountRecordId() + "|" + internalCallContext.getTenantRecordId() + "\n" +
+                                     "-- " + tableNameA + " record_id|a_column|blob_column|account_record_id|tenant_record_id\n" +
+                                     "1|a|WlYAAARjYWZl|" + internalCallContext.getAccountRecordId() + "|" + internalCallContext.getTenantRecordId() + "\n" +
                                      "-- " + tableNameB + " record_id|b_column|account_record_id|tenant_record_id\n" +
                                      "1|b|" + internalCallContext.getAccountRecordId() + "|" + internalCallContext.getTenantRecordId() + "\n");
 
diff --git a/util/src/test/resources/org/killbill/billing/util/dao/Kombucha.sql.stg b/util/src/test/resources/org/killbill/billing/util/dao/Kombucha.sql.stg
index cbb4410..52dbbc8 100644
--- a/util/src/test/resources/org/killbill/billing/util/dao/Kombucha.sql.stg
+++ b/util/src/test/resources/org/killbill/billing/util/dao/Kombucha.sql.stg
@@ -1,4 +1,4 @@
-group Kombucha: EntitySqlDao;
+import "org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg"
 
 tableName() ::= "kombucha"