3

I am getting a null pointer exception when I am iterating over a set of custom settings which I have initialised earlier. Should the exception be thrown if the set is empty but not null? Outstanding_Product_Group_Index_Mapping__c is a custom setting. I am following Trigger Pattern for Tidy, Streamlined, Bulkified Triggers by Tony Scott.

/*Trigger Handler for the Account SObject. This class implements the  
*ITrigger interface to help ensure the trigger code is bulkified and all in one place.*/
public class Outstanding_TriggerHandler implements ITrigger{   
Map<String,String> mapOfProdDivsAndGrp = new Map<String, String>();
Map<String, Set<Outstanding_Product_Group_Index_Mapping__c>> mapOfGroupAndSetting =  new Map<String, Set<Outstanding_Product_Group_Index_Mapping__c>>();
Map<String,Outstanding_Product_Group_Index_Mapping__c> mapOfNameAndSetting = Outstanding_Product_Group_Index_Mapping__c.getAll();

public Outstanding_TriggerHandler() {
}

public void bulkBefore() {
    if(Trigger.isInsert) {
        for(Outstanding_Product_Group_Index_Mapping__c opgi : mapOfNameAndSetting.Values()) {
            if(!mapOfProdDivsAndGrp.containsKey(opgi.Product_Divisions__c)) {
                mapOfProdDivsAndGrp.put(opgi.Product_Divisions__c, opgi.Group_Index__c);
            }   
            if(!mapOfGroupAndSetting.containsKey(opgi.Group_Index__c)) {
                mapOfGroupAndSetting.put(opgi.Group_Index__c, new Set<Outstanding_Product_Group_Index_Mapping__c>());
            }
            mapOfGroupAndSetting.get(opgi.Group_Index__c).add(opgi);
        }
    }
}

public void bulkAfter() {        
}

public void beforeInsert(SObject so) {
    Outstanding__c os = (Outstanding__c)so;
    String prodgrp;
    Set<Outstanding_Product_Group_Index_Mapping__c> setOfSettings = new Set<Outstanding_Product_Group_Index_Mapping__c>();
    if(os.Product_Division__c != NULL && os.Days_Due__c != NULL) {
        for(String proddivs: mapOfProdDivsAndGrp.keySet()) {
            if(proddivs.contains(os.Product_Division__c)) {
                prodgrp = mapOfProdDivsAndGrp.get(proddivs);
                os.Product_Group_Index__c = prodgrp;
            }    
        }
        try {
            setOfSettings = mapOfGroupAndSetting.get(prodgrp);
            for(Outstanding_Product_Group_Index_Mapping__c opgi : setOfSettings) {
                if(os.Days_Due__c <= opgi.Due_Days_Upper_Limit__c && os.Days_Due__c > opgi.Due_Days_Lower_Limit__c) {
                    if(opgi.Index_Type__c == 'Higher') {
                        os.Higher_Approval_Level_Index__c = opgi.Approval_Index__c;
                    }    
                    if(opgi.Index_Type__c == 'Lower') {
                        os.Lower_Approval_Level_Index__c = opgi.Approval_Index__c;
                    }    
                }
            }        
        } catch (Exception ee) {
            ExceptionLogging.addException('Outstanding Trigger Handler', ee);
        }    
    } else {
        os.Higher_Approval_Level_Index__c = NULL;
        os.Lower_Approval_Level_Index__c = NULL;
    }
}

public void beforeUpdate(SObject oldSo, SObject so) {
}

public void beforeDelete(SObject so) {    
}

public void afterInsert(SObject so ) {   
}

public void afterUpdate(SObject oldSo, SObject so) { 
}

public void afterDelete(SObject so) {
}

public void andFinally() {
    ExceptionLogging.saveException();                
}
}

The Exception I am getting at the line for(Outstanding_Product_Group_Index_Mapping__c opgi : setOfSettings): is below -

System.NullPointerException
Attempt to de-reference a null object           
Class.Outstanding_TriggerHandler.beforeInsert: line 56, column 1

But I resolved the issue when I put an if condition for all the code in the try block:

if(mapOfGroupAndSetting.containsKey(prodgrp))

So I guess this line may also be causing the issue:

setOfSettings = mapOfGroupAndSetting.get(prodgrp);
0

