10

I am working on a REST Service that will desiralize the request body and interpret it. My understanding was that calling String.valueOf(objectInstance) would just call objectInstance.toString(). However, I am observing different behavior.

Working

Blob requestBody = Blob.valueOf('[{"key":"value"}]');
List<Object> body = (List<Object>)JSON.deserializeUntyped(requestBody.toString());

Not Working

Blob requestBody = Blob.valueOf('[{"key":"value"}]');
List<Object> body = (List<Object>)JSON.deserializeUntyped(String.valueOf(requestBody));

The above throws:

Line: 11, Column: 1

System.JSONException: Unexpected character ('B' (code 66)): expected a valid value (number, String, array, object, 'true', 'false' or 'null') at input location [1,2]

13

String.valueOf returns Blob[X] for Blob values. I believe it does it this way because System.debug internally uses String.valueOf, and debugging a potentially non-Unicode stream into a Unicode String could break things. In other words, you can't reliably use String.valueOf unless you can also use it in System.debug and get the output you expect. String.valueOf is always safe to use on a Blob, but Blob.toString may result in an exception if the contents are not a Unicode String.

Let's go with some examples to show how other standard and custom objects behave:

String.valueOf(JSON.createParser('[]'));
// JSONParser:[delegate=common.apex.json.ApexJsonParser@7cde3f62]

String.valueOf(Crypto.generateAesKey(128));
// Blob[16]

String.valueOf([SELECT Id FROM Account LIMIT 1]);
// (Account:{Id=001..., RecordTypeId=012...})

String.valueOf(new MyClassWithoutToString());
// or //
new MyClassWithoutToString().toString();
// MyClasswithoutTostring:[key1=value1, key2=value2]

String.valueOf(new MyClassWithToString());
// Hello There. I work correctly because I have an overridden toString.

String.valueOf(Date.today());    Date.today().format()
// 2016-02-10                    // 2/10/2016

Database.getQueryLocator([SELECT Id FROM Account LIMIT 1])
// Database.QueryLocator[Query=SELECT Id FROM Account LIMIT 1]

String.valueOf(Database.setSavepoint());
// SavepointValue0

String.valueOf(new Component.MyCustomComponent());
// *** Crashes and produces no logs ***

As you can see, you can never quite be sure what you're going to get out of it, unless you're using one of the concrete types listed in the documentation, which is currently: Date, DateTime, Decimal, Integer, and Long.

It does say that it supports "Object" generically, but generally speaking, you'll get the "debug safe" version of a string if you do so, which means it will probably be the wrong value.

1
  • Whoa. This is fantastic to know. puts like behavior from String.valueOf for in page debug statements, yes please! Feb 11 '16 at 4:08

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.