Seems as though casting is not transitive in some cases. Consider trying to get an Integer from an SObject number field.

Integer myInt = (Integer) mySObject.get('My_Field__c');


System.TypeException: Invalid conversion from runtime type Decimal to Integer

Apparently you need to first cast it to a Decimal, so you can then Cast it to a Integer.

Integer myInt = (Integer)(Decimal) mySObject.get('My_Field__c');

This seems broken to me. Pretty sure casting should be transitive. In other words if. A=B & B=C then A=C.

Or maybe I'm missing something?


3 Answers 3


You can't hop more than one data type per cast; each additional conversion requires another cast.

For example, the following works:

Integer i = (Integer)5.2;

But you can't write:

Object o = 5.2;
Integer i = (Integer)o;

And you also can't write:

Integer i = (Integer)(Object)5.2;

Basically, casting a Decimal from an Object reference to an Integer reference is invalid, because it's not a compatible type.

I wouldn't call this a "bug" so much as a limitation of the runtime. It's not documented, so I'm going to ask about it elsewhere.

For now, though, you can safely use Integer.valueOf to get a valid conversion, even if the value is null.


The same behavior is observed in Java, so at least it's consistent.

Runtime Error (Java)

    Object a = 5.2f;
    int b = (int)a;

Valid Code (Java)

    float a = 5.2f;
    int b = (int)a;

It appears that this limitation stems from Java itself, and is not specific to Apex Code.

  • Integer.valueOf throws NumberFormatException if the value is null or empty string. So it is not a "safe" way to get a conversion. Feb 6, 2018 at 16:09
  • oh wow, I always through you could do this in Java. Great answer!
    – NSjonas
    Feb 6, 2018 at 16:32
  • Looks like it has to do with primitive unboxing stackoverflow.com/a/27459873/800619
    – NSjonas
    Feb 6, 2018 at 16:52
  • @JamesWatkins At least in v42.0, Integer.valueOf no longer throws an exception on null, and number fields will never return an empty string. It's perfectly safe to use if the source is a Number field.
    – sfdcfox
    Feb 6, 2018 at 17:26
  • @NSjonas It's been a while since I've tested more esoteric limits of Java, but I discovered that limitation yesterday, so that was nice. I need to get back in to Java, I haven't done much with it since Java 2 or so, lol.
    – sfdcfox
    Feb 6, 2018 at 17:29

In Salesforce My_Field__c we create field with Number actually stores the decimal type values even if we define decimal places as 0. It is never be an Integer until we transform the value explicitly from Decimal to Integer.

Decimal myDec = (Decimal) mySObject.get('My_Field__c');

So, then from this Decimal we can transform to Integer.

Also, refer Rules of Conversion

Numbers form a hierarchy of types. Variables of lower numeric types can always be assigned to higher types without explicit conversion. The following is the hierarchy for numbers, from lowest to highest:

  1. Integer
  2. Long
  3. Double
  4. Decimal

Once a value has been passed from a number of a lower type to a number of a higher type, the value is converted to the higher type of number.


It's not really a bug, because the returned value is not an instance of an Integer. Here's a snippet to demonstrate:

SObject record = [SELECT Integer__c FROM MyObject__c LIMIT 1];
Object value = record.get('Integer__c');
system.debug(value instanceOf Integer);
system.debug(value instanceOf Long);
system.debug(value instanceOf Double);
system.debug(value instanceOf Decimal);

The resulting log:


However, you don't need to use casting at all. Simply use Integer.valueOf:

SObject record = [SELECT Integer__c FROM MyObject__c LIMIT 1];
Integer value = Integer.valueOf(record.get('Integer__c'));
  • 1
    But Integer i = (Integer)5.2 works, even though 5.2 is a Decimal.
    – sfdcfox
    Feb 6, 2018 at 4:09

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .