One of the most complex challenges in API integrations is handling JSON responses containing **dynamic keys**. Dynamic keys are property keys that are not fixed names, but instead change depending on user IDs, timestamps, or product codes. In this article, we explain how to parse these unpredictable JSON payloads within the static constraints of Salesforce Apex.
The Problem with Static Class Mapping
Static deserialization methods (like JSON.deserialize()) require class variables to perfectly match the JSON keys. Consider this payload containing dynamic user IDs as keys:
{
"users": {
"usr_101": { "name": "Alice" },
"usr_102": { "name": "Bob" }
}
}
Because the keys "usr_101" and "usr_102" change dynamically, you cannot define them statically as class properties. Attempting to do so would result in compile errors or unmapped properties.
Solution 1: Map-Based Deserialization
The standard way to resolve dynamic key scenarios is to parse the payload as a generic key-value map. Instead of modeling the entire structure, map only the static portion, and cast the dynamic child nodes to a Map<String, Object>:
String payload = '{"users": {"usr_101": {"name": "Alice"}, "usr_102": {"name": "Bob"}}}';
// Parse statically to root level
Map<String, Object> root = (Map<String, Object>) JSON.deserializeUntyped(payload);
Map<String, Object> usersMap = (Map<String, Object>) root.get('users');
// Loop through dynamic keys
for (String userId : usersMap.keySet()) {
Map<String, Object> userData = (Map<String, Object>) usersMap.get(userId);
System.debug('User ID: ' + userId + ', Name: ' + userData.get('name'));
}
This allows your code to process any dynamic ID structure without requiring class adjustments.
Solution 2: Pre-Processing JSON via String Manipulation
If you prefer working with type-safe wrapper classes, you can pre-process the raw JSON string before deserializing it. By converting the dynamic key structure into a standard array format, you can deserialize it into list properties.
For example, you can write a utility method to replace dynamic keys with static array labels:
Original Dynamic Keys:
"users": {
"usr_101": { "name": "Alice" }
}
Converted Array Structure:
"users": [
{ "id": "usr_101", "name": "Alice" }
]
By using standard regular expressions or string replacement to reformat the payload, you can then deserialize it directly into a standard list wrapper, preserving all the compilation checking benefits of wrapper classes.
Best Practices for Dynamic JSON in Salesforce
- **Check for Nulls**: Dynamic payloads frequently contain missing properties. Always verify that a map key exists before calling methods on it to prevent
NullPointerExceptions. - **Avoid Massive Casts**: Deeply nested dynamic arrays can require multiple lines of type casting, which makes code unreadable. Break your casting steps down into smaller, well-commented statements.
- **Benchmark CPU Limits**: Running regex replacements or parsing massive nested maps consumes Salesforce CPU cycles. Run stress tests in sandboxes to ensure you remain safely below transaction limits.
Conclusion
While dynamic JSON keys complicate static Apex compilation, combining untyped parsing maps with type-safe wrapper models allows you to handle any payload structure gracefully. Selecting the right balance between maps and classes keeps your Salesforce integration robust and performant.