In this post, I am going to quick recall on the winter 19 Salesforce lightning component changes and improvements.
1.Mark Apex Methods as Cacheable
Prior to Winter ’19, to cache data returned from an Apex method, you had to call setStorable() in JavaScript code on every action that called the Apex method. Now you can mark the Apex method as storable (cacheable) and get rid of any setStorable() calls in JavaScript code.
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. Marking a method as storable improves your component’s performance by quickly showing cached data from client-side storage without waiting for a server trip. If the cached data is stale, the framework retrieves the latest data from the server. Caching is especially beneficial for users on high-latency, slow, or unreliable connections, such as 3G networks. To cache data returned from an Apex method for any component with an API version of 44.0 or later, annotate the Apex method with
@AuraEnabled(cacheable=true). For example:
@AuraEnabled(cacheable=true)
public static Account getAccount(Id accountId) {
// your code here
}
2. Fire Platform Events from Batch Apex Classes (Beta)
Batch Apex classes can now opt in to fire platform events when encountering an error or exception. Event records provide more granular tracking of errors than the Apex Jobs UI because they include the record IDs being processed, exception type, exception message, and stack trace. You can also incorporate custom handling and retry logic for failures. Clients listening on an event can tell how often it failed, which records were in scope at the time of failure, and other exception details. Events are also fired for Salesforce Platform internal errors and other “uncatchable” Apex exceptions like LimitExceptions that are caused by reaching governor limits.
global with sharing class PlatformEventRaise implements Database.Batchable<SObject>, Database.RaisesPlatformEvents{
// class implementation
global Database.QueryLocator start(Database.BatchableContext BC){
return Database.getQueryLocator('Select Id ,Name,Rating,Industry, BillingAddress,BillingStreet,BillingCity, BillingCountry, BillingPostalCode,BillingState,Phone from Account where BillingStreet!=NULL');
}
global void execute(Database.BatchableContext BC, List<sObject> scope){
List<Account> accs =(List<Account>) scope ;
List<Cloud_News__e> cnewList = new List<Cloud_News__e>();
for(Account a : accs){
// Create an instance of the event and store it in the newsEvent variable
Cloud_News__e newsEvent = new Cloud_News__e(
Location__c=a.BillingStreet,
Urgent__c=true,
News_Content__c=a.BillingStreet);
cnewList.add(newsEvent) ;
}
EventBus.publish(cnewList);
}
global void finish(Database.BatchableContext BC){
}
}
3. Use Inherited Sharing to Secure Your Apex Code
You can now specify the inherited sharing keyword on an Apex class, which allows the class to run in the sharing mode of the class that called it. Using 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. This example declares an Apex class with inherited sharing and a Visualforce invocation of that Apex code. Because of the inherited sharing declaration, only contacts for which the running user has sharing access are displayed.
If the declaration is omitted, even contacts that the user has no rights to view are displayed due to the insecure default behavior of omitting the declaration.
public inherited sharing class InheritedSharingClass{
public List<Contact> getAllTheSecrets(){
return [SELECT Name FROM Contact];
}
}
<apex:page controller="InheritedSharingClass">
<apex:repeat value="{!allTheSecrets}" var="record">
{!record.Name}
</apex:repeat>
</apex:page>
4. Get Domain URL from Apex
Use the new System.Url.getOrgDomainUrl() method to interact with Salesforce REST and SOAP APIs in Apex code. Use getOrgDomainUrl() in orgs with or without My Domain to retrieve canonical URLs. For example, https://yourDomain.my.salesforce.com, or, for orgs without My Domain enabled https://yourInstance.salesforce.com .
Url.getOrgDomainUrl().toExternalForm()
5. Get Session Id in Asynchronous Context
UserInfo.getSessionId() method to retrieve session IDs, even when your code runs asynchronously. Previously, orgs with My Domain enabled could access some API features from Apex code only after setting up remote site settings or named credentials. Some objects, such as DatedExchangeRate, are accessible only through the API. You can use getSessionId() both synchronously and asynchronously. In asynchronous Apex (Batch, Future, Queueable, or Scheduled Apex), this method returns the session ID only when the code is run by an active, valid user. When the code is run by an internal user, such as the automated process user or a proxy user, the method returns null.
Http h = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint(Url.getOrgDomainUrl().toExternalForm()
+ '/services/data/v44.0/limits');
req.setMethod('GET');
req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionId());
HttpResponse res = h.send(req);
6.Share Extensible Functionality with the Callable Interface
The System.Callable interface enables you to use a common interface to build loosely coupled integrations between Apex classes or triggers, even for code in separate packages. Agreeing upon a common interface enables developers from different companies or different departments to build upon one another’s solutions. Implement this interface to enable the broader community, which might have different solutions than the ones you had in mind, to extend your code’s functionality.
public class Extension implements Callable {
// Actual method
String concatStrings(String stringValue) {
return stringValue + stringValue;
}
// Actual method
Decimal multiplyNumbers(Decimal decimalValue) {
return decimalValue * decimalValue;
}
// Dispatch actual methods
public Object call(String action, Map<String, Object> args) {
switch on action {
when 'concatStrings' {
return this.concatStrings((String)args.get('stringValue'));
}
when 'multiplyNumbers' {
return this.multiplyNumbers((Decimal)args.get('decimalValue'));
}
when else {
throw new ExtensionMalformedCallException('Method not implemented');
}
}
}
public class ExtensionMalformedCallException extends Exception {}
}
7.Instantiate Custom Metadata Types in Apex
Now you can able to Instantiate Custom Metadata Types in Apex direly. You can now edit custom metadata records in memory within Apex. Previously, custom metadata records queried with SOQL in Apex were immutable. Audit fields (CreatedDate, CreatedBy, LastModifiedDate, LastModifiedBy, SystemModStamp) and calculated fields remain uneditable. DML operations aren’t allowed on custom metadata in Apex or the Partner or Enterprise APIs. DML operations can be done with the Apex Metadata API.


