Why Does JSON Break SObject Equality with Decimals?
Question
Why Does JSON Roundtrip Deserialization Break SObject Equality for Decimals in Apex?
I’ve noticed an issue where SObject equality is broken after a JSON roundtrip when the SObject contains Decimal fields. Here’s an example:
Opportunity o1 = new Opportunity(Amount = 12.3);
Opportunity o2 = (Opportunity) JSON.deserialize(JSON.serialize(o1), Opportunity.class);
System.debug(o1 == o2); // Outputs: false
However, when the SObject does not contain Decimal fields, the equality remains intact:
Opportunity o3 = new Opportunity(Name = 'foo');
Opportunity o4 = (Opportunity) JSON.deserialize(JSON.serialize(o3), Opportunity.class);
System.debug(o3 == o4); // Outputs: true
My Questions:
- Why does the equality contract break specifically for Decimal fields during a JSON serialization/deserialization roundtrip?
- Is there a way to prevent this behavior or ensure that equality is maintained for SObjects with Decimal fields after deserialization?
Keywords: Apex, JSON, SObject, Decimal, Equality, Serialization, Deserialization
Answer
When working with SObjects in Salesforce, you may encounter a situation where serializing and deserializing an SObject containing Decimal
fields breaks the equality contract (==
). Consider the following example:
Opportunity o1 = new Opportunity(Amount = 12.3);
Opportunity o2 = (Opportunity) JSON.deserialize(JSON.serialize(o1), Opportunity.class);
System.debug(o1 == o2); // false
In this scenario, even though System.debug(o1.Amount)
and System.debug(o2.Amount)
output the same value (12.3
), the equality check o1 == o2
returns false
. However, for SObjects without Decimal
fields, equality is preserved during the roundtrip:
Opportunity o3 = new Opportunity(Name = 'foo');
Opportunity o4 = (Opportunity) JSON.deserialize(JSON.serialize(o3), Opportunity.class);
System.debug(o3 == o4); // true
This discrepancy arises because of how Decimal
fields are handled during JSON serialization and deserialization. The Decimal
field may lose certain metadata or precision, leading to inequality when the ==
operator compares the two SObjects.
To resolve this issue and restore equality, you can explicitly cast the Decimal
field back to its original data type after deserialization. For example:
Opportunity o1 = new Opportunity(Amount = 12.3);
Opportunity o2 = (Opportunity) JSON.deserialize(JSON.serialize(o1), Opportunity.class);
System.debug(o1.Amount); // 12.3
System.debug(o2.Amount); // 12.3
System.debug(o1 == o2); // false
o2.Amount = (Decimal) o2.Amount;
System.debug(o1 == o2); // true
By explicitly casting o2.Amount
to Decimal
, you ensure that the field’s data type is consistent and that the equality check will succeed.
Alternative Approach
If modifying the deserialized object directly is not feasible or desirable, you can implement a custom equality check that compares individual field values instead of relying on the ==
operator. For example:
public static Boolean areOpportunitiesEqual(Opportunity o1, Opportunity o2) {
return o1.Amount == o2.Amount && o1.Name == o2.Name;
}
Opportunity o1 = new Opportunity(Amount = 12.3, Name = 'Deal A');
Opportunity o2 = (Opportunity) JSON.deserialize(JSON.serialize(o1), Opportunity.class);
System.debug(areOpportunitiesEqual(o1, o2)); // true
This approach provides more control over how equality is determined and avoids relying on the default behavior of the ==
operator.
Summary
When an SObject with Decimal
fields undergoes JSON serialization and deserialization in Salesforce, the equality check (==
) fails, even though the field values appear identical. This happens because the process may subtly alter the Decimal
field’s internal representation.
To resolve this, you can:
Cast the Decimal
field back to its original type after deserialization:apexCopy code
o2.Amount = (Decimal) o2.Amount;
System.debug(o1 == o2); // true
Implement a custom equality method to compare individual field values directly:
public static Boolean areOpportunitiesEqual(Opportunity o1, Opportunity o2) {
return o1.Amount == o2.Amount && o1.Name == o2.Name;
}
Both approaches ensure that the equality check produces the expected results for SObjects.
Real-Time Project-Based Salesforce Course
Our Salesforce course delivers a comprehensive and immersive learning experience, providing you with the skills required to excel in the CRM industry. The program focuses on essential areas such as Salesforce Admin, Developer, and AI, combining detailed theoretical instruction with hands-on practical experience. Through live projects and assignments, you’ll develop the expertise to tackle complex business challenges with Salesforce solutions. Our seasoned instructors are dedicated to helping you gain both technical proficiency and valuable industry insights.
Beyond technical skills, our Salesforce training in Dallas offers personalized mentorship, guidance for certification exam preparation, and interview readiness to give you a competitive edge in the job market. You’ll have access to extensive study materials, real-world project exposure, and continuous support throughout your learning journey. By the end of the course, you’ll be fully prepared for certification exams and equipped with the practical skills and problem-solving abilities employers seek. Begin your Salesforce career with us and open doors to exciting career opportunities!