The future annotation is a great feature on the Salesforce Platform to allow you to execute custom logic asynchronously. I often use them to perform callouts within the context of a database trigger. However, one of the restrictions of future annotations is that you can not pass sObjects or objects as arguments to the annotated method. I regularly use encapsulation to pass a collection of parameters, or even an sObject, but this won’t work in @future method:
@future static void doFutureCall(List<AddressHelper> addresses) { //do something }
But thankfully there is a way you can do. The secret sauce is the JSON serialize|deserialize methods.
Take the example of an AddressHelper object referred to above. This is encapsulated convenience object to help me pass around address details. (note:For simplicity, this helper object just includes strings, but it could easily include other types including objects, sobjects, collections etc.)
/** * Sample encapsulated class * $author: qwall@salesforce.com */ public with sharing class AddressHelper { public String street {set; get;} public String city {set; get;} public String state {set; get;} public String zip {set; get;} public AddressHelper(String s, String c, String st, String z) { street = s; city = c; state = st; zip = z; } }
Using the JSON serialize method I can easily pass this to an @future method.
public with sharing class AddressFuture {
public AddressFuture () { List<String> addresses = new List<String>(); AddressHelper ah1 = new AddressHelper('1 here st', 'San Francisco', 'CA', '94105'); AddressHelper ah2 = new AddressHelper('2 here st', 'San Francisco', 'CA', '94105'); AddressHelper ah3 = new AddressHelper('3 here st', 'San Francisco', 'CA', '94105'); //serialize my objects addresses.add(JSON.serialize(ah3)); addresses.add(JSON.serialize(ah2)); addresses.add(JSON.serialize(ah3)); doFutureCall(addresses); }
And then, within my future method, all I need to do is deserialize the object, and you are good to go.
@future static void doFutureCall(List<String> addressesSer) { AddressHelper currAddress = null; for (String ser : addressesSer) { currAddress = (AddressHelper) JSON.deserialize(ser, AddressHelper.class); System.debug('Deserialized in future:'+currAddress.street); } }
That’s it. JSON.serialize|deserialize makes it amazingly simple to pass objects, even ones with complex nested relationships, to @future annotated methods. There are time though that a particular object can not be serialized due to the underlying inheritance structure. One such example is the Pattern class in Apex.
To handle these outliers, I often create my own custom getSerializable() method on my custom object.
That’s about it. You can grab the complete code for the examples above as a gist here.