Question
How to Deserialize JSON into an Object in Apex When Property Names Are Reserved Words?
Is there a way to deserialize JSON into an Apex object using JSON.deserialize
if some property names in the JSON are reserved keywords in Apex? For example, I want to deserialize the following JSON:
{
"currency": "ABC"
}
Here’s my Apex class and code:
string jsonString = '{"currency" : "ABC"}';
public class JSONResult {
public string currency;
}
JSONResult res = (JSONResult) JSON.deserialize(jsonString, JSONResult.class);
system.debug(res);
However, this throws an error because currency
is a reserved keyword in Apex. How can I handle this scenario and successfully deserialize the JSON? Any help or workarounds would be appreciated!
Answer
In Apex, certain words are reserved and cannot be used as identifiers, such as variable or property names. This creates a challenge when trying to deserialize JSON that contains these reserved words as property names. For instance:
String jsonString = '{"currency" : "ABC"}';
public class JSONResult {
public String currency;
}
// Attempting to deserialize
JSONResult res = (JSONResult) JSON.deserialize(jsonString, JSONResult.class);
System.debug(res);
The above code results in an error because currency
is a reserved word in Apex. There are two common ways to address this issue, along with an advanced solution using a custom serializer/deserializer:
1. String Replacement in the JSON String
One straightforward solution is to replace the reserved word in the JSON string with a non-reserved substitute before deserialization. After processing, you can replace it back if necessary. For example:
String jsonString = '{"currency" : "ABC"}';
jsonString = jsonString.replace('"currency":', '"currency_x":');
public class JSONResult {
public String currency_x;
}
JSONResult res = (JSONResult) JSON.deserialize(jsonString, JSONResult.class);
System.debug(res.currency_x); // Outputs: ABC
In this code, the reserved keyword currency
is replaced with currency_x
in the JSON string, and the JSONResult
class defines a matching property. This allows successful deserialization, avoiding reserved word conflicts. The debug statement prints the deserialized value of the currency_x
property.
2. Manually Parsing JSON with JSONParser
Another approach is to use the JSONParser
class to manually parse the JSON string and map reserved words to acceptable identifiers. While this method is accurate and flexible, it requires more effort and can be tedious if the JSON structure changes frequently.
String jsonString = '{"currency" : "ABC"}';
JSONParser parser = JSON.createParser(jsonString);
String currencyValue;
while (parser.nextToken() != null) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME && parser.getText() == 'currency') {
parser.nextToken();
currencyValue = parser.getText();
}
}
System.debug(currencyValue); // Outputs: ABC
Here, the JSONParser
is used to process the JSON string token by token. When the parser encounters the currency
field, it retrieves the associated value. This avoids deserialization errors related to reserved words while maintaining full control over the parsing logic.
3. Using a Custom Serializer/Deserializer
For a more robust solution, you can implement a custom serialization and deserialization framework that maps reserved keywords to alternative names during processing. Here’s an example based on the implementation by Charlie Jonas:
Custom Abstract Class:
public abstract class JSONReservedSerializer {
private final Map<Type, Map<String, String>> typeMapKeys;
public JSONReservedSerializer(Map<Type, Map<String, String>> typeMapKeys) {
this.typeMapKeys = typeMapKeys;
}
public String serialize(Object obj, System.Type type) {
String retString = JSON.serialize(obj);
return transformForSerialization(retString, typeMapKeys.get(type));
}
public Object deserialize(String jsonString, System.Type type) {
jsonString = transformForDeserialization(jsonString, typeMapKeys.get(type));
return JSON.deserialize(jsonString, type);
}
private static String transformForSerialization(String s, Map<String, String> mapKeys) {
for (String key : mapKeys.keySet()) {
s = s.replaceAll('"' + key + '"(\\s*):', '"' + mapKeys.get(key) + '":');
}
return s;
}
private static String transformForDeserialization(String s, Map<String, String> mapKeys) {
Map<String, String> reversedMap = new Map<String, String>();
for (String key : mapKeys.keySet()) {
reversedMap.put(mapKeys.get(key), key);
}
return transformForSerialization(s, reversedMap);
}
}
In this abstract class, mappings between reserved keywords and alternative names are maintained in a map. The transformForSerialization
and transformForDeserialization
methods handle bidirectional replacements, ensuring reserved words are appropriately substituted during serialization and deserialization.
Implementation:
public class MySerializer extends JSONReservedSerializer {
private static final Map<String, String> MAPPINGS = new Map<String, String> {
'currency' => 'currency_alias'
};
public MySerializer() {
super(new Map<Type, Map<String, String>> {
JSONResult.class => MAPPINGS
});
}
public class JSONResult {
public String currency_alias;
}
}
String jsonString = '{"currency" : "ABC"}';
MySerializer serializer = new MySerializer();
MySerializer.JSONResult res = (MySerializer.JSONResult) serializer.deserialize(jsonString, MySerializer.JSONResult.class);
System.debug(res.currency_alias); // Outputs: ABC
This implementation defines a custom serializer and a mapping for reserved words. The JSONReservedSerializer
class substitutes currency
with currency_alias
during deserialization. The mapped property is then accessed without any errors, making it suitable for handling APIs or JSON with reserved keywords.
Summing Up
To handle reserved words in JSON deserialization in Apex, you have three main options:
- String Replacement: Replace reserved words in the JSON string with acceptable alternatives before deserialization. This is simple but risky if unintended replacements occur.
- Manual Parsing with
JSONParser
: Use Apex’sJSONParser
to manually extract and process data, ensuring full control over reserved word handling but requiring more effort for complex structures. - Custom Serializer/Deserializer: Implement a custom serialization framework to map reserved keywords to alternative identifiers. This robust solution works well for APIs with consistent structures but involves an initial setup effort.
Each approach has trade-offs, and the best choice depends on the complexity of your JSON and your use case.
Enroll for Career-Building Salesforce Training with Real-Time Projects
Our Salesforce training in India delivers an all-encompassing learning experience, crafted to help you gain mastery over the Salesforce platform and pave the way for a successful career. Whether you aspire to become a Salesforce Administrator, Developer, or work on AI integrations, our courses delve into every essential aspect of the platform. With an emphasis on practical application through real-world projects, our training ensures you build hands-on expertise and can address real business challenges effectively. Guided by experienced industry professionals, our program equips you with the knowledge and confidence to thrive in the Salesforce ecosystem.
In addition to comprehensive technical training, our Salesforce training in India provides exceptional career development support. This includes personalized mentorship and expert advice to help you prepare for certifications. From in-depth learning materials to real-time project work and targeted interview coaching, we ensure you’re fully prepared for the job market. Our ultimate goal is to not only strengthen your Salesforce proficiency but also to position you for success in your next role. By completing the program, you’ll acquire the skills, experience, and confidence needed to excel in Salesforce and advance your career.