[SalesForce] Issue with Invocable Method to Call Queueable

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:

public List<Id> oppList;

Note how you are creating a new Queueable in this line:

System.enqueueJob(new PrimaryCampaignQueueable(oppIds));

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:

The Queueable interface behaves a lot like the Batchable interface. It gives you a class structure that we can serialize for you, and you can serialize more than just primitive arguments. It is called by a method, System.enqueueJob(), which returns a job ID to you.

developer documentation

Related Topic