2

I have a JSON response coming from an HTTP callout that contains an array of columns and an array of array of records where those records have a value that needs to map to the column.

Example data from HTTP Callout:

{
    "columns": [
        "AID_YEAR",
        "LAST_NAME",
        "FIRST_NAME",
        "EMPLID",
        "DOCTYPE",
        "SOURCE",
        "DATE_INDEXED",
        "TIME_INDEXED",
        "DLN",
        "SALESFORCE_ID"
    ],
    "id": "{913ec09f-86f2-4ee3-be31-212349ccb9d6}",
    "updated": "2022-06-09T00:08:26.7610698Z",
    "entries": [
        {
            "indexvalues": [
                "2016",
                "SMITH",
                "JOHN",
                "12345",
                "PDF",
                "EFORM",
                "",
                "",
                "RANDOM_NAME",
                "500xxxx"
            ],
            "ID": 84,
            "PageCount": 1
        }
    ]
}

I want to deserialize this to a structure where the column name maps to the value.

Currently, I have the following deserialize based on a quick JSON2APEX:

AppxResponse data = (AppxResponse) System.JSON.deserialize(jsonResponse, AppxResponse.class);

public class AppxResponse {
   public List<String> columns;
   public List<ResponseEntries> entries;
}

public class ResponseEntries {
   public List<String> indexvalues;
   public Integer ID;
   public Integer PageCount;
}

What I am now trying to do is create a structure that looks like the following:

[{
    "DOCUMENT_LINK":"https://site.com/84",
    "PAGE_COUNT":"1",
    "ID":"84",
    "SALESFORCE_ID":"500xxxx",
    "DLN":"RANDOM_NAME",
    "TIME_INDEXED":"",
    "DATE_INDEXED":"",
    "SOURCE":"EFORM",
    "DOCTYPE":"PDF",
    "EMPLID":"12345",
    "FIRST_NAME":"JOHN",
    "LAST_NAME":"SMITH",
    "AID_YEAR":"2016"
}]

My attempt was to make a class for the structure of the entry that contains all of the column names I am working with. I called this Document.

public class Document {
    public String DOCUMENT_LINK;
    public String PAGE_COUNT;
    public String ID;
    public String SALESFORCE_ID;
    public String DLN;
    public String TIME_INDEXED;
    public String DATE_INDEXED;
    public String SOURCE;
    public String DOCTYPE;
    public String EMPLID;
    public String FIRST_NAME;
    public String LAST_NAME;
    public String AID_YEAR;
}

I came up with this attempt to try and map the indexvalues to the column based on the index location. The issue I am running into is trying to add the mappedData to the response, which I was hoping to get a List<Document>.

Attempt:

private static List<ApplicationXtenderService.Document> createMapForHttpResponse(String jsonResponse) {
    List<ApplicationXtenderService.Document> response = new List<ApplicationXtenderService.Document>();
    AppxResponse data = (AppxResponse) System.JSON.deserialize(jsonResponse, AppxResponse.class);
    List<String> cols = data.columns;

    // For each entry
    for (ApplicationXtenderService.ResponseEntries entry : data.entries) {
        Integer i = 0;

        // Map value to column
        Map<String, String> mappedData = new Map<String, String>();
        for (String iv : entry.indexvalues) {
            mappedData.put(cols[i], iv);
            i++;
        }
        // Add additional fields
        mappedData.put('ID', String.valueOf(entry.ID));
        mappedData.put('PAGE_COUNT', String.valueOf(entry.PageCount));
        mappedData.put('DOCUMENT_LINK', DOCUMENT_URL + '/' + entry.ID);

        response.add(mappedData);
    }

    return response;
}

I feel like I am seriously over complicating this and looking for some guidance. Currently running into the error of Method does not exist or incorrect signature: void add(Map<String,String>) from the type List<ApplicationXtenderService.Document>.

1 Answer 1

2

When the field names are separated from the values, there's not much we can do besides using a nested loop to step through each list in lock-step.

If this were an SObject, you could skip the step where you add data to your Map<String, String> because the SObject class provides the .put(String fieldName, Object fieldValue) method. However, since you're using a custom Apex class, that method isn't available to you (pun somewhat intended).

You could create your own .put() method, but it'd be an ugly if-else if or switch-when that you'd have to update any time the schema you're working with changes.

The only solution that I've found to this is round-trip deserialization. Serialize your mappedData at the end of your outer loop to get JSON, then deserialize that JSON as an instance of your Document class.

String intermediateJSON = JSON.serialize(mappedData);
response.add((ApplicationXtenderService.Document)JSON.deserialize(intermediateJSON, ApplicationXtenderService.Document.class));

All of your other code would remain as is

You must log in to answer this question.

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