Tag Archives: Apex

Apex Callable Interface

In Winter’19 release Salesforce introduced Callable interface in apex. The interface enables developers to use a common interface to build loosely coupled integrations between Apex classes or triggers, even for code in separate packages.

This interface has one method call(String action, Map args). It helps developer to call a method dynamically with the help of “Type” class.

Example:

public class SampleCallable implements Callable {
    
    //Method 1
    public String method1(String stringValue) {
        return 'Welcome ' + stringValue;
    }
    
    //Method 2
    public Decimal method2(Integer integerValue) {
        return integerValue + 100;
    }
    
    //Callable interface method
    public Object call(String action, Map<String, Object> args) {
        switch on action {
            when 'method1' {
                return this.method1((String)args.get('stringValue'));
            }
            when 'method2' {
                return this.method2((Integer)args.get('integerValue'));
            }
            when else {
                return null;
            }
        }
    }
}

Execute:

Callable c = (Callable)Type.forName('SampleCallable').newInstance();
system.debug(c.call('method1', new map<String,Object>{'stringValue' => 'Biswajeet'}));
system.debug(c.call('method2', new map<String,Object>{'integerValue' => 5}));

Cacheable Apex Method

To improve the performance of the lightning component cache Salesforce introduced storable (cacheable) in Winter’19 release. In API version 44.0 and later, you can mark an Apex method as storable (cacheable) instead of using setStorable() on every JavaScript action that calls the Apex method to centralize your caching notation for a method in the Apex class.

Here is an example to cache data returned from an Apex method for lightning component, annotate the Apex method with @AuraEnabled(cacheable=true).

Apex Class:

public class SampleAuraController {
    
    @AuraEnabled(cacheable = true)
    public static List<Account> getDirectCustomerAccount() {
        List<Account> accList = new List<Account>();
        accList = [SELECT Id, Name, Type, Industry, Phone
                   FROM Account WHERE Type = 'Customer - Direct'];
        return accList;
    }
}

Lightning Component:

<aura:component controller="SampleAuraController" implements="flexipage:availableForAllPageTypes,force:appHostable">
    
    <!--Declare Event Handlers-->
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    
    <!--Declare Attributes-->
    <aura:attribute name="accList" type="Account[]"/>
    
    <!--Component Start-->
    <div class="slds-m-around_xx-large">
        <table class="slds-table slds-table_cell-buffer slds-table_bordered slds-table_col-bordered">
            <thead>
                <tr class="slds-line-height_reset">
                    <th class="slds-text-title_caps" scope="col">
                        <div class="slds-truncate" title="Account Name">Account Name</div>
                    </th>
                    <th class="slds-text-title_caps" scope="col">
                        <div class="slds-truncate" title="Account Type">Account Type</div>
                    </th>
                    <th class="slds-text-title_caps" scope="col">
                        <div class="slds-truncate" title="Industry">Industry</div>
                    </th>
                    <th class="slds-text-title_caps" scope="col">
                        <div class="slds-truncate" title="Phone">Phone</div>
                    </th>
                </tr>
            </thead>
            <tbody>
                <aura:iteration items="{!v.accList}" var="acc">
                    <tr class="slds-hint-parent">
                        <th data-label="Account Name" scope="row">
                            <div class="slds-truncate" title="{!acc.Name}"><a href="javascript:void(0);" tabindex="-1">{!acc.Name}</a></div>
                        </th>
                        <td data-label="Account Type">
                            <div class="slds-truncate" title="{!acc.Type}">{!acc.Type}</div>
                        </td>
                        <td data-label="Industry">
                            <div class="slds-truncate" title="{!acc.Industry}">{!acc.Industry}</div>
                        </td>
                        <td data-label="Phone">
                            <div class="slds-truncate" title="{!acc.Phone}">{!acc.Phone}</div>
                        </td>
                    </tr>
                </aura:iteration>
            </tbody>
        </table>
    </div>
    <!--Component End-->
