A Well Oiled Abstraction

Trading Copy/Paste for Configurable Apex Execution

As we continue to build our library of common customizations, we must also be looking at the overhead involved in creating and modifying classes that override B2B Commerce functionality.  As a proof of concept, I recently abstracted logic that we had previously implemented for a customer that rounded the quantities of cart items up to the nearest multiple of the standard pack quantity for that product.

Prior to this exercise, the logic involved was written directly in the child class of the ccrz.cc_api_CartExtension class.

The first step I took in abstracting the logic was to create a custom object that would be used to handle the configuration of the overrides.  My object (named XC_Relection__c) contains two custom fields: XC_Apex_Class__c, and XC_Virtual_Class__c. The first is used to detail the name of the class that contains the logic to be implemented, and the second is used to define where that logic should be injected.

Next, I needed to write a simple abstract class that would be used to call the logic execution from the dynamically instantiated class objects.

public abstract class XC\_Process {

 public Map<String, Object> inputData;

 public abstract Map<String, Object> execute ();

   public abstract void setInputData (Map<String, Object> inputData);

 public abstract Map<String, Object> getInputData ();


Then each of the subsequent classes that perform the logic (or the execution of those classes) override the abstract methods in XC_Process.

In my POC, I created a XC_CartPreprocess class that handled the execution of the logic class.

public class XC\_CartPreprocess extends XC\_Process {

 public Map<String, Object> inputData;

 public override Map<String, Object> execute () {

    for (XC\_Reflection\_\_c reflection : \[

          SELECT Id, XC\_Apex\_Class\_\_c

          FROM XC\_Reflection\_\_c

          WHERE XC\_Virtual\_Class\_\_c = 'preprocess'

    \]) {

       XC\_Process instance =

(XC\_Process) Type.forName(reflection.XC\_Apex\_Class\_\_c).newInstance();


       inputData = instance.execute();


    return inputData;


 public override void setInputData (Map<String, Object> inputData) {

    this.inputData = inputData;


 public override Map<String, Object> getInputData () {

    return inputData;



Note that I had to explicitly create the getter and setter methods for the inputData variable, and that is likely due to a difference in how Apex and Java interpret the get/set on the class variable definition.