0

We are a small non-profit . Recently moved our org to Lightning experience. Since the Javascript buttons are not supported , I converted this JavaScript button to VF and called the Apex Controller. After the code runs , I see this error in the log-'Attempt to de-reference a null object' . After debugging I find that the termName and the account records are null , hence this error.

Looking for some guidance to figure this out please.

JavaScript button -

{!REQUIRESCRIPT("/soap/ajax/30.0/connection.js")} 
{!REQUIRESCRIPT("/soap/ajax/30.0/apex.js")} 

var records = {!GETRECORDIDS($ObjectType.Account)}; 
var Id = records.length == 0 ? null : records; 
var message = records.length == 0 ? "all" : records.length; 

var term = prompt("Please enter a term from the selection below: \r\n- Fall\r\n- Winter\r\n- Spring\r\n- Summer"); 
if(term) { 
term = term.toLowerCase(); 
} 
if(term && (term === 'fall' || term === 'spring' || term === 'winter' || term === 'summer')) { 
if (confirm("Click ''OK'' to generate " + term + " Student Terms for " + message + " College/University")) { 
var result = sforce.apex.execute("UniveristyStudentTermGeneratorService", "generateStudentTermsForUniversities", { 
accIds: Id, 
termName: term 
}); 

if (result[0]) { 
//window.location = "{!$Site.BaseUrl}/00O30000008UE9X"; 
alert('The student term generation job has started. Please allow a few minutes for them to be generated.'); 
} else { 
alert("No reponse..."); 
} 
} 
} else { 
alert('Invalid term entered'); 
}

My VF page to replace the script

> <apex:page standardController="Account" tabStyle="Account" recordSetVar="Allaccounts"  extensions="GenerateTerms"   >
    <apex:form >
        <apex:pageBlock title="Generate Student Term">
            <apex:pageBlockButtons >
                <apex:commandButton action="{!generateStudentTermsForUniversities}" value="Confirm"/>
            </apex:pageBlockButtons>
            <apex:pageBlockSection title="Please select the term" collapsible="false">
                <apex:selectList value="{!termName}" multiselect="false" size="1">
                    <apex:selectOption itemValue="Fall" itemLabel="Fall"/>
                    <apex:selectOption itemValue="Spring" itemLabel="Spring"/>
                    <apex:selectOption itemValue="Winter" itemLabel="Winter"/>
                    <apex:selectOption itemValue="Summer" itemLabel="Summer"/>
                </apex:selectList>
            </apex:pageBlockSection>
            <apex:pageBlockTable value="{!accIds}" var="account">
            </apex:pageBlockTable> 
        </apex:pageBlock>
    </apex:form> 
</apex:page>

Apex Controller -

I know that the termName and accids should bring in data from VF to the Apex controller. However they didn't . I used the records variable and it does get initialized in the first constructor, however when I check for its value in the Database,queryLocator, the value is null.

