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
RossGRossG 

attempt to de-reference a null object error

I'm getting this error.  Ususally I can resolve it but I can't seem to on this one.

This is a visualforce page with custom controller that is basically a custom product picker on opportunity object.  The error I get when trying to add a product to the opp is:

Attempt to de-reference a null object
Error is in expression '{!modifyRecord}' in page manage_products: Class.ManageProductsController.modifyRecord: line 324, column 1



Does anyone see anything in this code below that could be causing the error?
 
public class ManageProductsController {


    /* Controller for "Manage Products" Visualforce Page, aka the "product picker" */
    

    // Declare static variables
    private static final Map<String,String> PRODUCT_FILTER_VALUES_MAP;  
    private static final Set<String> COREBLOX_PRODUCT_CODES = new Set<String>{'CBWK-H-PUL','PE-CS-CBWS'};
    private static final Set<String> VALID_CHOICES_SET = new Set<String>{ 'CIC','CK','SC','TT' };
    private static final Set<Id> ADMIN_PROFILE_ID_SET; // Which profiles can use product picker to edit won Opps
    private static final string PICKLIST_DEFAULT = 'All'; //defailt picklist value

    // Declare public class variables
    public Boolean editAfterClosed { get { return (editAfterClosed == null) ? false : editAfterClosed; } set; }
    public Boolean showAddProductsPanel { get { return (showAddProductsPanel == null) ? false : showAddProductsPanel; } set; }
    public String action { get; set; }
    public String productFilter { get; set; }
    public String useCase { get; set; }
    public String capability { get; set; }
    public String license { get; set; }
    public String upToQuantity { get; set; }
    public Id currentOliId { get; set; }
    public Opportunity currentOpp { get; set; }
    public List<OpportunityLineItem> oliExistingList { get; set; }
    public List<OpportunityLineItem> oliPickerList { get; set; }
    public List<PricebookEntry> pbeListActive { get; set; }
    public List<SelectOption> productFilterValues { get; set; }
    public Map<Id,Decimal> pbeCalculableSupportProductMap { get; set; }
    public Map<Id,String> pbeProductCodeMap { get; set; }
    public Map<Id,String> pbeProductNameMap { get; set; }
    public Map<Id,OpportunityLineItem> oliDetailsMap { get; set; }   
    
    // Declare private class variables
    private ApexPages.StandardController stdController;
    private List<OpportunityLineItem> oliNewList = new List<OpportunityLineItem>();
    private List<PricebookEntry> pbeListAll = new List<PricebookEntry>();
    private Map<Id,PricebookEntry> pbeDetailsMapAll = new Map<Id,PricebookEntry>();
    private Map<Id,PricebookEntry> pbeDetailsMapActive = new Map<Id,PricebookEntry>();

    // Instantiate static variables
    static { 
    
        ADMIN_PROFILE_ID_SET = new Set<Id>{
            '00e40000000rTp1', // Custom Contract Admin
            '00e30000000bzB3'  // System Administrator
        };   
        
        PRODUCT_FILTER_VALUES_MAP = new Map<String,String>{
            'All'   =>    'All',
            'Bundles'    =>    'CB',
            'Cloud Identity Connector'   =>    'CIC',
            'Commercial Integration Kit'    =>    'CK',
            'Connection Based'  =>    'CONN',
            'CoreBlox'    =>    'CoreBlox',
            'Discount'  =>    'Cust',
            'ELA'    =>    'ELA',
            'Endpoint'    =>    'EP',
            'Oauth Add-on'   =>    'OAA',
            'Oauth Standalone' => 'OAS',
            'PingAccess'    =>    'PA',
            'PingConnect' => 'PC',
            'PingEnable Consulting' => 'PE',
            'PingFed Server' => 'PFS',
            'PingOne' => 'PO',
            'PingEnable Training' => 'PT',
            'Saas Program Bundle' => 'Saas',
            'SaaS Connector' => 'SC',
            'STS Add-on' => 'SSA',
            'STS Standalone' => 'SSS',
            'Support' => 'SUP',
            'Token Translator' => 'TT',
            'WAM Integration Kit' => 'WMIK',
            'WAM Token Translator' => 'WMTT'
        };
    }
    
        
    /* Constructor */
    public ManageProductsController(ApexPages.StandardController stdController) { 
    
        // Instantiate class variables
        this.stdController = stdController;               
        currentOpp = (Opportunity)stdController.getRecord();
        
        editAfterClosed = false; // Default value
        if (ADMIN_PROFILE_ID_SET.contains(UserInfo.getProfileId())) {
            editAfterClosed = true;
        }

        productFilterValues = new List<SelectOption>();
        for (String s : PRODUCT_FILTER_VALUES_MAP.keySet()) {
            productFilterValues.add(new SelectOption(PRODUCT_FILTER_VALUES_MAP.get(s),s));
        }
        productFilterValues.sort(); 
               
        oliDetailsMap = new Map<Id,OpportunityLineItem>();
        oliExistingList = new List<OpportunityLineItem>();
        oliPickerList = new List<OpportunityLineItem>();
        pbeListActive = new List<PricebookEntry>();
        pbeCalculableSupportProductMap = new Map<Id,Decimal>();
        pbeProductCodeMap = new Map<Id,String>();
        pbeProductNameMap = new Map<Id,String>();
                       
        refreshData();
    }
    
    
    /* STATIC METHODS */
    
