0

I realize there are a lot of 'de-reference a null object' questions out there and I've damn near read them all, but I still can't figure out why the Account.Id is null in my code. I've tried instantiating the Account and using if statements to check to see if there are nulls, but nothing is working for me.

The following is my controller:

/*
    *This is a controller class for a contact search within all of Salesforce. 
    *It brings results back to the page in real time. 
    *There is visualforce page that goes with this controller - ContactSearchPage - 
    *This page could be transformed into a visualforce component and used within another visualforce page. 
    *This controller, page, or component can be changed to use any object in salesforce or multiple objects if needed. 
    *It can be customized to fit any search application that might be required. 

 */
public with sharing virtual class AccountSearchController {

    // the soql without the order and limit
    private String soql {get;set;}
    // the collection of contacts to display
    public List<Account> accounts {get;set;}
    public CLSearchDataClass aData {
        get{
            return aData;
        }
        set;
    }
    public Boolean isSelected {
        get {if (isSelected == null)
            isSelected = false;
            return isSelected;
        }        
        set; 
    }
    //Account account;
    /*public Account getAccount() {
        if(account == null)
            account = [select id, name, site from Account
                       where id = :ApexPages.currentPage().getParameters().get('id')];
        return account;
    }*/
    public Account account{
        get{
            return account;
        }
        set;
    }
    public String acctId {
        get {
            if (acctId == null) acctId = 'null';
            return acctId;
        }
        set{
        }
    }

    // the current sort direction. defaults to asc
    public String sortDir {
        get  { if (sortDir == null) {  sortDir = 'asc'; } return sortDir;  }
        set;
    }

    // the current field to sort by. defaults to last name
    public String sortField {
        get  { if (sortField == null) {sortField = 'name'; } return sortField;  }
        set;
    }

    // format the soql for display on the visualforce page
    public String debugSoql {
        get { return soql + ' order by ' + sortField + ' ' + sortDir + ' limit 10'; }
        set;
    }

    // init the controller and display some sample data when the page loads
    public AccountSearchController() {
        soql = 'select Id, name, Industry, Zip_Postal_Code__c, Owner.id, parent.name, parent.id, Country_Code__c from account where name != null';  
        runQuery();
    }

    // toggles the sorting of query from asc<-->desc
    public void toggleSort() {
        // simply toggle the direction
        sortDir = sortDir.equals('asc') ? 'desc' : 'asc';
        // run the query again
        runQuery();
    }
    // runs the actual query
    public void runQuery() {
        try {
            accounts = Database.query(soql + ' order by ' + sortField + ' ' + sortDir + ' limit 10');
        } catch (Exception e) {
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'Ooops!'));
            System.debug('Error ' + e);
        }
    }

    // runs the search with parameters passed via Javascript
    public PageReference runSearchA() {
        //Account 
        String acctName = Apexpages.currentPage().getParameters().get('acctname');
        //String zipCode = Apexpages.currentPage().getParameters().get('zipCode');
        String PAcctName = Apexpages.currentPage().getParameters().get('PAcctName');
        String acctIndustry = Apexpages.currentPage().getParameters().get('acctIndustry');
        String acctCountry = Apexpages.currentPage().getParameters().get('acctCountry'); 
        //ID AcctId = Apexpages.currentPage().getParameters().get('AcctId');

        //Account  
        soql = 'select Id, name, Industry, Zip_Postal_Code__c, Owner.id, parent.name, parent.id, Country_Code__c from account where name != null';
        if (!acctName.equals(''))
            soql += ' and name LIKE \''+String.escapeSingleQuotes(acctName)+'%\'';
        //if (!zipCode.equals(''))
        //soql += ' and Zip_Postal_Code__c LIKE \''+String.escapeSingleQuotes(zipCode)+'%\'';
        if (!PAcctName.equals(''))
            soql += ' and parent.name LIKE \''+String.escapeSingleQuotes(PAcctName)+'%\'';  
        if (!acctIndustry.equals(''))
            soql += ' and Industry LIKE \''+acctIndustry+'\'';
        if (!acctCountry.equals(''))
            soql += ' and Country_Code__c LIKE \''+acctCountry+'\'';

        // run the query again    
        runQuery();

        return null;
    }

    // use apex describe to build the picklist values
    public List<String> industries {
        get {
            if (industries == null) {
                industries = new List<String>();
                Schema.DescribeFieldResult field = Schema.Account.Industry.getDescribe();

                for (Schema.PicklistEntry f : field.getPicklistValues())
                    industries.add(f.getValue());
            }
            return industries;
        }
        set;
    }
    public List<String> accCountry {
        get {
            if (accCountry == null) {
                accCountry = new List<String>();
                schema.DescribeFieldResult field = Schema.Account.Country_Code__c.getDescribe();
                for (Schema.PicklistEntry f : field.getPicklistValues())
                    accCountry.add(f.getValue());
            }
            return accCountry;          
        }
        set;
    }

    public void selectAcct(){
        if(isSelected = true){
            aData.acctId = acctId; **<-- This is where it's saying the null reference is**
            system.debug(aData.acctId);
        }
    }

    public List<SelectOption> getItems() {
        List<SelectOption> options = new List<SelectOption>();
        if(accounts.size() > 0){
            for (Account acc : accounts)
            {
                if(acc.Id != null){
                    options.add(new SelectOption(acc.Id, acc.Name));
                }
            }
        }
        return options;
    }
}

