@future method takes an sObject or a collection of sObjects
ID |
apex.correctness.future_methods_accept_sobjects |
Severity |
high |
Remediation Complexity |
medium |
Remediation Risk |
medium |
Remediation Effort |
medium |
Resource |
Api Design |
Language |
Apex |
Description
Reports a @future method whose parameter list contains an sObject, a custom object, or a collection of them. @future accepts only primitives and collections of primitives.
Rationale
The platform rejects the signature, so the class fails to compile or deploy - and if the type is generic enough to slip through, the object would in any case be serialized at enqueue time and arrive stale: by the time the job runs, the record in the database may have changed, and the copy the method holds would overwrite it. Passing ids instead makes the freshness explicit, because the method has to query for the current row.
The following code illustrates the pattern detected by this rule:
public class AsyncSignatures {
// FLAGGED: @future method takes an sObject or a collection of sObjects
@future
public static void syncAccounts(List<Account> accts) {
System.debug(accts);
}
// FLAGGED: @future method takes an sObject or a collection of sObjects
@future(callout=true)
public static void pushOrder(Order__c order) {
System.debug(order);
}
@future
public static void syncAccountIds(Set<Id> accountIds) {
List<Account> accts = [SELECT Id, Name FROM Account];
System.debug(accts);
}
@future(callout=true)
public static void pushPayload(String payload) {
System.debug(payload);
}
}
Remediation
Pass Set<Id> or List<Id> and re-query the records inside the method, which also gives the asynchronous work the current field values. Where a whole payload has to travel, serialize it to a String with JSON.serialize - or use a Queueable, which takes typed member state including sObjects.