    /* Return set of Product Code values under 'CoreBlox' category in picker filter */
    public static Set<String> getCoreBloxProductCodes(){
        return COREBLOX_PRODUCT_CODES;
    }
    
    /**
    * Method returns a list of Product Use Case values as select options.
    *
    * @return a list of notes as select options
    */
    public List<SelectOption> getUseCaseOptions() {
     List<SelectOption> options = new List<SelectOption>();
    
     // Use schema describe functionality to generate list of options
     Schema.DescribeFieldResult fieldResult = Product2.Use_Case__c.getDescribe();
     options.add(new SelectOption(PICKLIST_DEFAULT,PICKLIST_DEFAULT));//add defailt value to picklist
     List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();
     for(Schema.PicklistEntry f : ple) {
       options.add(new SelectOption(f.getLabel(), f.getValue()));
     }
   
     return options;
    }
    
    /**
    * Method returns a list of Product Capability values as select options.
    *
    * @return a list of notes as select options
    */
    public List<SelectOption> getCapabilityOptions() {
     List<SelectOption> options = new List<SelectOption>();
    
     // Use schema describe functionality to generate list of options
     Schema.DescribeFieldResult fieldResult = Product2.Capability__c.getDescribe();
     options.add(new SelectOption(PICKLIST_DEFAULT,PICKLIST_DEFAULT));//add defailt value to picklist
     List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();
     for(Schema.PicklistEntry f : ple) {
       options.add(new SelectOption(f.getLabel(), f.getValue()));
     }
   
     return options;
    }
    
    /**
    * Method returns a list of Product License values as select options.
    *
    * @return a list of notes as select options
    */
    public List<SelectOption> getLicenseOptions() {
     List<SelectOption> options = new List<SelectOption>();
    
     // Use schema describe functionality to generate list of options
     Schema.DescribeFieldResult fieldResult = Product2.License__c.getDescribe();
     options.add(new SelectOption(PICKLIST_DEFAULT,PICKLIST_DEFAULT));//add defailt value to picklist
     List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();
     for(Schema.PicklistEntry f : ple) {
       options.add(new SelectOption(f.getLabel(), f.getValue()));
     }
   
     return options;
    }
    
    /**
    * Method returns a list of Product Up_to_Quantity values as select options.
    *
    * @return a list of notes as select options
    */
    public List<SelectOption> getUpToQuantityOptions() {
     List<SelectOption> options = new List<SelectOption>();
    
     // Use schema describe functionality to generate list of options
     Schema.DescribeFieldResult fieldResult = Product2.Up_to_Quantity__c.getDescribe();
     options.add(new SelectOption(PICKLIST_DEFAULT,PICKLIST_DEFAULT));//add defailt value to picklist
     List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();
     for(Schema.PicklistEntry f : ple) {
       options.add(new SelectOption(f.getLabel(), f.getValue()));
     }
   
     return options;
    }


    /* CLASS METHODS */
    