The following is my VisualForcePage:

<apex:component controller="AccountSearchController" >
    <apex:attribute type="CLSearchDataClass" name="accData" required="true" description="Account Data" assignTo="{!aData}"/>
  <apex:pageMessages id="errors" />

  <!--<apex:pageBlock title="Find a Account" mode="edit">-->


    <table width="100%" border="0">
  <tr>  
    <td width="200" valign="top">

      <apex:pageBlock title="Parameters" mode="edit" id="criteria">

      <script type="text/javascript">
          function doAccountSearch() 
          {
              searchServer(document.getElementById("acctName").value, document.getElementById("PAcctName").value,
                           document.getElementById("acctIndustry").options[document.getElementById("acctIndustry").selectedIndex].value,
                           document.getElementById("acctCountry").options[document.getElementById("acctCountry").selectedIndex].value);
          }
           function enableDisable(cb)
          {
              $("input:checkbox[id*=selectAccountRow]").removeAttr('checked');
              $(cb).attr('checked', 'checked');
          }

          var previousCheckId;

          function toggle(chkBox) {
            if (chkBox.checked){
                if(previousCheckId) {
                  document.getElementById(previousCheckId).checked = false;
              }

                previousCheckID = chkBox.getAttribute('id');

              }
          }


      </script> 

      <apex:actionFunction name="searchServer" action="{!runSearchA}" rerender="resultsA,debug,errors">
          <!--Accounts-->
          <apex:param name="acctName" value="" />
          <!--<apex:param name="zipCode" value="" />-->
          <apex:param name="PAcctName" value="" />
          <apex:param name="acctIndustry" value="" />
          <apex:param name="acctCountry" value="" />
      </apex:actionFunction>

      <table cellpadding="2" cellspacing="2">
      <tr>
        <td style="font-weight:bold;">Account Name<br/>
        <input type="text" id="acctName" onkeyup="doAccountSearch();"/>
        </td>
      </tr>
      <!--<tr>
        <td style="font-weight:bold;">Zip Code<br/>
        <input type="text" id="zipCode" onkeyup="doAccountSearch();"/>
        </td>
      </tr>-->
      <tr>
        <td style="font-weight:bold;">Parent Account<br/>
        <input type="text" id="PAcctName" onkeyup="doAccountSearch();"/>
        </td>
      </tr>
      <tr>
        <td style="font-weight:bold;">Industries<br/>
          <select id="acctIndustry" onchange="doAccountSearch();">
            <option value=""></option>
            <apex:repeat value="{!industries}" var="tech">
              <option value="{!tech}">{!tech}</option>
            </apex:repeat>
          </select>
        </td>
      </tr>
      <tr>
        <td style="font-weight:bold;">Country<br/>
          <select id="acctCountry" onchange="doAccountSearch();">
            <option value=""></option>
            <apex:repeat value="{!accCountry}" var="country">
              <option value="{!country}">{!country}</option>
            </apex:repeat>
          </select>
        </td>
      </tr>
          </table>

      </apex:pageBlock>

    </td>
    <td valign="top" width="775">

    <apex:pageBlock mode="edit" id="resultsA">

        <apex:pageBlockTable value="{!accounts}" var="account" align="top">
            <apex:column >
                <apex:inputCheckbox id="selectAccountRow" value="{!isSelected}" onclick="return checkone(this,'{!account.id}')">
                    <apex:param value="{!account.id}"/>
                    <apex:inputHidden id="acctId" value="{!acctId}"/>
                    <apex:actionSupport event="onclick" action="{!selectAcct}" /> 
                </apex:inputCheckbox>
                    <!--<apex:selectCheckboxes id="selectAccountRow">
                        <apex:selectOptions value="{!items}" >
                            <apex:actionSupport event="onclick" action="{!selectAcct}" /> 
                        </apex:selectOptions>
                    </apex:selectCheckboxes>-->
            </apex:column>
            <apex:column >
                <apex:facet name="header">
                    <apex:commandLink value="Account" action="{!toggleSort}" rerender="resultsA,debug" >
                        <apex:param name="sortField" value="Name" assignTo="{!sortField}"/>
                    </apex:commandLink>
                </apex:facet>
                    <a href="/{!account.Id}"
                       id="{!account.Id}" 
                       onblur="LookupHoverDetail.getHover('{!account.Id}').hide();" 
                       onfocus="LookupHoverDetail.getHover('{!account.Id}', '/{!account.Id}/m?retURL=%2F{!account.Id}&isAjaxRequest=1').show();" 
                       onmouseout="LookupHoverDetail.getHover('{!account.Id}').hide();" 
                       onmouseover="LookupHoverDetail.getHover('{!account.Id}', '/{!account.Id}/m?retURL=%2F{!account.Id}&isAjaxRequest=1').show();">
                       {!account.Name}
                    </a>
            </apex:column>
            <apex:column >
                <apex:facet name="header">
                    <apex:commandLink value="Country" action="{!toggleSort}" rerender="resultsA,debug">
                        <apex:param name="sortField" value="Country_Code__c" assignTo="{!sortField}"/>
                    </apex:commandLink>
                </apex:facet>
                <apex:outputField value="{!account.Country_Code__c}"/>
            </apex:column>
            <apex:column >
                <apex:facet name="header">
                    <apex:commandLink value="Industry" action="{!toggleSort}" rerender="resultsA,debug">
                        <apex:param name="sortField" value="industry" assignTo="{!sortField}"/>
                    </apex:commandLink>
                </apex:facet>
                <apex:outputField value="{!account.industry}"/>
            </apex:column>

            <apex:column >
                <apex:facet name="header">
                    <apex:commandLink value="Parent Account" action="{!toggleSort}" rerender="resultsA,debug">
                        <apex:param name="sortField" value="parent.name" assignTo="{!sortField}"/>
                    </apex:commandLink>
                </apex:facet>
                <apex:outputField value="{!account.parent.name}"/>
            </apex:column>
        </apex:pageBlockTable>
    </apex:pageBlock>
    </td>
  </tr>
  </table>

     <!-- <td valign="bottom">
  <apex:pageBlock title="Debug - SOQL" id="debug">
      <apex:outputText value="{!debugSoql}" />           
  </apex:pageBlock>  
      </td>-->

 <!--</apex:pageBlock>-->

