4

Wondering if anyone can explain to me why without casting I get System.StringException: Invalid id: ..... caused by: Class.ocms_mli_ArticleLoader.getHTML: line 971.. error.

I have the following getter/setter on my class which either returns an Id or null:

...
public ID oTaxonomyMandatoryFilterNodeTagDefID {
        get {
           ID oTemp = null;
            if (this.oPageParametersMap.get('sTaxonomyMandatoryFilterNode') != null) { // GET/POST are case insensetive
                try {
                    oTemp = Id.valueOf(EncodingUtil.urlDecode(this.oPageParametersMap.get('sTaxonomyMandatoryFilterNode'), 'UTF-8'));
                }
                catch (Exception e) {}
            }
            else  {
                try {
                    Map<String, Object> oMap = (Map<String, Object>)JSON.deserializeUntyped(this.sTaxonomyMandatoryFilterNode);
                    oTemp = (ID)oMap.get('tagDefId');
                }
                catch (Exception e) {}
            }
            return oTemp;
        }
        set;

    }
...

Then in my code I am referencing the getter in a string concatenation like so:

...
 ',sTaxonomyMandatoryFilterNode: \'' + (this.oTaxonomyMandatoryFilterNodeTagDefID != null ? this.oTaxonomyMandatoryFilterNodeTagDefID : '')  + '\' \n'
...

At runtime, if my this.sTaxonomyMandatoryFilterNode contains a valid value the code works, if this.sTaxonomyMandatoryFilterNode == null the above error happens.

However, after some hair pulling I realized that if I cast to String then the issue is fixed:

...
 ',sTaxonomyMandatoryFilterNode: \'' + (this.oTaxonomyMandatoryFilterNodeTagDefID != null ? (String)this.oTaxonomyMandatoryFilterNodeTagDefID : '')  + '\' \n'
...

So why, at runttime when this.sTaxonomyMandatoryFilterNode == null the ternary operator errors out and the casting fixes it?

5

It occurs because '' is not a valid Id. When you use the ternary operator, it must be in the form of:

Boolean ? T : T;

where T is any single concrete type. If one of your ternary values is an Id and the other is a String, then the String parameter will implicitly be converted to an Id. When the system tries to do so, it generates an exception, because Id.valueOf('') is not a valid Id value. In other words, your expression tries to conform to:

Boolean ? Id : Id;

As you might imagine, casting to a String fixes the problem because your expression then becomes:

Boolean ? String : String;
  • That makes sense, what confuses me is why is it trying to cast the true statement even though this.sTaxonomyMandatoryFilterNode == null, this makes me think it's a greedy evaluation? – Daniel Sokolowski Feb 16 '16 at 23:06
  • Anyone interested I could not find any reference to types and ternary operators in SF docs, but perhaps assuming it's Java under the hood this holds true: stackoverflow.com/questions/25230171/… – Daniel Sokolowski Feb 16 '16 at 23:11
  • 2
    @DanielSokolowski It's funny how many assumptions that the documentation team makes about how much you should know about Java when using Apex Code. But, in short, yes, both types must end up being the same type, even though only one of the two values will be used. As a trivial example, System.assert((Object)(true? 5: 5.0) instanceOf Decimal); passes, but System.assert((Object)(true? 5: 5.0) instanceOf Integer); fails. The cast is needed here only because Apex Code refuses to compile trivial instanceOf checks (e.g. it already knows the type on the left). – sfdcfox Feb 16 '16 at 23:31
  • 1
    @sfdcfox Excellent! I like the way you explain things using System.assert – javanoob Feb 16 '16 at 23:59
  • geez louise - this just happened to me today, threw me for an hour's detour into wtf-land before it dawned on me what was happening: Account a = [select id,website from Account limit 1]; String res = String.isBlank(a.website) ? a.id : a.website; for a simple reproducible example. Casting solves it as you noted. – cropredy Jun 24 '16 at 0:16

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.