Skip to main content

Demystifying JSON.deserializeUntyped in Apex Salesforce with Code Examples

๐Ÿ’ฌ In plain words: JSON.deserializeUntyped parses raw JSON strings into flexible generic Apex maps (Map<String, Object>) or lists (List<Object>)—eliminating the need to define predefined wrapper classes for dynamic third-party API payloads.

In Salesforce development, working with JSON information is a common challenge when integrating with external systems or handling data in a flexible and dynamic way. Salesforce provides a powerful method called JSON.deserializeUntyped that allows developers to parse JSON strings into a manageable format. In this blog post, we'll explore the ins and outs of JSON.deserializeUntyped in Apex, understand its usage, and provide practical code examples to demonstrate its capabilities.

1. What is JSON.deserializeUntyped?

JSON.deserializeUntyped is an Apex method that allows you to parse JSON payloads into untyped data structures (maps and lists of generic Objects). Unlike typed deserialization—where you map JSON properties directly to specific Apex wrapper classes—untyped deserialization does not require defining a custom class beforehand. Instead, it provides a flexible way to parse and work with dynamic JSON structures on the fly.

2. Why Use JSON.deserializeUntyped?

There are scenarios where JSON payloads change frequently, contain dynamic keys, or are completely unknown at compile time. Using JSON.deserializeUntyped is particularly useful in these cases because it enables you to extract key values from varying JSON responses without writing or constantly updating rigid Apex wrapper classes.

3. Syntax and Parameters

The basic syntax of JSON.deserializeUntyped is as follows:

Object result = JSON.deserializeUntyped(jsonString);

Parameter: jsonString — The JSON-formatted string you want to parse and deserialize.

4. Code Examples

a. Basic JSON Deserialization
String jsonString = '{"name": "John", "age": 30, "isStudent": false}';

// Cast the deserialized object to a Map
Map<String, Object> jsonData = (Map<String, Object>) JSON.deserializeUntyped(jsonString);

String name = (String) jsonData.get('name');
Integer age = (Integer) jsonData.get('age');
Boolean isStudent = (Boolean) jsonData.get('isStudent');
b. Handling Nested JSON Structures
String jsonString = '{"person": {"name": "Jane", "age": 25}}';

Map<String, Object> jsonData = (Map<String, Object>) JSON.deserializeUntyped(jsonString);

// Extract the nested object map
Map<String, Object> personData = (Map<String, Object>) jsonData.get('person');
String name = (String) personData.get('name');
Integer age = (Integer) personData.get('age');
c. Working with Arrays
String jsonString = '{"students": [{"name": "Alice", "age": 22}, {"name": "Bob", "age": 23}]}';

Map<String, Object> jsonData = (Map<String, Object>) JSON.deserializeUntyped(jsonString);

// Cast the array property to a List of Objects
List<Object> studentsData = (List<Object>) jsonData.get('students');

for (Object student : studentsData) {
    Map<String, Object> studentData = (Map<String, Object>) student;
    String name = (String) studentData.get('name');
    Integer age = (Integer) studentData.get('age');
}
d. Error Handling and Exception Scenarios
String jsonString = '{"name": "Invalid JSON}'; // Malformed JSON

try {
    Map<String, Object> jsonData = (Map<String, Object>) JSON.deserializeUntyped(jsonString);
} catch (JSONException e) {
    System.debug('Error parsing JSON: ' + e.getMessage());
}
๐Ÿ’ก Key Takeaways & Best Practices
  • Validate JSON inputs or catch JSONException to prevent unexpected runtime failures.
  • Perform explicit type casting ((String), (Integer), (Map<String, Object>)) when accessing untyped values.
  • Use JSON.deserializeUntyped for dynamic/unknown schemas; prefer typed JSON.deserialize with wrapper classes when API schemas are strict and well-defined.
⚠ TYPE CASTING TRAP: Numbers in untyped JSON deserialization are implicitly parsed as Integer or Decimal. Direct type casting to an incorrect primitive type without checking or validating key existence can trigger a runtime System.TypeException or NullPointerException.
๐Ÿง  Key Takeaway: Untyped JSON deserialization provides dynamic structure flexibility at runtime, eliminating the need for strict wrapper classes when processing dynamic REST payload responses.
๐Ÿงญ 360 Card — Typed vs. Untyped JSON Deserialization
  • Rule: Use JSON.deserializeUntyped when JSON key structures vary; use JSON.deserialize(jsonString, ApexClass.class) when schemas are fixed.
  • Gain: Eliminates static class dependencies, reduces Apex metadata clutter, and easily parses changing payload schemas.
  • Price: Requires explicit manual casting for every map key and list item in Apex logic.
  • Limits: Deeply nested structures require multi-level type casting, increasing verbose null-checking requirements.

6. Conclusion

In this post, we explored the versatile JSON.deserializeUntyped method in Salesforce Apex. By removing the dependency on pre-defined Apex wrapper classes, untyped deserialization keeps your code dynamic, clean, and flexible when handling unpredictable JSON responses from third-party APIs.