ArduinoJson icon indicating copy to clipboard operation
ArduinoJson copied to clipboard

JsonVariant tests false for both a value that doesn't exist and for a value that is zero

Open judge2005 opened this issue 1 year ago • 7 comments

Describe the bug
In v7 JsonVariant tests false for both a value that doesn't exist and for a value that is zero, yet the documentation recommends that operator[] be used to test if a key is there rather than containsKey().

Troubleshooter report
I don't see how the troubleshooter can be used to answer this

Environment
Here is the environment that I used:

  • Microcontroller: ESP32
  • IDE: platformio Reproduction
    Here is a small snippet that reproduces the issue.
    JsonDocument test;
    JsonVariant value = test["test"];
    if (value) {
        Serial.println("[1] value found");
    } else {
        Serial.print("[1] value not found, value=");Serial.println(value.as<int>());
    }

    test["test"] = 0;
    if (value) {
        Serial.print("[2] value found, value=");Serial.print(value.as<int>());
    } else {
        Serial.print("[2] value not found, value=");Serial.println(value.as<int>());
    }

Program output
If relevant, include the repro program output.

Expected output:

[1] value not found, value=0
[2] value found, value=0

Actual output:

[1] value not found, value=0
[2] value not found, value=0

judge2005 avatar Apr 27 '24 23:04 judge2005

Hi @judge2005,

Thank you for this feedback but I don't see any problem since this behavior is consistent with the conversion to bool. For example:

JsonVariant var;
var.as<bool>();  // false

JsonDocument doc;
var = doc.to<JsonVariant>();
var.as<bool>();  // false

var.set(false);
var.as<bool>();  // false

var.set(true);
var.as<bool>();  // true

var.set(0);
var.as<bool>();  // false

var.set(1);
var.as<bool>();  // true

var.set(nullptr);
var.as<bool>();  // false

var.set("hello world");
var.as<bool>();  // true

var = doc.to<JsonArray>();
var.as<bool>();  // true

var = doc.to<JsonObject>();
var.as<bool>();  // true

Best regards, Benoit

bblanchon avatar Apr 29 '24 08:04 bblanchon

The problem is that using operator[] I can’t tell the difference between an attribute that doesn’t exist and one that does exist but who’s value is zero. However that is the solution recommended by the documentation. In reality I have to use containsKey().

judge2005 avatar Apr 30 '24 17:04 judge2005

You can use value.is<int>(). Not only does it tell you that the value is present, but it also confirms it has the expected type, making your code even more robust.

bblanchon avatar May 01 '24 15:05 bblanchon

That is good, but I am trying to make the point that the documentation is misleading. If it is followed it would lead to code that does not function correctly. The documentation states that operator[] can be used to determine if an attribute is present or not because it returns false if the attribute is not present. In fact it will also return false if the attribute is present but is either a numeric zero or a boolean false.

judge2005 avatar May 02 '24 23:05 judge2005

Which part of the documentation are you referring to?

bblanchon avatar May 04 '24 16:05 bblanchon

https://arduinojson.org/v7/api/jsonvariant/containskey/

The text under the heading "Avoid this function when you can!"

Because ArduinoJson implements the Null Object Pattern, it is always safe to read the object: if the key doesn’t exist, it returns an empty value.

Which is only true in the sense that it will always return something rather than throwing an exception.

judge2005 avatar May 04 '24 18:05 judge2005

I'm sorry I don't see any problem with this paragraph. How would you rephrase it?

bblanchon avatar May 06 '24 09:05 bblanchon