    /* Add new product line items to Opportunity */
    public void addProducts() {
    
        // Declare method variables
        PricebookEntry pbe;
        
        // Prepare selected items for insertion
        for (OpportunityLineItem oli : oliPickerList) {
        
            if (oli.Selected__c) {
            
                // Reset record-level variables
                pbe = pbeDetailsMapActive.get(oli.PricebookEntryId);
            
                // Set "Discount" to default value of 0 unless list price is 0 (in which case no discount could be applied)
                // Since record has not yet been inserted, cannot leverage formula field and must use map instead
                if (pbeDetailsMapActive.get(oli.PricebookEntryId).UnitPrice != 0 && oli.Discount__c == null) {
                    oli.Discount__c = 0;
                }
                oli.Selected__c = FALSE;
                
                // Perform additional processing
                if (pbe.Product2.Calculate_Support_Pricing__c == 0) {
                    
                    // Set "Full Description"
                    oli.Full_Description__c = '';

                    if (pbe.Product2.Price_Book_Group__c != null) {
                        oli.Full_Description__c += ' - ' + pbe.Product2.Price_Book_Group__c;
                    }
                    if (pbe.Product2.Price_Book_Type__c != null) {
                        oli.Full_Description__c += ' - ' + pbe.Product2.Price_Book_Type__c;
                    }
                    if (pbe.Product2.Price_Book_Environment__c != null) {
                        oli.Full_Description__c += ' - ' + pbe.Product2.Price_Book_Environment__c;
                    }
                    if (pbe.Product2.Price_Book_License__c != null) {
                        oli.Full_Description__c += ' - ' + pbe.Product2.Price_Book_License__c;
                    }
                    if (pbe.Product2.Price_Book_Service__c != null) {
                        oli.Full_Description__c += ' - ' + pbe.Product2.Price_Book_Service__c;
                    }
                    if (pbe.Product2.Price_Book_Term__c != null) {
                        oli.Full_Description__c += ' - ' + pbe.Product2.Price_Book_Term__c;
                    }
                    if (pbe.Product2.Price_Book_Detailed_Description__c != null) {
                        oli.Full_Description__c += ' - ' + pbe.Product2.Price_Book_Detailed_Description__c;
                    }
                    
                    // Set various fields related to the "Choices" field
                    if (oli.Choices__c == 'CIC') {
                        oli.Cloud_Identity_Connectors__c = oli.Connector_Choice__c;                     
                    } else if (oli.Choices__c == 'CK') {
                        oli.Commercial_Integration_Kit__c = oli.Connector_Choice__c; 
                    } else if (oli.Choices__c == 'SC') {          
                        oli.SaaS_Connectors__c = oli.Connector_Choice__c;  
                    } else if (oli.Choices__c == 'TT') {
                        oli.Commercial_Translators__c = oli.Connector_Choice__c; 
                    }
                }                
                oliNewList.add(oli);
            }
        }
        
        // Insert new line items
        if (!oliNewList.isEmpty()) {
            try {            
                // Insert new line items
                insert oliNewList;
                hideAddProductsPanel();
                refreshData();
                updateCalculatedSupportProducts();
            } catch (DMLException e) {
                ApexPages.addMessages(e);
            }
            oliNewList.clear();
        }
    }
    
    
    /* Redirect user to pricebook selection page if pricebook is not yet selected */
    public PageReference displayAppropriatePage() {
        
        // Declare method variables
        PageReference pageRef = null;
        
        // Perform redirection as appropriate
        if (currentOpp.Pricebook2Id == null && currentOpp.OpportunityLineItems.isEmpty()) {
            pageRef = new PageReference(
                '/oppitm/choosepricebook.jsp?id=' + currentOpp.Id
                + '&cancelURL=' + currentOpp.Id 
                + '&saveURL=/apex/Manage_Products?id=' + currentOpp.Id
            );
            pageRef.setRedirect(true);
        }
        
        return pageRef;
    }
        