</apex:component>

It's saying the null reference is in the public void selectAcct()

Please let me know if there are any questions or if I need to clarify anything.

1 Answer 1

2

You have a lot of problems in your code, but to answer the first question: you never initialized aData, so it is null.

// init the controller and display some sample data when the page loads
  public AccountSearchController() {
    aData = new CLSearchDataClass(); // Initialize here
    soql = 'select Id, name, Industry, Zip_Postal_Code__c, Owner.id, parent.name, parent.id, Country_Code__c from account where name != null';  
    runQuery();
  }

Secondly, you're "lazy-loading" way too much. Only use the technique if you don't know if you need the data (it appears you always do, so you may as well initialize everything in the constructor).

This line here will always execute:

  if(isSelected = true){

Using a single equals sign is an assignment, which results in isSelected always being set to true, and the branch is always executed (because the return value is true). Use == instead.

For some minor optimizations:

    if(accounts.size() > 0){
        for (Account acc : accounts)
        {
            if(acc.Id != null){
            options.add(new SelectOption(acc.Id, acc.Name));
            }
        }
    }

It's legal to iterate over an empty list, and checking for empty beforehand just wastes CPU time and makes code more verbose. Also, since acc is coming from a query, Id will never be null.

    for (Account acc : accounts) {
        options.add(new SelectOption(acc.Id, acc.Name));
    }

public PageReference runSearchA() {
    ...
    return null;
}

If you're never going to redirect, just use void. Returning a PageReference suggests that you could redirect, which is misleading. Doubly so if someone is using the Summary view of your class.

3
  • thank you so much, sfdcfox, for your advice and insights. I'm pretty new to salesforce and still learning a lot. It was also complaining about acctId being null so I had to initiate the Account object as well. My code is now running successfully, but in the logs it's still saying aData is null. I'm confused as to why it's not passing the value.. Any ideas? Apr 1, 2015 at 18:47
  • How are you debugging this? Did you change your constructor? What error or behavior are you seeing?
    – sfdcfox
    Apr 1, 2015 at 19:13
  • Unfortunately, I'm debugging in the developer console that SalesForce provides.. I changed everything that you recommended. With the changes I implemented that you mentioned above, I'm still getting the following in my logs: 16:25:55:112 CODE_UNIT_FINISHED AccountSearchController set(aData,null); 16:25:55:112 CODE_UNIT_STARTED [EXTERNAL]|AccountSearchController set(aData,null); 16:25:55:064 VARIABLE_ASSIGNMENT [EXTERNAL]|this.aData|null|0x30a3d194 Apr 1, 2015 at 20:27

You must log in to answer this question.

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