How to get the Runtime-Type of an Object dynamically (for Primitive Data Types and SObjects)

  • Is it possible to get the Type of an Object (it's not an SObject)?

    String s = 'test';
    doSomething(s);
    
    public static void doSomething(o Object) {
        // need to find out if o is a string or an integer
        type = IsThereAMethodToGetTheTypeOf(o) // ?
        if(type='String') {
            // do something for strings here ....
        } else {
            // do something else ....
        }
    }
    

    I think the Type class can't help me, because it has no way to get the type of an existing object instance, right? Any there any other way?

    Since there is most likely no perfect solution possible within the current platform limitations, I posted an Idea on IdeaExchange here: https://success.salesforce.com/ideaView?id=08730000000l9wHAAQ

    For SObject I have already this

    public static string getType(SObject obj) {
        if(obj==null) return '';
        return obj.getSObjectType().getDescribe().getName()+'';
    }
    

    One silly (but actually usable) way I found is to use a couple of try/catches to iterate over possible types by typecast and assignment like `try { Integer testInt = (Integer) o; ... } catch(Exception e) { try { String testStr = (String) o; ... } }` - but can we do this better?

    I can't even find any sfdc doc about 'Object' class :(

    There is `instanceof` which is better than the casting approach though that also requires hard coding of the types. And it used to return true for null but I think that may now be fixed.

    @Uwe I'm curious why you need to know the Objects type? Run-time checking of an Object's type is usually an anti-pattern in most OO languages, see explanation.

    @ArpiJakab : For simple static stuff, I agree. But if you want to write Apps capable of working on different objects and fields dynamically, the anti-pattern is your only friend left.

    @Uwe Cool. I've posted an answer bellow that parses the type string of any primitive type, such as 'Map,Decimal>' from the error message of a type cast exception.

    @ArpiJakab linking to an opinion blog entry about Javascript doesn't bolster your argument. There are many scenarios in polymorphic languages where you want to know the type at runtime.

  • Uwe Heim

    Uwe Heim Correct answer

    7 years ago

    The closest I could figure out with the approaches that we have right now you see below. Note that as an unfortunate we still can't detect sets and maps and we can't distinguish between decimal and double. The rest feels usable.

    public class xs {
      public static string getType(Object o) {
        if(o==null) return '';              // we can't say much about null with our current techniques
        if(o instanceof SObject)            return ((SObject)o).getSObjectType().getDescribe().getName()+''; 
        if(o instanceof Boolean)            return 'Boolean';
        if(o instanceof Id)                 return 'Id';
        if(o instanceof String)             return 'String';
        if(o instanceof Blob)               return 'Blob';
        if(o instanceof Date)               return 'Date';
        if(o instanceof Datetime)           return 'Datetime';
        if(o instanceof Time)               return 'Time';
        if(o instanceof String)             return 'String';
        if(o instanceof Integer)            return 'Integer';
        if(o instanceof Long)               return 'Long';
        if(o instanceof Decimal)            return 'Decimal';  // we can't distinguish between decimal and double
        if(o instanceof Double)             return 'Double';   // we can't distinguish between decimal and double
        if(o instanceof List<object>)       return 'List';
        return 'Object';                    // actually we can't detect maps and sets and maps
      }
    }
    

    Actually I'm not that kind of big test-writer, but this could be rewritten and used as test. I run it as Execute Anonymous to verify the results:

    list<string>t00 = new list<string>{'test'};             system.debug('List<string> : '  + xs.getType(t00));
    Account     t01 = new Account();                        system.debug('Account : '       + xs.getType(t01));
    Boolean     t02 = true;                                 system.debug('Boolean : '       + xs.getType(t02));
    Boolean     t03 = false;                                system.debug('Boolean : '       + xs.getType(t03));
    String      t04 = 'sdfsdf';                             system.debug('String  : '       + xs.getType(t04));
    Id          t05 = [select id from user limit 1][0].Id;  system.debug('Id : '            + xs.getType(t05));
    Blob        t06 = Blob.valueOf('testsdf');              system.debug('Blob : '          + xs.getType(t06));
    Datetime    t07 = Datetime.now();                       system.debug('Datetime : '      + xs.getType(t07));
    Time        t08 = Time.newInstance(18, 30, 2, 20);      system.debug('Time : '          + xs.getType(t08));
    Date        t09 = (Date) Date.today();                  system.debug('Date : '          + xs.getType(t09));
    Integer     t10 = 7;                                    system.debug('Integer : '       + xs.getType(t10));
    Decimal     t11 = 18.99;                                system.debug('Decimal : '       + xs.getType(t11));
    Double      t12 = 77.99;                                system.debug('Double : '        + xs.getType(t12));
    Long        t13 = 9;                                    system.debug('Long : '          + xs.getType(t13));
    

    It's quite obvious but, if you implement something like this, note that **order** of the lines above is important to get proper results returned.

    Also instanceof still returns true for null as of today (2014-08-28)

    You can detect sets and maps using overloading. And also distinguish Double from Decimal. Added an answer as the code's too long to fit in a comment.

    To add to Uwe Heim's comment: "instanceof sObject" appears to return true for a List -- so I believe the "if(o instanceof List)" line should come first

    Curiously, Integer is now getting picked up as a string.

License under CC-BY-SA with attribution


Content dated before 7/24/2021 11:53 AM