    /* Disable rendering of add products panel and refresh data */
    public PageReference hideAddProductsPanel() {
        showAddProductsPanel = false;
        return null;
    }
    
    
    /* Update or delete existing products */
    public void modifyRecord() {
    
        // Declare method variables
        OpportunityLineItem currentOli;
        Pricebookentry pbe;
        
        refreshAddProductsTableData();
        
        // Instantiate method variables
        currentOli = oliDetailsMap.get(currentOliId);
        
        pbe = pbeDetailsMapAll.get(currentOli.PricebookEntryId);
        
        // Perform update or delete
        try {
            if (action == 'update') {
                update currentOli;
            } else if (action == 'delete') {
                delete currentOli;
            }
            refreshData();     
            if (pbe.Product2.Calculate_Support_Pricing__c == 0) {
                updateCalculatedSupportProducts();
            }
        } catch (DMLException e) {
            ApexPages.addMessages(e);
        }
    }

    
    /* Respond to user clicking on "Filter by Product Code:" dropdown in add products table */
    public void refreshAddProductsTableData() {
    
        // Declare method variables
        String choices;
        String oppCurrency = currentOpp.CurrencyISOCode;
        String productCodeRoot;
        String productFilterSearchString = productFilter + '%';
        String queryStr;
        Id pricebookId = currentOpp.Pricebook2Id;
        
        // Reset relevant class collections
        oliPickerList.clear();
        pbeListActive.clear();
        pbeListAll.clear();
        pbeCalculableSupportProductMap.clear();
        pbeProductCodeMap.clear();
        pbeProductNameMap.clear();
        
        // Build query
        queryStr = 'SELECT ';
        queryStr += 'Id, ';
        queryStr += 'IsActive, ';
        queryStr += 'Name, ';
        queryStr += 'ProductCode, ';
        queryStr += 'Product2Id, ';
        queryStr += 'Product2.Calculate_Support_Pricing__c, ';
        queryStr += 'Product2.Default_Support_Percentage__c, ';
        queryStr += 'Product2.Description, ';
        queryStr += 'Product2.Price_Book_Detailed_Description__c, ';
        queryStr += 'Product2.Price_Book_Environment__c, ';
        queryStr += 'Product2.Price_Book_Group__c, ';
        queryStr += 'Product2.Price_Book_License__c, ';
        queryStr += 'Product2.Price_Book_Service__c, ';
        queryStr += 'Product2.Price_Book_Term__c, ';
        queryStr += 'Product2.Price_Book_Type__c, ';
        queryStr += 'Product2.ProductCode, ';
        queryStr += 'UnitPrice ';
        queryStr += 'FROM PricebookEntry ';
        queryStr += 'WHERE Pricebook2Id = :pricebookId ';
        queryStr += 'AND CurrencyISOCode = :oppCurrency ';
        if (productFilter != 'All') {
            if (productFilter == 'CoreBlox') { 
                queryStr += 'AND ProductCode IN :COREBLOX_PRODUCT_CODES ';
            } else {
                queryStr += 'AND ProductCode LIKE :productFilterSearchString ';
            }
        }
        if (useCase != 'All'){
          queryStr += 'AND Product2.Use_Case__c = :useCase ';
        }
        if (capability != 'All'){
          queryStr += 'AND Product2.Capability__c = :capability ';
        }
        if (license != 'All'){
          queryStr += 'AND Product2.License__c = :license ';
        }
        if (upToQuantity != 'All'){
          queryStr += 'AND Product2.Up_to_Quantity__c = :upToQuantity ';
        }
        queryStr += 'ORDER BY Name ';
        
        // Retrieve records and refill collections
        pbeListAll.addAll((List<PricebookEntry>)Database.query(queryStr));
        
        for (PricebookEntry pbe : pbeListAll) {
        
            pbeDetailsMapAll.put(pbe.Id,pbe);

            if (pbe.IsActive) {
            
                // Reset record-level variables
                choices = null;
                productCodeRoot = pbe.ProductCode.left(pbe.ProductCode.indexOf('-'));
                
                // Fill collections
                pbeListActive.add(pbe);
                pbeDetailsMapActive.put(pbe.Id,pbe);
                pbeCalculableSupportProductMap.put(pbe.Id,pbe.Product2.Calculate_Support_Pricing__c);
                pbeProductCodeMap.put(pbe.Id, pbe.ProductCode);
                pbeProductNameMap.put(pbe.Id, pbe.Name);
                
                //Determine "Choices" variable
                if (VALID_CHOICES_SET.contains(productCodeRoot)) {
                    choices = productCodeRoot;
                }            
                
                oliPickerList.add(new OpportunityLineItem(
                    Choices__c = choices,
                    OpportunityId = currentOpp.Id,
                    PricebookEntryId = pbe.Id,
                    Quantity = 1, // Default value
                    Support__c = pbe.Product2.Default_Support_Percentage__c,
                    UnitPrice = pbe.UnitPrice
                ));
            }
        }
    }
    
    
    /* Query data and update variables */
    public void refreshData() {   
    
        // Reset variables to default values
        productFilter = 'All';
        showAddProductsPanel = false;
        
        // Refresh Opportunity data     
        currentOpp = [
            SELECT
                Id,
                Amount,
                CurrencyIsoCode,
                IsClosed,
                Name,
                Owner.Name,
                Pricebook2Id,
                StageName,
                (
                    SELECT
                        Id,
                        Choices__c,
                        Connector_Choice__c,
                        Discount__c,
                        Full_Description__c,
                        ListPrice,
                        PricebookEntryId,
                        PricebookEntry.Product2.Calculate_Support_Pricing__c,
                        PricebookEntry.Product2.ProductCode,
                        PricebookEntry.Product2.Name,
                        Quantity,
                        Selected__c,
                        Support__c,
                        Support_Basis__c,
                        Term_End_Date__c,
                        Term_Start_Date__c,
                        TotalPrice,
                        UnitPrice // "Sales Price"
                    FROM OpportunityLineItems
                    WHERE IsDeleted = FALSE
                    ORDER BY SortOrder
                )
            FROM Opportunity
            WHERE Id = :currentOpp.Id
        ];
        
        // Clear collections
        oliExistingList.clear();
        oliDetailsMap.clear();

        // Refill collections
        oliExistingList.addAll(currentOpp.OpportunityLineItems);
        for (OpportunityLineItem oli : oliExistingList) {
            oliDetailsMap.put(oli.Id,oli);
        }
    }

    
    /* Enable rendering of add products panel */
    public PageReference showAddProductsPanel() {
        refreshAddProductsTableData();
        showAddProductsPanel = true;
        return null;
    }   


