2

I am facing a problem which I am not finding any answers. I am trying to call a third party API (which is working). But when I try to deserialize the json receive, nothing is happening. Here is my code. Can anyone see any problems here ?

The first callout method is for another api. THe problem comes from the 2nd one

That is my class calloutViewer controller

    public with sharing class RF_Controller {

    public String requestEndpoint {get;set;}
    public String accountodel {get;set;}
    public String createnewtask {get;set;}
    public String requestMethod {get;set;}
    public String requestBody {get;set;}
    public String responseStatus {get;set;}
    public Integer responseStatusCode {get;set;}
    public String responseBody {get;set;}
    public string toMail { get; set;}
    public string ccMail { get; set;}
    public string repMail { get; set;}
    public stackExchangeAPI.responseResource response {get;set;}
    public RF_Forum.responseResource2 response2 {get;set;}
    public List<stackExchangeAPI.questionResource> deserializedQuestions {get;set;}
    public List<RF_Forum.questionResource2> deserializedQuestions2 {get;set;}



    public List<SelectOption> getMethodOptions(){
        List<SelectOption> options = new List<SelectOption>();
        options.add(new SelectOption('GET','GET'));
        return options;
    }




    // RF callout2
    public void callout2(){
        httpResponse res2 = RFAPI.callout2(requestMethod, requestEndpoint, requestBody);
        responseStatus = res2.getStatus();
        responseStatusCode = res2.getStatusCode();
        responseBody = res2.getBody();
    }

public void deserializeQuestions2() {

    System.assert( string.isNotBlank(responseBody), 'missing responseBody test');

    if(string.isNotBlank(responseBody) ) {
        response2 = (RF_Forum.responseResource2)JSON.deserialize(responseBody,RF_Forum.responseResource2.class);
        deserializedQuestions2 = response2.items2;
    }   

}


       public class responseResource2 {
        public List<questionResource2> items2{get;set;}
    }

     public class questionResource2 {
         public Timestamps timestamps {get;set;}
         public Counts counts {get;set;}
         public Entity entity {get;set;}

    }


    public class Timestamps {
        public String firstSeen {get;set;} 
        public String lastSeen {get;set;}
    }

    public class Entity {
        public String id {get;set;} 
        public String name {get;set;} 
        public String type_Z {get;set;}
    }

    public class Counts {
        public Integer returned {get;set;} 
        public Integer total {get;set;} 
    }

}

That is my RFAPI class who does callout and try to deserialize

    public with sharing class RF_Forum {
    public static String BASE_URL = 'My api url';


    //Method to perform a callout and return an httpResponse
    public static httpResponse callout2(String httpMethod, String endpoint, String body){
        //Instantiate an httpRequest and set the required attributes
        String token = 'My api token';
        httpRequest req = new httpRequest();
        req.setHeader('X-RFToken', token);
        req.setMethod(httpMethod);
        req.setEndpoint(endpoint);
        req.setTimeout(120000);   
        httpResponse res2 = new http().send(req);

        system.debug(res2.toString());
        system.debug(res2.getBody());
        return res2;
        }

  public static responseResource2 deserialize(httpResponse res2){
        return (responseResource2)JSON.deserialize(res2.getBody(),responseResource2.class);

    }
/********************* RF JSon ***********************/ 
    public class responseResource2 {
        public List<questionResource2> items2{get;set;}
    }

     public class questionResource2 {
         public Timestamps timestamps {get;set;}
         public Counts counts {get;set;}
         public Entity entity {get;set;}

    }   
    public class Timestamps {
        public String firstSeen {get;set;} 
        public String lastSeen {get;set;}
    }
    public class Entity {
        public String id {get;set;} 
        public String name {get;set;} 
        public String type_Z {get;set;}
    }
    public class Counts {
        public Integer returned {get;set;} 
        public Integer total {get;set;} 
    }
}

That's my Apex to have a visual page

