0

On recieving a response from the external system, I used Json2Apex to create the apex class viz.,JSON2Apex. Here's my JSON response for System.debug('##Raw Response-->' + responseBody);

{
"result": {
    "upon_approval": "proceed",
    "location": "",
    "expected_start": "",
    "reopen_count": "0",
    "close_notes": "",
    "impact": "3",
    "urgency": "3",
    "correlation_id": "",
    "sys_tags": "",
    "sys_domain": {
        "link": "abc.com/api/now/table/sys_user_group/global",
        "value": "global"
    },
    "description": "",
    "group_list": "",
    "priority": "5",
    "delivery_plan": "",
    "sys_mod_count": "0",
    "work_notes_list": "",
    "follow_up": "",
    "closed_at": "",
    "sla_due": "",
    "delivery_task": "",
    "sys_updated_on": "2015-11-18 10:12:18",
    "parent": "",
    "work_end": "",
    "number": "123",
    "closed_by": "",
    "work_start": "",
    "calendar_stc": "",
    "business_duration": "",
    "category": "inquiry",
    "incident_state": "1",
    "activity_due": "",
    "correlation_display": "",
    "company": "",
    "active": "true",
    "due_date": "",
    "assignment_group": "",
    "caller_id": {
        "link": "abc.com/api/now/table/sys_user/xxx",
        "value": "xxx"
    },
    "knowledge": "false",
    "made_sla": "true",
    "comments_and_work_notes": "",
    "parent_incident": "",
    "state": "1",
    "user_input": "",
    "sys_created_on": "2015-11-18 10:12:18",
    "approval_set": "",
    "reassignment_count": "0",
    "rfc": "",
    "u_record_url": "",
    "child_incidents": "0",
    "opened_at": "2015-11-18 10:12:18",
    "short_description": "test",
    "order": "",
    "sys_updated_by": "admin",
    "resolved_by": "",
    "notify": "1",
    "upon_reject": "cancel",
    "approval_history": "",
    "problem_id": "",
    "work_notes": "",
    "calendar_duration": "",
    "close_code": "",
    "sys_id": "abc",
    "approval": "not requested",
    "caused_by": "",
    "severity": "3",
    "sys_created_by": "admin",
    "resolved_at": "",
    "assigned_to": "",
    "business_stc": "",
    "sys_domain_path": "/",
    "cmdb_ci": "",
    "opened_by": {
        "link": "abc.com/api/now/table/sys_user/abc",
        "value": "abc"
    },
    "subcategory": "",
    "sys_class_name": "incident",
    "watch_list": "",
    "time_worked": "",
    "contact_type": "phone",
    "escalation": "0",
    "comments": ""
  }
 }

and using the JSON2APEX tool resulted me in the following class..

public class JSON2Apex {
public static void consumeObject(JSONParser parser) {
    Integer depth = 0;
    do {
        JSONToken curr = parser.getCurrentToken();
        if (curr == JSONToken.START_OBJECT || 
            curr == JSONToken.START_ARRAY) {
            depth++;
        } else if (curr == JSONToken.END_OBJECT ||
            curr == JSONToken.END_ARRAY) {
            depth--;
        }
    } while (depth > 0 && parser.nextToken() != null);
}

public Result result {get;set;} 

public JSON2Apex(JSONParser parser) {
    while (parser.nextToken() != JSONToken.END_OBJECT) {
        if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
            String text = parser.getText();
            if (parser.nextToken() != JSONToken.VALUE_NULL) {
                if (text == 'result') {
                    result = new Result(parser);
                } else {
                    System.debug(LoggingLevel.WARN, 'Root consuming unrecognized property: '+text);
                    consumeObject(parser);
                }
            }
        }
    }
 }

 public class Sys_domain {
    public String link {get;set;} 
    public String value {get;set;} 

    public Sys_domain(JSONParser parser) {
        while (parser.nextToken() != JSONToken.END_OBJECT) {
            if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
                String text = parser.getText();
                if (parser.nextToken() != JSONToken.VALUE_NULL) {
                    if (text == 'link') {
                        link = parser.getText();
                    } else if (text == 'value') {
                        value = parser.getText();
                    } else {
                        System.debug(LoggingLevel.WARN, 'Unrecognized property: '+text);
                        consumeObject(parser);
                    }
                }
            }
        }
    }
}

public class Result {
    public String upon_approval {get;set;} 
    public String location {get;set;} 
    public String expected_start {get;set;} 
    public String reopen_count {get;set;} 
    public String close_notes {get;set;} 
    public Sys_domain caller_id {get;set;} 
    public String short_description {get;set;} 
    public String priority {get;set;} 
    //....excluded for brevity

    public Result(JSONParser parser) {
        while (parser.nextToken() != JSONToken.END_OBJECT) {
            if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
                String text = parser.getText();
                if (parser.nextToken() != JSONToken.VALUE_NULL) {
                    if (text == 'upon_approval') {
                        upon_approval = parser.getText();
                    } else if (text == 'location') {
                        location = parser.getText();
                    } else if (text == 'expected_start') {
                        expected_start = parser.getText();
                    } else if (text == 'reopen_count') {
                        reopen_count = parser.getText();
                    } else if (text == 'close_notes') {
                        close_notes = parser.getText();
                    } else if (text == 'impact') {
                        impact = parser.getText();
                    }//....excluded for brevity
                    } else {
                        System.debug(LoggingLevel.WARN, 'Unrecognized property: '+text);
                        consumeObject(parser);
                    }
                }
            }
        }
    }
}


public static JSON2Apex parse(String json) {
    return new JSON2Apex(System.JSON.createParser(json));
}

}

I used the class in the following manner:

When I call this in apex class, I get all as null values.

 JSON2Apex.result myJson = (JSON2Apex.Result)JSON.deserialize(responseBody, 
 JSON2Apex.result.class);
 System.debug('##myJson-->'+myJson);

Is the class wrongly generated? Kindly let me know what might be the issue. Thanks in advance.

  • 2
    you should use the generated parse method – superfell Nov 18 '15 at 15:32
2

Since the Json2Apex parser generate a parse method that means that you have reserved keywords in your JSON.

For example:

{
   "result" : {

        "number" : 123

    }
}

If you have a lot of reserved keywords then simply use the parser provided in the class given to you.

If you only have one reserved keyword then you can generate Json2Apex replacing all reserved keywords with say "number_X" and you will get the simple class.

Then when deserializing you would replace the reserved keywords with the replaced version:

(JSON2Apex.Result)JSON.deserialize(responseBody.replace('number','number_X'), 
 JSON2Apex.result.class);
  • JSON2Apex now has perhaps a cleaner solution to this problem and emits generated code with this comment "The supplied json has fields with names that are reserved words in apex and so can only be parsed with explicitly generated code, this option was auto selected for you.". – Keith C Nov 18 '15 at 18:05
  • @KeithC - Yea, which is why I told the OP to use the parser generated from that service. BUT I am curious as to the performance of that vs a simple deserialize if you only have one reserved keyword and simply replace it in the source string. So I gave that option as well – Eric Nov 18 '15 at 18:07
  • Sorry read the end of your answer not the beginning... – Keith C Nov 18 '15 at 18:08
  • I have found the performance of the native JSON serializer to be better so I would suggest using the method provided by @Eric to replace reserved keywords. This comes up often enough for me that I have created utility method public static String convertFromReservedKeys(String jsonString, Map<String, String> reservedKeyMap) that accept a map where the key is the reserved word and the value is the replacement: currency => currency_x. I think there is some real value in using native methods too in terms of code maintenance. – dsharrison Nov 18 '15 at 21:39

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.