</aura:component>

Lightning JS Controller:

({
    doInit : function(component, event) {
        var action = component.get("c.getDirectCustomerAccount");
        action.setCallback(this, function(response) {
            var state = response.getState();
            if(state === "SUCCESS"){
                var result = response.getReturnValue();
                component.set("v.accList", result);
            }
        });
        $A.enqueueAction(action);
    }
})

Output:

Inherited Sharing in Apex Class

Now you can specify the Inherited Sharing keyword on an Apex class, which allows the class to run your apex code with or without sharing settings, depending on the class that called it.

  • An Apex class with Inherited Sharing enables you to pass security review and ensure that your privileged Apex code is not used in unexpected or insecure ways.
  • An Apex class with Inherited Sharing runs as with sharing when used as a Visualforce page controller, Apex REST service, or an entry point to an Apex transaction.
  • An Apex class with Inherited Sharing is being called from some other class which is having without sharing setting, then it will run in without sharing mode.

Here is an example of an Apex class with Inherited Sharing and a Visualforce invocation of that Apex class. Here the running user sharing access contacts will be displayed. If the declaration Inherited Sharing will be omitted, even contacts that the user has no rights to view will be displayed due to the insecure default behavior of omitting the declaration.

Apex Class:

public inherited sharing class InheritedSharingClass{
    public List<Contact> getAllContacts(){
        return [SELECT Name FROM Contact];
    }
}

Visualforce Page:

<apex:page controller="InheritedSharingClass">
    <apex:repeat value="{!AllContacts}" var="record">
        {!record.Name}
    </apex:repeat>
</apex:page>

Set Approval Process Lock And Unlock Records Using Apex Code

Sometimes we have faced business requirement to Lock or Unlock records in Salesforce. We can use apex lock() and unlock() methods in the System.Approval namespace to lock and unlock records by passing in record IDs or sObjects.

To enable this feature, go to Setup | Search Automation Settings in the Quick Find box | click on Automation Settings. Then, select Enable record locking and unlocking in Apex.

Lock Record Example:

//Get records to lock
List<case> caseList = [SELECT Id From Case LIMIT 10];
//Lock records
List<Approval.LockResult> lrList = Approval.lock(caseList, false);

// Iterate through each returned result
for(Approval.LockResult lr : lrList) {
    if (lr.isSuccess()) {
        //Operation was successful, so get the ID of the record that was processed
        System.debug('Successfully locked account with ID: ' + lr.getId());
    }
    else {
        //Operation failed, so get all errors                
        for(Database.Error err : lr.getErrors()) {
            System.debug('The following error has occurred.');                    
            System.debug(err.getStatusCode() + ': ' + err.getMessage());
            System.debug('Case fields that affected this error: ' + err.getFields());
        }
    }
}

Unlock Record Example:

//Get records to unlock
List<case> caseList = [SELECT Id From Case LIMIT 10];
//Check locked records
List<case> caseLockList = new List<Case>();
for(Case c :caseList){
    if(Approval.isLocked(c.id)){
        caseLockList.add(c);
    }
}
//Unlock record
if(!caseLockList.isEmpty()){
    //Unlock records
    List<Approval.UnlockResult> ulrList = Approval.unlock(caseLockList, false);
    
    // Iterate through each returned result
    for(Approval.UnlockResult  ulr : ulrList) {
        if (ulr.isSuccess()) {
            //Operation was successful, so get the ID of the record that was processed
            System.debug('Successfully locked account with ID: ' + ulr.getId());
        }
        else {
            //Operation failed, so get all errors                
            for(Database.Error err : ulr.getErrors()) {
                System.debug('The following error has occurred.');                    
                System.debug(err.getStatusCode() + ': ' + err.getMessage());
                System.debug('Case fields that affected this error: ' + err.getFields());
            }
        }
    }
}