bblanchon / ArduinoJson

📟 JSON library for Arduino and embedded C++. Simple and efficient.
https://arduinojson.org
MIT License
6.63k stars 1.1k forks source link

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

Closed judge2005 closed 1 month ago

judge2005 commented 2 months ago

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:

    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
bblanchon commented 2 months ago

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

judge2005 commented 2 months ago

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().

bblanchon commented 2 months ago

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.

judge2005 commented 2 months ago

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.

bblanchon commented 2 months ago

Which part of the documentation are you referring to?

judge2005 commented 2 months ago

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.

bblanchon commented 2 months ago

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