    /* Evaluate all line items on the Opportunity that require support, sum their total price together,
     * and from there calculate the default pricing for any calculable support products (such as Support
     * Gold) on the Opp.
     */
    private void updateCalculatedSupportProducts() {
    
        // Declare method variables
        Decimal supportBasis = 0;
        String supportDescription = '';
        PricebookEntry pbe;
        List<OpportunityLineItem> oliList = new List<OpportunityLineItem>();
        
        for (OpportunityLineItem oli : oliExistingList) {
        
            // Reset record-level variables
            pbe = pbeDetailsMapAll.get(oli.PricebookEntryId);
            
            // Aggregate non-support line item data
            if (pbe.Product2.Calculate_Support_Pricing__c == 0) {           
             
                if (pbe.Product2.Price_Book_License__c != null && 
                    pbe.Product2.Price_Book_License__c.toLowerCase().contains('perpetual')
                ) {
                
                    supportBasis += oli.Quantity * oli.UnitPrice;
                    
                    if (supportDescription != '') {
                        supportDescription += ', ';
                    }
                    supportDescription += pbe.Product2.ProductCode;
                }
                                
            // Tag as a support line item
            } else { // pbe.Product2.Calculate_Support_Pricing__c != 0                
          //      oliList.add(oli);
            }
        }
        
        if (!oliList.isEmpty()) {
        
            // Perform processing on support line items
            for (OpportunityLineItem oli : oliList) {
            
                // Reset record-level variables
                pbe = pbeDetailsMapAll.get(oli.PricebookEntryId);
                
                // Set price and description
                oli.UnitPrice = supportBasis * oli.Support__c / 100;
                oli.Full_Description__c = supportDescription;
                oli.Support_Basis__c = supportBasis;
            }
            
            // Perform DML
          //  update oliList;
            refreshData();
        }
        
    }
}

 
Balaji BondarBalaji Bondar
Hi,

Initiate the object at Line#307 and try
Pricebookentry pbe = new Pricebookentry ();

Important :
If this is what you were looking for then please mark it as a "SOLUTION" or You can Click on the "Like" Button if this was beneficial for you.
RossGRossG
Thanks.  Do you mean replace "Pricebookentry pbe" with "Pricebookentry pbe = new Pricebookentry ();"?  I tried that but it didn't work.
Balaji BondarBalaji Bondar
Hi,

I am not sure about this relationship pbe.Product2 but you can add not null check on Line#324.
like if(pbe != Null && pbe.Product2 != Null.......)