1

Here I have to replace 6 keywords from the response. I have created a metadata with word and replaced word.

public static String replaceJSONKeywordsModified(String strJsonResponse) {

    String strJson = '';

    //strRegexFormat is a regular expression used to replace only the keys in JSON string
    String strRegexFormat = '(?i)(?m)^\\s*"{0}"\\s*:';
    String strReplacementFormat = '"{0}" :';
    String strRegex;
    String strReplacement;
    String strFormattedJSON;
    List<Reserve_Keyword_ACE__mdt> lstReserveKeywords = new List<Reserve_Keyword_ACE__mdt>();
    try {
        if (String.isNotEmpty(strJsonResponse)) {
            lstReserveKeywords = [SELECT MasterLabel,DeveloperName FROM Reserve_Keywords__mdt WHERE Active_ACE__c = true];
            strFormattedJSON = JSON.serializePretty(JSON.deserializeUntyped(strJsonResponse));
            for (Integer intCount = 0; intCount < lstReserveKeywords.size(); intCount++) {
                strRegex = String.format(
                        strRegexFormat,
                        new List<String>{
                                lstReserveKeywords[intCount].MasterLabel
                        }
                );
                strReplacement = String.format(
                        strReplacementFormat,
                        new List<String>{
                                lstReserveKeywords[intCount].DeveloperName
                        }
                );
                strFormattedJSON = strFormattedJSON.replaceAll(strRegex, strReplacement);
            }
            strJson = strFormattedJSON;
        } else {
            strJson = strJsonResponse;
        }
    } catch (JSONException objException) {
        strJson = strJsonResponse;
    }
    return strJson;
}

Above is the logic which replaces all the reserved keywords by iterating over the reserved keywords.

The issue here is this logic breaks if the response is big. regex too complicated If I can split the response in 4 equal parts, based on the response length, and then pass each part through this method then it can resolve the issue.

Or is there any other way I can achieve this without hitting Apex CPU time limit?

Also how can I split the response in different parts?

4

It seems like you're trying really hard to avoid untyped deserialization just because it's comfortable and easy to work with or because it feels "prettier".

The best solution then would be to create constructors for your classes that you want to serialize the information into. The constructors should accept a Map<String, Object> and look through the map for the properties you want.

private class JSONResponse {
    public List<String> prop1 {get; set;}
    public List<JSONChildObject> prop2 {get; set;}

    public JSONResponse(Map<String, Object> JSONResponseObject) {
        this.prop1 = (List<String>) JSONResponseObject.get('systemReservedWord');
        this.prop2 = new JSONChildObject(JSONResponseObject.get('childProp'));
    }
}

private class JSONChildObject {
    public Decimal prop3 {get; set;}

    public JSONChildObject(Map<String, Object> JSONChildObject) {
        this.prop3 = (Decimal) JSONChildObject.get('systemReservedWord2');
    }
}

This should be much more performant than what you're trying to do with fewer limitations.

Usage

JSONResponse response = new JSONResponse(JSON.deserializeUntyped(httpResponse));

for (String s : response.prop1) {
    system.debug(s);
}

system.debug(response.prop2.prop3);
  • Serializing the response is not an issue, i have classes created which deserializes the response body. The issue is that the response sometimes has reserved keywords which needs to be replaced before deserialization. – Nagendra Singh Aug 20 at 16:59
  • Re-read my answer, I clearly put some strings in there to show you how to handle reserved words. – gNerb Aug 20 at 20:02
  • But when you do JSONResponseObject.get('systemReservedWord') you expect the system reserved keywords to be present somewhere, I did not understand where. Secondly, I am not sure about this new JSONChildObject(JSONResponseObject.get('childProp')) , as JSONResponseObject.get('childProp') would return a List and there is no constructor for that in JSONChildObject, Also is JSONChildObject constucting the reserved keywords? – Nagendra Singh Aug 21 at 3:06
  • This is just a sample, Without your full json response I can't provide any real usable code; nor would I consider it. You will have to be able to adapt this to work for you. This is not a "do it for me" website. – gNerb Aug 21 at 14:59
0

This works perfectly fine, I have modified the logic where it appends '_x' to replace it with the metadata file.

Changed from :

for (String key : keys) {
        Object value = obj.get(key);
        objJSONGenerator.writeFieldName(key + '_x'); //<------- reserved word safety here

        if (value == null) {
            objJSONGenerator.writeNull();
        } else if (value instanceof Map<String,Object>) {
            traverseMap((Map<String,Object>)value);
        } else if (value instanceof List<Object>) {
            traverseList((List<Object>)value);
        } else {
            objJSONGenerator.writeObject(value);
        }
    }

to

for (String key : keys) {
        Object value = obj.get(key);
        if(mapReserveKeywordFromMetadata != null && mapReserveKeywordFromMetadata.get(key) != null){
            key = mapReserveKeywordFromMetadata.get(key); //<------- reserved word safety here
        }
        objJSONGenerator.writeFieldName(key);

        if (value == null) {
            objJSONGenerator.writeNull();
        } else if (value instanceof Map<String, Object>) {
            traverseMap((Map<String, Object>) value);
        } else if (value instanceof List<Object>) {
            traverseList((List<Object>) value);
        } else {
            objJSONGenerator.writeObject(value);
        }
    }

Here I am building the reserved keywords map like this :

List<Reserve_Keyword__mdt> lstReserveKeywordFromOrg = [SELECT MasterLabel,DeveloperName FROM Reserve_Keyword__mdt WHERE Active__c = true];
        for (Reserve_Keyword_ACE__mdt objReserveKeyword : lstReserveKeywordFromOrg){
            mapStaticReserveKeywords.put(objReserveKeyword.MasterLabel, objReserveKeyword.DeveloperName);
        }

https://salesforce.stackexchange.com/a/88245/45062

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.