<apex:page id="page" controller="RF_Controller" >
<apex:form id="form" >
    <apex:sectionHeader title="AKTARUS" />
    <apex:pageMessages id="pageMessages" />
    <apex:pageBlock >
        <apex:pageBlockButtons >                
            <!-- RF API -->
          <apex:commandButton value="Callout 2" action="{!callout2}" rendered="{!$CurrentPage.parameters.offline!='1'}"/>
            <apex:commandButton value="Deserialize2" action="{!deserializeQuestions2}" rendered="{!$CurrentPage.parameters.offline!='1'}"/>

            <apex:commandButton value="Callout (offline)" action="{!callout2}" rendered="{!$CurrentPage.parameters.offline=='1'}" />
            <apex:commandButton value="Deserialize (offline)" action="{!deserializeQuestions2}" rendered="{!$CurrentPage.parameters.offline=='1'}" /> -

        </apex:pageBlockButtons>

        <apex:pageBlockSection columns="1" title="HttpRequest" collapsible="false" >
            <apex:pageBlockSectionItem >
                <apex:outputLabel value="setMethod()" />
                <apex:selectList size="1" value="{!requestMethod}" >
                     <apex:selectOptions value="{!MethodOptions}" />
                </apex:selectList> 
            </apex:pageBlockSectionItem>         
           <apex:pageBlockSectionItem >
                <apex:outputLabel value="setEndpoint()" />
                <apex:inputText value="{!requestEndpoint}" style="width:90%" />
            </apex:pageBlockSectionItem>  
        </apex:pageBlockSection> 
        <apex:pageBlockSection columns="1" title="HttpResponse" collapsible="false" >
            <apex:pageBlockSectionItem >
                <apex:outputLabel value="getStatusCode()" />
                <apex:outputText value="{!responseStatusCode}" />
            </apex:pageBlockSectionItem>
            <apex:pageBlockSectionItem >
                <apex:outputLabel value="getStatus()" />
                <apex:outputText value="{!responseStatus}" />
            </apex:pageBlockSectionItem>
            <apex:pageBlockSectionItem >
                <apex:outputLabel value="getBody()" />
                {!responseBody}
            </apex:pageBlockSectionItem>
        </apex:pageBlockSection>-

        <apex:pageBlockSection columns="1" title="JSON Deserializer" rendered="{!deserializedQuestions2 != null}" collapsible="false" >
            <apex:pageBlockTable value="{!deserializedQuestions2}" var="i" >
                <apex:column headerValue="Question Id" style="width:75px;" >
                    <apex:outputText value="{!i.timestamps.firstseen}" />
                </apex:column>
                <apex:column headerValue="Creation Date" style="width:75px;" >
                    <apex:outputText value="{!i.timestamps.lastseen}" />
                </apex:column>
                <apex:column headerValue="View Count" style="width:75px;" >
                    <apex:outputText value="{!i.entity.id}" />
                </apex:column>
                <apex:column headerValue="Answer Count" style="width:75px;" >
                    <apex:outputText value="{!i.entity.name}" />
                </apex:column>
                <apex:column headerValue="Score" style="width:50px;" >
                    <apex:outputText value="{!i.entity.type_Z}" />
                </apex:column>
                <apex:column headerValue="Score" style="width:50px;" >
                    <apex:outputText value="{!i.counts.returned}" />
                </apex:column>
                <apex:column headerValue="Score" style="width:50px;" >

                </apex:column>
            </apex:pageBlockTable>

    </apex:pageBlockSection> 
    </apex:pageBlock>
</apex:form>

My JSON looks like that:

