💡 Mastering JSON in Salesforce Apex: The Complete Guide to System.JSON
In today’s API-first world, working with JSON is no longer optional — it’s essential. Whether you’re integrating Salesforce with external platforms, transforming data in LWC, or powering dynamic UIs, Salesforce’s System.JSON class is your go-to toolbox.
In this guide, we’ll walk through all the key methods of the System.JSON class in Apex — complete with examples and best practices.
🚀 What Is System.JSON?
The System.JSON class provides static methods for:
- Serializing Apex objects into JSON
- Deserializing JSON strings into Apex objects
- Generating or parsing JSON programmatically
🔍 Why Should You Care?
System.JSON is vital for:
- REST API integrations
- Transforming Apex/LWC data
- AI agents and dynamic interfaces
- Storing or handling loosely-typed or external data
📘 Core Methods with Examples
- createGenerator(prettyPrint)
Build JSON manually using code.
apex
public static String buildDynamicJson() {
JSONGenerator gen = JSON.createGenerator(true); // Pretty print
gen.writeStartObject();
gen.writeStringField(‘accountName’, ‘ACME Corp’);
gen.writeNumberField(’employees’, 120);
gen.writeBooleanField(‘active’, true);
gen.writeEndObject();
return gen.getAsString();
}
✔ Best Use: Custom API payloads with conditional fields
⚠ Use true to make debugging easier.
- createParser(jsonString)
Parse JSON token-by-token.
apex
public static void parseWithControl(String jsonInput) {
JSONParser parser = JSON.createParser(jsonInput);
while (parser.nextToken() != null) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME && parser.getText() == ‘status’) {
parser.nextToken(); // Move to value
System.debug(‘Status: ‘ + parser.getText());
}
}
}
✔ Best Use: Large/nested JSON, fine-grained control
⚠ Avoid unless needed. Use deserialize() when possible.
- deserialize(jsonString, apexType)
Convert JSON into a known Apex class.
apex
public class Order {
public String id;
public Decimal total;
}
public static Order parseOrder(String jsonInput) {
return (Order) JSON.deserialize(jsonInput, Order.class);
}
✔ Best Use: Standard integrations with structured payloads
💡 Extra JSON fields are ignored safely.
- deserializeStrict(jsonString, apexType)
Same as deserialize() but fails on extra fields.
apex
public class Invoice {
public String invoiceNumber;
public Decimal amount;
}
public static Invoice parseInvoiceStrict(String jsonInput) {
return (Invoice) JSON.deserializeStrict(jsonInput, Invoice.class);
}
✔ Best Use: Enforcing strict data contracts
⚠ Use for critical systems or validation layers
- deserializeUntyped(jsonString)
Convert JSON into a Map<String, Object> or List<Object>
apex
String jsonInput = ‘{“name”:”Widget”,”stock”:25,”active”:true}’;
Map<String, Object> product = (Map<String, Object>) JSON.deserializeUntyped(jsonInput);
System.debug(‘Stock: ‘ + product.get(‘stock’));
✔ Best Use: Unknown or dynamic JSON payloads
⚠ Handle data types carefully — always cast explicitly.
- serialize(objectToSerialize)
Convert Apex objects into compact JSON strings.
apex
public class Customer {
public String name;
public String email;
}
public static String toJson() {
Customer c = new Customer();
c.name = ‘Ada Lovelace’;
c.email = ‘ada@tech.io’;
return JSON.serialize(c);
}
✔ Best Use: Outbound API calls or object logging
💡 Use DTOs instead of raw SObjects.
- serialize(objectToSerialize, suppressApexObjectNulls)
Same as serialize(), but removes null values.
apex
public class ContactWrapper {
public String firstName;
public String lastName;
public String nickname; // might be null
}
public static String toCleanJson() {
ContactWrapper cw = new ContactWrapper();
cw.firstName = ‘Grace’;
cw.lastName = ‘Hopper’;
return JSON.serialize(cw, true); // nickname will be removed
}
✔ Best Use: Clean, efficient API payloads
💡 Helps reduce payload size
- serializePretty(objectToSerialize)
Generate indented JSON for humans.
apex
public class DebugHelper {
public static void logObject(Object obj) {
System.debug(JSON.serializePretty(obj));
}
}
✔ Best Use: Debugging and developer logs
⚠ Don’t use in production APIs — adds unnecessary size
- serializePretty(objectToSerialize, suppressApexObjectNulls)
Readable and clean JSON — great for documentation.
apex
public static String prettyAndClean() {
Map info = new Map{
‘name’ => ‘Alan Turing’,
‘role’ => null
};
return JSON.serializePretty(info, true); // role omitted
}
✔ Best Use: API mocking, test logs
💡 Ideal for dev environments, not production
🧠 Summary Table: What to Use When?
Method | Use Case |
serialize() | Quick conversion to JSON |
serializePretty() | Developer-friendly readable logs |
serialize(…, true) | Compact payloads without nulls |
deserialize() | Flexible parsing with extra field support |
deserializeStrict() | Enforced contract with strict structure |
deserializeUntyped() | Dynamic/unknown JSON payloads |
createGenerator() | Manual construction of complex JSON |
createParser() | Large streams, low-level control |
📚 Recommended Reading
🧵 Final Thoughts
- ✅ Use deserializeStrict() when data accuracy is non-negotiable.
- ✅ Prefer DTOs over raw SObjects for serialization.
- ⚠ deserializeUntyped() gives flexibility — but handle with care.
- 🎯 Pretty JSON = for devs. Compact JSON = for machines.