function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Shawn Reichner 29Shawn Reichner 29 

Apex null pointer Issue

Awesome developers!

I have the following trigger that is operating as intended, however every now and then I receive an Null pointer exection error on line 21 of the following code.  I can not trace this back to anything and the code looks to be looking for nulls but again I am not a very seasoned developer with code so I am hopign someone can help share why this error is generated every now and then.  

Appreciate the help!
trigger AcctPaymentRollup on Zuora__Payment__c (after insert, after update, before delete, after unDelete) {
    List<Id> AccIds=new List<Id>();
    
If(Trigger.isInsert || Trigger.isUpdate || Trigger.isUnDelete) {
    for(Zuora__Payment__c mst:Trigger.New){
    if(mst.Zuora__Account__c !=null && mst.Zuora__AppliedInvoiceAmount__c != null && mst.Zuora__GatewayStatus__c == 'Submitted' && mst.Zuora__PaymentMethod__c != 'Check'){
     AccIds.add(mst.Zuora__Account__c);
    }
        else if (mst.Zuora__Account__c != null && mst.Zuora__AppliedInvoiceAmount__c != null && (mst.Zuora__PaymentMethod__c == 'Check' || string.ValueOf(mst.Zuora__PaymentMethod__c).startsWith('ACH'))){
            AccIds.add(mst.Zuora__Account__c);
        }
    }
   

   Map<Id,Account> AccMap = new Map<Id,Account>([select id,Current_Invoice_Amount_Paid__c from Account where id in:AccIds]);
   
   for(Zuora__Payment__c mst:Trigger.New)
   {
        if(AccMap != NULL && !AccMap.IsEmpty())
        {
            AccMap.get(mst.Zuora__Account__c).Current_Invoice_Amount_Paid__c = mst.Zuora__AppliedInvoiceAmount__c;
        
        }
   }

   if(AccMap != NULL && !AccMap.IsEmpty())
   {
        update AccMap.values();
   }}
   
   If(Trigger.isDelete) {
    for(Zuora__Payment__c mst:Trigger.Old){
    if(mst.Zuora__Account__c !=null && mst.Zuora__GatewayStatus__c == 'Submitted' && mst.Zuora__PaymentMethod__c != 'Check'){
     AccIds.add(mst.Zuora__Account__c);
    }
    else if (mst.Zuora__Account__c != null && (mst.Zuora__PaymentMethod__c == 'Check' || string.ValueOf(mst.Zuora__PaymentMethod__c).startsWith('ACH'))){
     AccIds.add(mst.Zuora__Account__c);   
        }
    }
   

   Map<Id,Account> AccMap = new Map<Id,Account>([select id,Current_Invoice_Amount_Paid__c from Account where id in:AccIds]);
   
   for(Zuora__Payment__c mst:Trigger.Old)
   {
        if(AccMap != NULL && !AccMap.IsEmpty())
        {
            AccMap.get(mst.Zuora__Account__c).Current_Invoice_Amount_Paid__c = AccMap.get(mst.Zuora__Account__c).Current_Invoice_Amount_Paid__c - mst.Zuora__AppliedInvoiceAmount__c;
        }
   }

   if(AccMap != NULL && !AccMap.IsEmpty())
   {
        update AccMap.values();
   }}

}

 
Best Answer chosen by Shawn Reichner 29
Alain CabonAlain Cabon
Hi Shawn.

Need of the test that AccMap contains the Key mst.Zuora__Account__c that itself can be null.
 
for(Zuora__Payment__c mst:Trigger.Old) {
       if(AccMap != NULL && !AccMap.IsEmpty() && mst.Zuora__Account__c != null && AccMap.containsKey(mst.Zuora__Account__c)) {          AccMap.get(mst.Zuora__Account__c).Current_Invoice_Amount_Paid__c = AccMap.get(mst.Zuora__Account__c).Current_Invoice_Amount_Paid__c - mst.Zuora__AppliedInvoiceAmount__c; }
​ }

 

All Answers

Alain CabonAlain Cabon
Hi Shawn.

Need of the test that AccMap contains the Key mst.Zuora__Account__c that itself can be null.
 
for(Zuora__Payment__c mst:Trigger.Old) {
       if(AccMap != NULL && !AccMap.IsEmpty() && mst.Zuora__Account__c != null && AccMap.containsKey(mst.Zuora__Account__c)) {          AccMap.get(mst.Zuora__Account__c).Current_Invoice_Amount_Paid__c = AccMap.get(mst.Zuora__Account__c).Current_Invoice_Amount_Paid__c - mst.Zuora__AppliedInvoiceAmount__c; }
​ }

 
This was selected as the best answer
Shawn Reichner 29Shawn Reichner 29
Alain, thank you for your help here!  I really appreciate it.  If you look at the first lines of the trigger, am I not already doign this null check in order to acc the accounts to the Map?  Please advise as I am a little confused as I thought I was already checking for this.  Is this check in the incorrect place?

Thanks again, just trying to understand so I know fo rthe future. 

Shawn
Alain CabonAlain Cabon
In fact, this kind of test is called Short Circuit Evaluation of Java's Boolean Operators (behind Apex, it is Java, same logic).

Barry Burd (Edu, writer of Java for Dummies): The && and || operators are short circuit operators. A short circuit operator is one that doesn't necessarily evaluate all of its operands. 

https://users.drew.edu/bburd/JavaForDummies4/ShortCircuitEval.pdf
  i
Map<Id,Account> AccMap = new Map<Id,Account>([select id,Current_Invoice_Amount_Paid__c fromAccount where id in:AccIds]);

for(Zuora__Payment__c mst:Trigger.Old) {

if(AccMap != NULL    // if NULL : no other test is done (short circuit) the global test is false.
&& !AccMap.IsEmpty()  
&& mst.Zuora__Account__c != null   
&& AccMap.containsKey(mst.Zuora__Account__c) // if you arrive here, you are not sure that AccMap.containsKey(mst.Zuora__Account__c) even if mst.Zuora__Account__c != null
) {      // here you are sure    
        AccMap.get(mst.Zuora__Account__c).  // this part could be null if AccMap doesn't contains the Key(mst.Zuora__Account__c)
                  Current_Invoice_Amount_Paid__c   // null.Current_Invoice_Amount_Paid__c  => error.
}


mst.Zuora__Account__c != null   : could be useless if you are sure of your data.
For safety reason, you test all the parts.
Shawn Reichner 29Shawn Reichner 29
Thank you for the detailed explanation, that made perfect sense.  I did have to edit yoru code very slightly in the for loop, I could not useTrigger.old, I had to use Trigger.new.  I have this placed into our production environment and will test.  if this handles the issues I will mark this as the best answer.  Thanks again for your assistance. 

Shawn
Alain CabonAlain Cabon
Good if that could help. It is a very common problem and the code could have worked fine for many years until the first "exception". It is highly dependent on the data. Your code worked fine until the first unlikely event in the data. 
Shawn Reichner 29Shawn Reichner 29
Thanks again for the help and explanation!