{
  "data": {
    "results": [
      {
        "entity": {
          "id": "ip:186.1xx",
          "name": "186.183.1xxxx",
          "type": "IpAddress"
        },
        "timestamps": {
          "firstSeen": "2018-08-25T01:01:39.946Z",
          "lastSeen": "2019-06-25T20:48:30.833Z"
        }
      },
      {
        "entity": {
          "id": "ip:179.14.2xx",
          "name": "179.14.2.xx",
          "type": "IpAddress"
        },
        "timestamps": {
          "firstSeen": "2019-04-05T18:07:40.670Z",
          "lastSeen": "2019-06-25T21:29:25.148Z"
        }
      },
  • So people can help, add a formatted (jsonformatter.curiousconcept.com) copy of the JSON that you are trying to parse to your question. For example, it would be unusual to have the name "items2" is the JSON but that is what your code expects. – Keith C Jun 26 at 13:47
  • 1
    The code you've posted never actually calls either deserialization method. Is this code complete and compilable? There's some duplication too. – David Reed Jun 26 at 13:58
  • 2
    @Tiburce Please edit all of that detail into your question. Make sure your code inclusions are complete and compilable so the community can support your debugging effort. – David Reed Jun 26 at 14:03
  • @DavidReed I do apologize, its my first time using the forum . Thank you for the answers so fast tho ;) I just edited the first post – Tiburce Jun 26 at 14:08
2

... when I try to deserialize the json receive, nothing is happening.

The first callout method is for another api. THe problem comes from the 2nd one

From those two statements I assume the problem is occurring in deserializeQuestions2().

Looking at the body of that method the most likely reason that it would do nothing would be responseBody being null or empty.

It doesn't look like responseBody is flagged as transient, so it should persist in the pages viewstate between postbacks. However, I do see a couple of locations trying to set that value. You might find something in the page lifecycle is inadvertently clearing the value out.

I'd recommend a generous application of System.assert() statements to your code. They are a bit of a crude tool, but they will allow you to move through the code incrementally and ensure it is in the expected state. E.g.

public void deserializeQuestions2() {

    System.assert( string.isNotBlank(responseBody), 'missing responseBody');

    if(string.isNotBlank(responseBody) ) {
        response2 = (RFAPI.responseResource2)JSON.deserialize(responseBody,RFAPI.responseResource2.class);
        deserializedQuestions2 = response2.items2;
    }   
}

You could also use System.debug statements and the debug log, or the interactive Apex debugger. Whichever approach you use, work backwards through your code and test the assumptions being made about the state of the system.


More specifically, your problem is around how you deserialize the json. The Apex class structure needs to match that of the JSON payload. If it doesn't you are likely to just get null properties, which is happening in your case with the sample JSON you provided.

Here is an anonymous Apex example that will deserialize the sample JSON.

public class Timestamps {
    public String firstSeen {get;set;} 
    public String lastSeen {get;set;}
}

public class Entity {
    public String id {get;set;} 
    public String name {get;set;} 
    public String type_Z {get;set;}
}

public class Results {
    public Entity entity {get;set;} 
    public Timestamps timestamps {get;set;} 
}

public class Data {
    public List<Results> results {get;set;} 
}

public class responseResource2 {
    public Data data {get;set;}
}

string responseBody = '{"data":{"results":[{"entity":{"id":"ip:186.1xx","name":"186.183.1xxxx","type":"IpAddress"},"timestamps":{"firstSeen":"2018-08-25T01:01:39.946Z","lastSeen":"2019-06-25T20:48:30.833Z"}},{"entity":{"id":"ip:179.14.2xx","name":"179.14.2.xx","type":"IpAddress"},"timestamps":{"firstSeen":"2019-04-05T18:07:40.670Z","lastSeen":"2019-06-25T21:29:25.148Z"}}]}}';
if(string.isNotBlank(responseBody) ) {
    responseResource2 response2 = (responseResource2)JSON.deserialize(responseBody,responseResource2.class);
    System.debug(response2);
}

Outputs:

13:52:33:026 USER_DEBUG [28]|DEBUG|responseResource2:[data=Data:[results=(Results:[entity=Entity:[id=ip:186.1xx, name=186.183.1xxxx, type_Z=null], timestamps=Timestamps:[firstSeen=2018-08-25T01:01:39.946Z, lastSeen=2019-06-25T20:48:30.833Z]], Results:[entity=Entity:[id=ip:179.14.2xx, name=179.14.2.xx, type_Z=null], timestamps=Timestamps:[firstSeen=2019-04-05T18:07:40.670Z, lastSeen=2019-06-25T21:29:25.148Z]])]]

  • Hello @DanielBallinger, I edited the first post and added all my code inside. I tried all morning and night to fix it, and it's still not displaying in my apex blocks.. The responsebody is not empty as there is not error (I tried with an empty body and the error was displaying) I don't know what to do anymore... Do you have anymore tips for me , I would be delighted to fix that problem (3 days working on it now) The full code is working and compilable if anyone as the time to try. Thank you so much in advance – Tiburce Jun 27 at 8:31
  • Maybe it's just a display problem in the apex block section?. I am actually fairly stuck and might go crazy soon ;( – Tiburce Jun 27 at 9:09
  • 1
    Thank you Daniel you helped me so much =) everything is working now – Tiburce Jun 28 at 7:00

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.