I'm using Delphi XE3. I have a JSON stream where an object can be null. That is, I can receive:
"user":null
or
"user":{"userName":"Pep","email":"[email protected]"}
I want to discriminate both cases, and I tried with this code:
var
jUserObject: TJSONObject;
jUserObject := TJSONObject(Get('user').JsonValue);
if (jUserObject.Null)
then begin
FUser := nil;
end else begin
FUser := TUser.Create;
with FUser, jUserObject do begin
FEmail := TJSONString(Get('email').JsonValue).Value;
FUserName := TJSONString(Get('userName').JsonValue).Value;
end;
end;
If I put a breakpoint right in line if (jUserObject.Null) then begin
and I mouse over jUserObject.Null
it says jUserObject.Null = True
if "user":null
and it says jUserObject.Null = False
if "user":{"userName":"Pep","email":"[email protected]"}
However, if I step into that line with the debugger, jUserObject.Null calls the following XE3 library code:
function TJSONAncestor.IsNull: Boolean;
begin
Result := False;
end;
So I always get a False
for my if
sentence, even if "user":null
.
I suppose I always have the workaround of catching the exception that is raised when "user":null
and Get('email').JsonValue
is executed in order to discriminate if the value is null or not, but that does not seem so elegant.
How is one supposed to detect if an JSON object has a null value in the JSON stream?
Get()
returns a TJSONPair
. When you have "user":null
, the TJSONPair.JsonValue
property will return a TJSONNull
object, not a TJSONObject
object. Your code is not accounting for that possibility. It assumes the JsonValue
is always a TJSONObject
and not validating the type-cast.
There are two ways to handle this.
TJSONPair
has its own Null
property that specifies whether its JsonValue
is a null value or not:
var
JUser: TJSONPair;
jUserObject: TJSONObject;
jUser := Get('user');
if jUser.Null then begin
FUser := nil;
end else begin
// use the 'as' operator for type validation in
// case the value is something other than an object...
jUserObject := jUser.JsonValue as TJSONObject;
...
end;
Use the is
operator to test the class type of the JsonValue
before casting it:
var
JUser: TJSONPair;
jUserObject: TJSONObject;
jUser := Get('user');
if jUser.JsonValue is TJSONNull then begin
FUser := nil;
end
else if jUser.JsonValue is TJSONObject then begin
jUserObject := TJSONObject(jUser.JsonValue);
...
end else begin
// the value is something other than an object...
end;
You've made the common mistake of confusing JSON objects with Delphi objects. The TJSONObject
class represents JSON objects only, which are never null because null
is distinct from {...}
. TJSONObject
is not the ancestor for all JSON values, like your code assumes. TJSONValue
is.
Don't type-cast your "user" value to TJSONObject
until you know it's an object. Check the Null
property first, then type-cast.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With