public with sharing class GenerateTerms implements Database.Batchable<sObject>  {
//Construct a standard set controller as controller extension.
PageReference cancel;
Account[] records;
public list<String> accIds{get; set;}
public String termName{get; set;}


public GenerateTerms(ApexPages.StandardSetController c) {
    records = (Account[])c.getSelected();
    cancel = c.cancel();
    system.debug('22' + records + 'termName- ' + termName  );

}
public GenerateTerms() {
    this.accIds = accIds;
    this.termName = termName;
    system.debug('inside constructor-' + accIds + termName);

}


public Database.QueryLocator start(Database.BatchableContext BC) {
    system.debug('inside querylocator'+ records );
    return Database.getQueryLocator([SELECT school_name__c, student_name__c, id, dpsid__c,Mid_Year_Transfer_Status__c,application_status__c,mid_year_transfer_school__c FROM Application__c WHERE isCurrentApplication__c = true AND (School_Name__c IN :records OR mid_year_transfer_school__c IN :records)]);
}


public void execute(Database.BatchableContext BC, List<Application__c> appList) {
    list<Student_Term__c> stList = new list<Student_Term__c>();
    map<Id, Student_Term__c> stMap = new map<Id, Student_Term__c>();
    for (Student_Term__c st : [SELECT
                               Id,
                               Application__c,
                               Applied_for_ASSET__c,
                               Student_ID_at_College__c,
                               Daniels_Scholar__c,
                               Qualifies_for_Cook_Scholarship__c,
                               application__r.student_name__c,
                               application__r.school_name__c,
                               Program_Enrolled__c,
                               Financial_Aid_Deadline__c,
                               FA_File_Completion_Deadline__c,
                               Financial_Aid_Status__c,
                               Final_EFC_Upon_FA_File_Completion__c,
                               Projected_College_Graduation_Term__c,
                               Projected_College_Graduation_Year__c,
                               Has_Student_Completed_4_Year_Degree__c,
                               Qual_for_Daniels_Scholarship_by_College__c,
                               SSR_Completed_Previous_Term__c,
                               SSR_Comments_Previous_Term__c,
                               At_risk_of_stopping_out_Previous_Term__c,
                               At_Risk_Comments_Previous_Term__c,
                               SSR_Requirements_Completed__c,
                               SSR_Comments__c,
                               At_Risk_of_Stopping_Out__c,
                               At_Risk_Comments__c,
                               Term_Eligibility_Status__c,
                               Term_End_Date__c,
                               Rec_d_Pymt_Previous_Term__c,
                               Total_Payment_Value_Current_Term__c
                               FROM Student_Term__c
                               WHERE application__c IN :appList
                              ]) {
                                  Student_Term__c currentST = stMap.get(st.Application__c);
                                  if(currentST == null) {
                                      stMap.put(st.application__c, st);
                                  } else if(currentST != null && st.Term_End_Date__c != null && currentST.Term_End_Date__c != null && currentST.Term_End_Date__c < st.Term_End_Date__c) {
                                      stMap.put(st.application__c, st);
                                  }
                              }
    system.debug('Here');
    for (Application__c app : appList) {
        if(app.application_status__c == 'Finalist' && (app.mid_year_transfer_school__c == null || (app.mid_year_transfer_school__c != null && app.Mid_Year_Transfer_Status__c == 'Approved'))) {
            Student_Term__c previousStudentTermForContact = stMap.get(app.Id);
            Student_Term__c st = new Student_Term__c();
            st.Application__c = app.Id;
            //set inital student recieved pmt previous term as 'No'
            st.Rec_d_Pymt_Previous_Term__c = 'No';  
            if (app.mid_year_transfer_school__c != null && app.Mid_Year_Transfer_Status__c == 'Approved') {
                st.College_or_University__c = app.mid_year_transfer_school__c;
            } else {
                if (previousStudentTermForContact != null && previousStudentTermForContact.Term_Eligibility_Status__c == 'Finalist') {
                    //Should only be copied if not a mid year transfer
                    st.Student_ID_at_College__c = previousStudentTermForContact.application__r.school_name__c == app.school_name__c ? previousStudentTermForContact.Student_ID_at_College__c : null;
                    st.Term_Eligibility_Status__c = 'Finalist';
                    st.Program_Enrolled__c = previousStudentTermForContact.Program_Enrolled__c;
                    st.Financial_Aid_Deadline__c = previousStudentTermForContact.Financial_Aid_Deadline__c;
                    st.FA_File_Completion_Deadline__c = previousStudentTermForContact.FA_File_Completion_Deadline__c;
                    st.Financial_Aid_Status__c = previousStudentTermForContact.Financial_Aid_Status__c;
                    st.Final_EFC_Upon_FA_File_Completion__c = previousStudentTermForContact.Final_EFC_Upon_FA_File_Completion__c;
                    st.Applied_for_ASSET__c = previousStudentTermForContact.Applied_for_ASSET__c;
                    st.Projected_College_Graduation_Term__c = previousStudentTermForContact.Projected_College_Graduation_Term__c;
                    st.Projected_College_Graduation_Year__c = previousStudentTermForContact.Projected_College_Graduation_Year__c;
                    st.Has_Student_Completed_4_Year_Degree__c = previousStudentTermForContact.Has_Student_Completed_4_Year_Degree__c;
                    st.Daniels_Scholar__c = previousStudentTermForContact.Daniels_Scholar__c;
                    st.Qualifies_for_Cook_Scholarship__c = previousStudentTermForContact.Qualifies_for_Cook_Scholarship__c;
                    st.Qual_for_Daniels_Scholarship_by_College__c = previousStudentTermForContact.Qual_for_Daniels_Scholarship_by_College__c;
                    st.SSR_Completed_Previous_Term__c = previousStudentTermForContact.SSR_Requirements_Completed__c;    
                    st.SSR_Comments_Previous_Term__c = previousStudentTermForContact.SSR_Comments__c;
                    st.At_risk_of_stopping_out_Previous_Term__c = previousStudentTermForContact.At_Risk_of_Stopping_Out__c; 
                    st.At_Risk_Comments_Previous_Term__c = previousStudentTermForContact.At_Risk_Comments__c;
                    //sv - Update recieved payment previous term to yes if the student has recieved a payment previous term 
                    st.Rec_d_Pymt_Previous_Term__c = (previousStudentTermForContact.Total_Payment_Value_Current_Term__c > 0) ? 'Yes' : 'No'  ;
                }
                st.College_or_University__c = app.School_Name__c;

            }
            st.Term_Semester__c = termName;
            st.DPSID__c = app.DPSID__c;
            if(previousStudentTermForContact == null || (previousStudentTermForContact != null && previousStudentTermForContact.Term_Eligibility_Status__c == 'Finalist')) {
                stList.add(st);
            }
        }
    }
    insert stList;
}


public void finish(Database.BatchableContext BC) {


}

//Page Reference method to delete the selected records and then go back to the previous page.
public pageReference generateStudentTermsForUniversities(){
    GenerateTerms batchJob = new GenerateTerms();
    system.debug('inside generatestudenttermsuniversities');
    Database.executeBatch(batchJob, 500);
    return cancel.setRedirect(true);
}

}

