Ok, I'm officially confused. I've written some code to attempt to populate a Campaign lookup field on Opportunity based on some logic. The basic flow is Process Builder (so the client can declaratively change when the logic fires if desired) > Invocable Method > Queueable.
My code works just fine in the context of my unit tests, but when I try to test it in sandbox I get a null-pointer exception.
Invocable:
public class PrimaryCampaign {
@InvocableMethod
public static void setPrimaryCampaign(List<Id> oppIds){
System.debug(oppIds); //populated
System.enqueueJob(new PrimaryCampaignQueueable(oppIds));
}
}
Simplified Queueable:
public class PrimaryCampaignQueueable implements Queueable{
public static List<Id> oppList;
public PrimaryCampaignQueueable(List<Id> oppIds){
oppList = oppIds;
}
public static void execute(QueueableContext qc){
System.debug(oppList); //NPE occurs here, but when I run unit tests, this is populated
//do logic
}
}
Simplified Test Class:
@isTest
public class TestPrimaryCampaign {
@testSetup
static void setUp(){
//set up data including Accounts, Contacts, Campaigns, CampaignMembers, Opportunities & OpportunityContactRoles
}
@isTest
static void testPrimaryCampaign(){
List<Id> oppIds = new List<Id>();
Opportunity o = [SELECT Id FROM Opportunity];
oppIds.add(o.Id);
Test.startTest();
PrimaryCampaign.setPrimaryCampaign(oppIds);
Test.stopTest();
//do assertions
}
}
I've tried testing both through the UI to trigger the Process Builder, as well as just running the following anonymous block in the dev console getting the same NPE both ways:
List<Id> oppIds = new List<Id>();
oppIds.add('0062F000002USgZQAW');
PrimaryCampaign.setPrimaryCampaign(oppIds);
I also tried making the oppList not static and defining it with:
this.oppList = oppIds;
But that fails to compile with an error that the variable oppList doesn't exist. I am so confused. What is going on here?
Best Answer
Your oppList shouldn't be static.
It should be a member variable.
Try this:
Note how you are creating a new Queueable in this line:
EDIT: I was right, but for a partly wrong reason.
As @sfdcfox says, it's because the static member is not serialized when the
Queueable
is serialized prior to processing.When the execute method is called (by the system), the Queueable is rehydrated and the oppList, being static is lost - which is why it ends up null.
Here is the relevant documentation:
developer documentation