1

Hi I am getting a null error for this trigger. It seems to be that when I leave the Product Total Warranty Days and Product Purchase Date field empty while creating a case, then it will result in a null exception error.

What can I do to not run when any of those two fields are null or default to 0 when those fields are null when creating a case.

trigger WarrantySummary on Case (before Insert) {

for (Case myCase : Trigger.new) {
    //Set up variables to use in the summary field
    String purchaseDate        = myCase.Product_Purchase_Date__c.format();
    String createdDate          = DateTime.now().format();
    Integer warrantyDays       = myCase.Product_Total_Warranty_days__c.intValue();

    Decimal warrantyPercentage = (100 * (myCase.Product_Purchase_Date__c.daysBetween(Date.today())
                                    /myCase.Product_Total_Warranty_Days__c)).setScale(2);
    Boolean hasExtendedWarranty= myCase.Product_Has_Extended_Warranty__c;
    String endingStatement = 'Have a nice day!';

    // Populate summary field
    myCase.Warranty_Summary__c  = 'Product purchased on ' + purchaseDate + ' '
                               + 'and case created on ' + createdDate + '.\n'
                               + 'Warranty is for ' + warrantyDays + ' '
                               + 'days and is ' + warrantyPercentage + '% through its warranty period.\n'
                               + 'Extended warranty: ' + hasExtendedWarranty + '\n'
                               + endingStatement;

3 Answers 3

4

You can add guards inline such as:

Integer warrantyDays = myCase.Product_Total_Warranty_days__c != null
        ? myCase.Product_Total_Warranty_days__c.intValue()
        : 0;

or better create utility methods in a class:

public class Guarded {
    public static Integer toInteger(Decimal d) {
        return d != null ? d.intValue() : 0;
    }
    ...
}

so in the trigger you have the simpler code:

 Integer warrantyDays = Guarded.toInteger(myCase.Product_Total_Warranty_days__c);

To avoid divide by zero errors, check if the divisor is zero explicitly in your code and set the result to the value you want and/or use the addError method on the divisor field to signal the problem back to the UI.

Include the null value cases and divide by zero cases in the unit test cases for the trigger. The bottom line is that you need to think through and plan for the possibilities that the UI allows.

Generally speaking, write code that works in the normal case (where blank fields are quite normal) and resist using try/catch as adding that often obscures errors other than the ones you are thinking about and so hides bad code and makes debugging hard.

2
  • Thanks this worked for me. Question: why does an Apex class yield more utility? Is it because there is more global application?
    – JsonNoob
    Apr 14, 2018 at 17:58
  • @JsonNoob Triggers don't support moving code that you want to call many times into a method but classes do. Once the class/method is written you can call it many times from one trigger or indeed from any trigger or other class. Generally best to write something once - see DRY.
    – Keith C
    Apr 14, 2018 at 18:52
1

try-catch blocks are the safe way to deal with this, but may not give you the error handling granularity you need:

for(Case myCase : trigger.New)
{
    try
    {
        //operation that may divide by zero
    }
    catch(DivideByZeroException ex)
    {
        //Handle error, or just leave empty to move to the next case
    }
    catch(NullPointerException ex)
    {
    }
}

You can also use an if statement to check whether a field is zero or null before using it:

for(Case myCase : trigger.New)
{
    if (myCase.Product_Total_Warranty_Days__c != null && myCase.Product_Total_Warranty_Days__c != 0) 
    {
        //Do operation
    }
    else
    {
        //Handle error, or just leave empty to move to the next case
    }
}
2
  • The if statement made sense to me and worked for me. Thanks!
    – JsonNoob
    Apr 14, 2018 at 17:59
  • 1
    Huge performance hit. Much better to avoid exception if possible. Especially if calling in loop.
    – Adrian Larson
    Apr 14, 2018 at 19:18
1

I'll just add one more strategy - when dealing with loops, if you want to skip this iteration of the loop if it doesn't meet certain conditions, you can use continue;. So:

for(Case myCase : trigger.New){
  if (/* insert conditions here for skipping the calculation*/){
    // set a default value instead and then...
    continue;
  }
  // the rest of the code will now only execute if it didn't meet the skip conditions
}

While this is functionally the same as wrapping the whole rest of the loop in an "else" as IllusiveBrian suggested, if you have several guard conditions with different outcomes you can avoid having the rest of the body of the loop nested many levels deep in braces.

You must log in to answer this question.

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