5
  • 2
    Hi Shruthi, welcome to SFSE. Please edit your question to include your code as a code block (the {} button in the editor). Screen shots make it difficult for many community members, including those on mobile and using screen readers. – David Reed May 14 '19 at 22:09
  • 1
    Also, can't be copy-pasted, so would require a lot more effort for anyone to type an answer. – sfdcfox May 14 '19 at 22:23
  • Thank you for responding ...Sorry about that., pretty new to SFSE. Have pasted the code. – Shruthi Vasudeva May 14 '19 at 22:37
  • also - strip out unnecessary sections of code that are unrelated to the root of your issue; use edit – cropredy May 14 '19 at 22:47
  • In addition to the usability concerns above, code can be searched, while images cannot. – Adrian Larson May 14 '19 at 22:57
2

I'd strongly recommend that you not conjoin your Visualforce controller extension and batch job in this way. One of the reasons why is that it may confuse you about where exactly your state is preserved, as it does here:

public pageReference generateStudentTermsForUniversities(){
    GenerateTerms batchJob = new GenerateTerms();
    system.debug('inside generatestudenttermsuniversities');
    Database.executeBatch(batchJob, 500);
    return cancel.setRedirect(true);
}

The instance batchJob has no access to the instance variables of the (Visualforce controller) instance that is creating it. In your no-argument constructor,

public GenerateTerms() {
    this.accIds = accIds;
    this.termName = termName;
    system.debug('inside constructor-' + accIds + termName);
}

the assignments you perform are entirely within the new instance. Since all of the instance variables are initialized to null, these assignment statements do nothing at all - they just assign null to null variables. It's also not initializing records at all.

Break the batch class out separately, and define a constructor that takes all of the required parameters to store its state. Then you can move forward on testing the logic.

1
  • Thanks for the guidance David. I was able to figure it out based on what you said.I changed the Constructor to accept arguments public GenerateTerms(Set<Id>accIds, String termName) { this.accIds = accIds; this.termName = termName; } I changed the bacth job to send in parameters GenerateTerms batchJob = new GenerateTerms(accIds, termName); Appreciate your help!\ – Shruthi Vasudeva May 16 '19 at 16:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.