3 Answers 3

3

Yes, I'd expect you to get a NullPointerException if the custom setting you've called "isEmpty".

Note that I'm taking you literally from a coding standpoint.

isEmpty() returns true where objects & variables are null, for an empty string (''), a list with zero elements, a set with zero elements, and when a map has zero key-value pairs. When a set, list or map isEmpty(), there's nothing to iterate on.

7
  • If you attempt to use isEmpty() on a null object or variable it will throw a DNR error. It only check if a NON NULL object or variable list, set, map contains no items - re this statement (isEmpty() returns true where objects & variables are null)
    – Eric
    Mar 18, 2017 at 15:02
  • See this from Apex Docs which is where my answer came from. DNR? That acronym isn't registering with me at the moment. IsEmpty can be used 2 ways depending on context. someVar.isEmpty() and isEmpty(someVar). Are you referring to the diff between the two?
    – crmprogdev
    Mar 18, 2017 at 15:28
  • Dereference Null Object. Dang autocorrect. and if you do somevar.isEmpty() it will throw that if the object is null. Not sure if that was the context you meant or not. The doc you linked says: "Returns true if the list has zero elements" not null. isEmpty(someVar) will work if null
    – Eric
    Mar 18, 2017 at 15:30
  • Thank you for the clarification. Yes you can use listVar.isEmpty() to test to see if there are zero elements & isEmpty(listVar) would test for null. Although I've always understood the latter's primary usage to be for testing strings. It's always aggravated me how unclear the documentation is on whether to enclose or append methods to variables in cases like this one.
    – crmprogdev
    Mar 18, 2017 at 15:41
  • You are correct isEmpty(somevar) is for strings. Docs do leave a lot on the table and require one to piece a lot of assumptions together.
    – Eric
    Mar 18, 2017 at 15:43
1

Empty collection references do not throw a NullPointerException when accessed in a for loop using iterators, the loop simply exits without any iteration. On the other hand, null collection references do throw a NullPointerException when accessed in a for loop. This behavior can be tested with the following:

Set<String> testSet = new Set<String>();
for(string i : testSet)
{
    System.debug('Iterated Empty');
}
System.debug('For Loop Executed on Empty');
testSet = null;
for(String i : testSet)
{
    System.debug('Iterated Null');
}
System.debug('For Loop Executed on Null');

In your particular case, I think your issue is that one of your custom settings has a null field somewhere, though I'm still trying to figure out where that causes your logic to try to retrieve a map key that does not exist (which returns null, which sets your setOfSettings variable to null before trying to iterate).

0

Instead of this -

try {
        setOfSettings = mapOfGroupAndSetting.get(prodgrp);
        for(Outstanding_Product_Group_Index_Mapping__c opgi : setOfSettings) {
            if(os.Days_Due__c <= opgi.Due_Days_Upper_Limit__c && os.Days_Due__c > opgi.Due_Days_Lower_Limit__c) {
                if(opgi.Index_Type__c == 'Higher') {
                    os.Higher_Approval_Level_Index__c = opgi.Approval_Index__c;
                }    
                if(opgi.Index_Type__c == 'Lower') {
                    os.Lower_Approval_Level_Index__c = opgi.Approval_Index__c;
                }    
            }
        }        
    } catch (Exception ee) {
        ExceptionLogging.addException('Outstanding Trigger Handler', ee);
    } 

Check if values are null or not as below -

if(mapOfGroupAndSetting.containsKey(prodgrp) && mapOfGroupAndSetting(prodgrp) != null && mapOfGroupAndSetting(prodgrp) != ''){
setOfSettings = mapOfGroupAndSetting.get(prodgrp);
for(Outstanding_Product_Group_Index_Mapping__c opgi : setOfSettings) {
    if(os.Days_Due__c <= opgi.Due_Days_Upper_Limit__c && os.Days_Due__c > opgi.Due_Days_Lower_Limit__c) {
        if(opgi.Index_Type__c == 'Higher') {
            os.Higher_Approval_Level_Index__c = opgi.Approval_Index__c;
        }    
        if(opgi.Index_Type__c == 'Lower') {
            os.Lower_Approval_Level_Index__c = opgi.Approval_Index__c;
        }    
    }
}        

}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .