4

The Apex Developer Guide discusses the deserialize(jsonString, apexType) method of the JSON Class here, with the given example:

Decimal n = (Decimal)JSON.deserialize('100.1', Decimal.class);
System.assertEquals(n, 100.1);

I just always took casting the returned object into an object of choice, as shown, for granted. But I'm writing code where doing so will hinder me from making it as dynamic and minimal as possible.

Taking a deeper look at the documentation, I now wonder if casting a deserialization is sometimes redundant (even in the given example).

It explains, "[The method] deserializes the specified JSON string into an Apex object of the specified type [which is the second parameter System.Type apexType]."

So, if what I'm deserializing the JSON into and what I'm casting the deserialization into are the same object/type, and the type is an object instantiated from a wrapper class, can't I skip the casting?

4

Apex, like Java and other Object-Oriented Languages before it, are strongly-typed languages. This means that the compiler can check if an object is compatible with an assignment or operation before the code runs. This reduces the odds of deploying code that has no chance of ever working correctly. For example, you can't write:

Integer i = 5;
String s = i;

Because the compiler knows that an Integer is not a String. We need to manually convert it (e.g. String.valueOf).

JSON.deserialize returns an Object, which is the parent class of all other classes. This allows JSON.deserialize to be able to technically deserialize any type of object (some objects are inherently not deserializable/serializable). However, the compiler can't know that the returned Object is actually a Decimal, or DateTime, etc.

The compiler doesn't make special exceptions for any methods, as this would be specific behavior and introduce complexities into the compiler. Instead, the developer must help the compiler by telling it what the return type actually is.

This is what casting does. It bypasses the compiler's inferred type checks, and tells it what we know what we're doing, and that object being cast is indeed a specific type.

There are still certain types of casts that are disallowed, since they would be nonsensical (e.g. you can't cast an Integer to a String), but if the the source data type and the cast type are related to each other, the cast is allowed.

Of course, if the wrong type is used, a runtime error can occur, but this casting mechanism is what allows developers to help the compiler determine if an assignment is allowed, by allowing the type of a variable to change into a new, related type.

As a super-simple version that demonstrates the problem, consider:

Decimal d1 = 5.0;
Object o1 = d1;
// Decimal d2 = o1; // Compile error, Object is not a Decimal
Decimal d2 = (Decimal)o1; // Okay!

In summary, we can't skip the cast because while all Decimal objects are Object, not all Object are Decimal, so we must specifically tell the compiler that we are certain the result is a Decimal.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.