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