1

I insert object X, do a web call out, and then take the data I get back from the call out to update object X.

I found that you can't do DML before a webcallout so I broke this up into two methods and use action function to call the webservice method on the completion of the first method.

Where I am now stuck is on the update of the object's fields. I believe there to be another rule about DML after web call outs that I am unaware of. As you can see in the below code I update the object with the values I got back from the web service. But I am getting back System.NullPointerException: Attempt to de-reference a null object as soon as I try and save a value into the object's field. I know the values are not NULL. It is getting stuck on: crs.Bankcard_Score__c = IDScore1 and all the following field updates.

I have tried placing the update in the same method as well as a separated out method with a third action function. Is there a good workaround to this or something that I am missing with updates and web services?

VFP:

<apex:actionFunction name="crsUpdate_APEX" action="{!pullIDAnalyticsReportAPEX}" status="spinnerStatus1" oncomplete="CallWebService_APEX();"/>
<apex:actionFunction name="CallWebService_APEX" action="{!CallWebService}" status="spinnerStatus1" rerender="IDoldPullreportbutton1, refreshOutPutPannel1"/>
    ....
    <apex:commandLink value="Pull Report" onclick="crsUpdate_APEX(); removeButtonAndText(); return false;" style="text-decoration: none; text-align: center; position:relative; color: #333;"/>
    ....

APEX:

public PageReference pullIDAnalyticsReportAPEX() {
    currentPgId = ApexPages.currentPage().getParameters().get('id');
    guarantorId1 = [SELECT PG1__c FROM Credit_Review__c WHERE Id = :currentPgId].PG1__c;
    crs = new Consumer_Risk_Summary__c(Position__c = '1');//creating a new object
    insert crs;
    crsid = crs.Id;
    return null;
}

public PageReference CallWebService(){
    if(getAccounts() != NULL) {
        getAccounts(); //WEBSERVICE CALL OUT
        errorMessage();
        saveDateToString();
        crs.Bankcard_Score__c = IDScore1; //THIS IS WHERE IT ERRORS OUT, UNABLE TO UPDATE CRS VALUES
        crs.Comply360_Grade__c = Comply360Grade1;
        crs.Credit_Review__c = thecurrentPageId;
        crs.Transaction_Date__c = newdate;
        crs.Guarantor__c = guarantorId1;
        crs.Error_Message__c = ErrorMessage1;
        crs.Error__c = ApiErrorCode;

        List<Credit_Review__c> creditreview = [SELECT PG1__c, PG1_Cons_Risk_Summary__c FROM Credit_Review__c WHERE Id = :currentPgId];
        for (Credit_Review__c credRev : creditreview) {
            credRev.PG1_Cons_Risk_Summary__c = crs.Id;
            system.debug('got into the current credit review loop');
            update credRev;
        }
        if (crs.Error__c == 'null' || (crs.Bankcard_Score__c != 'null' && crs.Bankcard_Score__c != NULL)) {
            crs.Status__c = 'Completed';
        }
        update crs;
    }
    else {
        genericError = 'There has been an error in your organization. Please contact your system administrator for assistance.';
    }
    return null;
}

public string getAccounts() {
    Integer i = 0;
    system.debug('got into getAccounts: ' + (i = i + 1));
    HttpRequest req = new HttpRequest();
    endpoint = IDAnalyticsEndPoint__c.getInstance();
    url1 = endpoint.IDAnalyticsEndpointUrl__c;
    req.setEndpoint(url1);
    Http h = new Http();
    req.setMethod('POST');
    req.setBody(generateJSON());
    req.setHeader('Content-Type', 'application/json');
    system.debug('this is the setHeader');
    req.setTimeout(120000);
    system.debug('this is the setTimeout');
    string d = getAuth();
    string e = 'token ';
    string f = e + d;
    system.debug('this is the f: ' + f);
    req.setheader('Authorization', f);
    try {
        res = h.send(req);
        jsonStr = res.getBody();
        errorMessage();
        JSONParser parser = JSON.createParser(res.getBody());
        while (parser.nextToken() != null) {
            if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'IDScore')) {
                parser.nextToken();
                IDScore1 = parser.getText();
            }
            if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'Comply360Grade')) {
                parser.nextToken();
                Comply360Grade1 = parser.getText();
            }
            if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'ApiErrorCode')) {
                parser.nextToken();
                ApiErrorCode = parser.getText();
            }
            if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'ErrorMessage')) {
                parser.nextToken();
                ErrorMessage1 = parser.getText();
            }
        }
        return jsonStr;
    }
    catch (System.CalloutException z) {
        errorMessage();
        return null;
    }
}

I found most of my data from here: WebService and DML

  • @SantanuBoral You Cannot do DML prior to a callout in the same transaction regardless of it it originated from a VF page or not – Eric May 3 '17 at 23:59
  • @Olivia - You Can do DML after a callout so you can drop that for your troubleshooting process. Liberal use of debugs and the debug log is your friend here – Eric May 4 '17 at 0:00
  • Yes, if you see help.salesforce.com/articleView?id=000003701&type=1 there is a breakdown of how to do a DML call before your call out. What I have found over the past hour is that I can not do a post-DML update because of static vs non-static variables. I am getting a NULL value when I try and update because crs is a static variable. When I remove static modifier, I am able to update the crs object. This is great but does not entirely help because I need that variable to be static to persist the data on the VFP. So I am still stuck. – Olivia May 4 '17 at 0:13
  • @Eric I see...what I did wrong was I created a new instance of crs (I called it crsNew) and initialized that variable. But instead I shoul dhave just initialized crs, With this I am able to get it to persist. – Olivia May 4 '17 at 0:33
2

Your issue is in the CallWebService method the crs has not been initialized and thus is null. I do not see where you are setting the value of crs anywhere.

Per you comment you have crs as a static variable

Static will not help you there as after you make the callout and return to the page it is a separate transaction and the value of crs is reset to its defined value. In this case Static has the opposite effect.

Removing static will allow it to persist because it will be in the viewstate

The linked article is doing it correctly but it is NOT in the same transaction which is the whole point of the article.

Your issue is not DML after callout it is static variable and transactional boundaries.

In your case a minimal example would be

public class myController {
    public Consumer_Risk_Summary__c crs {get;set;} //maintained by view state

    public PageReference pullIDAnalyticsReportAPEX() {
        currentPgId = ApexPages.currentPage().getParameters().get('id');
        guarantorId1 = [SELECT PG1__c FROM Credit_Review__c WHERE Id =: currentPgId].PG1__c;
        crs = new Consumer_Risk_Summary__c(Position__c = '1'); //creating a new object
        insert crs;
        crsid = crs.Id;
        return null;
    }

    public PageReference CallWebService() {
        if (getAccounts() != NULL) {
            .......
            crs.Bankcard_Score__c = IDScore1; //crs will have the Id and Position field populated from the previous method
            crs.Comply360_Grade__c = Comply360Grade1;
            crs.Credit_Review__c = thecurre

        }
    }
}

First method called is pullIDAnalyticsReportAPEX then action function calls CallWebService

Naming need redone once you get it fixed as it is a bit misleading at the moment

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.