In this example, the first method is instantiating a custom metadata record, but no records are inserted into memory. The second the method retrieves a record, changes it, and returns it to the caller, but the change is not updated in the database.
public class CustomMetadataService{
public CustomMetadataService() {}
/**
* This method instantiates a custom metadata record of type Country_Code__mdt
* and sets the DeveloperName to the input String.
* Note that the record is not inserted into the database,
* and would not be found by a SOQL query.
*/
public Country_Code__mdt getCustomMetadataRecord(String myName) {
Country_Code__mdt theRecord = new Country_Code__mdt();
theRecord.DeveloperName = myName;
return theRecord;
}
/**
* This method retrieves a custom metadata record, changes a field, and returns it
* to the caller. Note that the changed record is not updated in the database.
*/
public Country_Code__mdt getChangedCustomMetadataRecord(String myNewName) {
Country_Code__mdt theRecord = [SELECT Id, DeveloperName from
Country_Code__mdt LIMIT 1];
theRecord.DeveloperName = myNewName;
return theRecord;
}
/**
* This method retrieves a custom metadata record,if the metadata found return the values from database
* Other wise instantiates a custom metadata record and return it
*/
public Country_Code__mdt getChangedCustomMetadata(String myNewName) {
Country_Code__mdt theRecord ;
theRecord = [SELECT Id, DeveloperName from
Country_Code__mdt LIMIT 1];
if(theRecord.DeveloperName!=null){
return theRecord;
}else{
theRecord = new Country_Code__mdt();
theRecord.DeveloperName = 'United_States';
return theRecord;
}
}
}
8.Prediction Field type
isAiPredictionField() from Schema.DescribeFieldResult Returns a Boolean indicating whether the field is enabled to display Einstein prediction data.d
9.Scale Your Event-Based Apps with High-Volume Platform Events (Pilot)
Use high-volume platform events to publish and process millions of events efficiently. This pilot was offered in the last release, and salesforce made enhancements for this release. Choose the platform event type that suits your business needs. For applications that receive several million events per day, use high-volume platform events through the pilot program. For applications that receive up to a million events per day, use standard-volume platform events.Y ou can define a high-volume platform event from the user interface or through Metadata API. From the UI, in Setup, enter Platform Events in the Quick Find box, then select Platform Events. When completing the standard fields, select High Volume for Event Type.In Metadata API, the event definition is represented in the CustomObject type with eventType set to HighVolume.Publish and subscribe to high-volume platform events in the same way that you publish and subscribe to standard-volume platform events. You can use declarative tools, such as Process Builder and flow, or write code with Apex and CometD API apps.
High-volume platform events are published asynchronously so that the system can process high loads of events efficiently. The publishing call places the publish request in a queue. The event message might not be published immediately after the call returns, but it is published when system resources are available. High-volume events are stored for up to three days, and stored events can be replayed.