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.
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);
}
}
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);
USER_DEBUG|[20]|DEBUG|Name: John DoeUSER_DEBUG|[21]|DEBUG|Age: 30USER_DEBUG|[22]|DEBUG|Email: john.doe@example.comUSER_DEBUG|[23]|DEBUG|Is Subscribed: trueUSER_DEBUG|[24]|DEBUG|Theme: lightUSER_DEBUG|[25]|DEBUG|Language: en
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.