Skip to main content

Demystifying Salesforce's json.deserializeUntyped Method - Full Code with Output

In Salesforce integrations, parsing dynamic JSON payloads without hardcoding custom wrapper classes is a common requirement. Apex provides the JSON.deserializeUntyped method, which deserializes raw JSON data into primitive collections like maps and lists.

In plain words: JSON.deserializeUntyped converts JSON strings into a Map<String, Object> (for JSON objects) or List<Object> (for JSON arrays) without requiring a typed Apex wrapper class.

What is JSON.deserializeUntyped?

The JSON.deserializeUntyped method takes a JSON string and parses it into key-value collections. Because the method signature returns a generic Object, you must cast the result directly to Map<String, Object> before calling map methods like .get().

Example Scenario

Suppose you receive the following nested JSON response from an external API callout:

{
  "name": "John Doe",
  "age": 30,
  "email": "john.doe@example.com",
  "isSubscribed": true,
  "preferences": {
    "theme": "light",
    "language": "en"
  }
}

Step-by-Step Implementation

Step 1: Create the Apex Utility Class

Cast the untyped result to a Map<String, Object> and perform type casting on retrieved property values:

public class JsonParsingExample {
    public static void parseJsonData(String jsonString) {
        // 1. Cast the untyped result directly to Map<String, Object>
        Map<String, Object> untypedMap = (Map<String, Object>) JSON.deserializeUntyped(jsonString);

        // 2. Extract primitive properties with type casting
        String name = (String) untypedMap.get('name');
        Integer age = (Integer) untypedMap.get('age');
        String email = (String) untypedMap.get('email');
        Boolean isSubscribed = (Boolean) untypedMap.get('isSubscribed');

        // 3. Extract nested JSON objects as secondary maps
        Map<String, Object> preferencesMap = (Map<String, Object>) untypedMap.get('preferences');
        String theme = (String) preferencesMap.get('theme');
        String language = (String) preferencesMap.get('language');

        // 4. Print results to debug logs
        System.debug('Name: ' + name);
        System.debug('Age: ' + age);
        System.debug('Email: ' + email);
        System.debug('Is Subscribed: ' + isSubscribed);
        System.debug('Theme: ' + theme);
        System.debug('Language: ' + language);
    }
}
Common Developer Mistake: Storing the output in a generic Object untypedObj variable and calling untypedObj.get('key') causes a compile error. You must cast the object to Map<String, Object> first.

Step 2: Execute via Anonymous Window or Service Apex

In Salesforce, run the method through Developer Console Anonymous Apex or another Apex execution context:

String jsonPayload = '{ "name": "John Doe", "age": 30, "email": "john.doe@example.com", "isSubscribed": true, "preferences": { "theme": "light", "language": "en" } }';
JsonParsingExample.parseJsonData(jsonPayload);
Expected Output: The execution log displays the parsed attributes:

USER_DEBUG|[20]|DEBUG|Name: John Doe
USER_DEBUG|[21]|DEBUG|Age: 30
USER_DEBUG|[22]|DEBUG|Email: john.doe@example.com
USER_DEBUG|[23]|DEBUG|Is Subscribed: true
USER_DEBUG|[24]|DEBUG|Theme: light
USER_DEBUG|[25]|DEBUG|Language: en
Use JSON.deserializeUntyped() when processing dynamic JSON schemas. When key structures are fixed, strongly-typed JSON.deserialize() with wrapper classes offers cleaner compile-time validation.

Conclusion

The JSON.deserializeUntyped method offers flexibility when parsing incoming API data in Salesforce. Casting top-level and nested attributes to maps allows you to extract properties quickly without writing extra wrapper boilerplate.