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 with .to<JsonArray>(); #2060

Closed EvEggelen closed 4 months ago

EvEggelen commented 4 months ago

ArduinoJson @ 7.0.3

Based on the documentation I expected that the following was allowed with the new API. Not sure if this was intended or not. Initially I expected the same result for the 2 pieces of code ( see below ).

JsonVariant test=outputDoc["images"];
JsonArray outputlist=test.to<JsonArray>();

This code works:

   JsonArray outputlist=outputDoc["images"].to<JsonArray>();
    {
    JsonObject obj = outputlist.add<JsonObject>();
    obj["id"]=1;
    obj["v"]=2;
    }

    {
    JsonObject obj = outputlist.add<JsonObject>();
    obj["id"]=4;
    obj["v"]=5;
    }

    std::string output;
    serializeJson(outputDoc, output);

With the following code results in an empty array. Not what I expected.

    JsonVariant test=outputDoc["images"];
    JsonArray outputlist=test.to<JsonArray>();
    {
    JsonObject obj = outputlist.add<JsonObject>();
    obj["id"]=1;
    obj["v"]=2;
    }

    {
    JsonObject obj = outputlist.add<JsonObject>();
    obj["id"]=4;
    obj["v"]=5;
    }

    std::string output;
    serializeJson(outputDoc, output);
bblanchon commented 4 months ago

Hi @EvEggelen,

Thank you for this question.

In the documentation, I forgot to mention that JsonVariant::to<T>() is a no-op if the JsonVariant is unbound. Indeed, you cannot modify a value if there is no value to begin with.

In your case, outputDoc["images"] returns an unbound JsonVariant because there is no "images" member in outputDoc. Returning a bound JsonVariant would require adding the "images" member in outputDoc, which is not what people expect from JsonVariant test = outputDoc["images"].

outputDoc["images"].to<JsonArray>() works because it calls MemberProxy::to<T>(), which knows it must add the member if it's missing. MemberProxy is part of ArduinoJson's internal sauce, so I don't recommend using it in your app.

If you need a bound JsonVariant, you must initialize it with to<JsonVariant>():

- JsonVariant test = outputDoc["images"];
+ JsonVariant test = outputDoc["images"].to<JsonVariant>();
  JsonArray outputlist = test.to<JsonArray>();

This feature is not new to ArduinoJson 7; it was already like that in version 6.

Best regards, Benoit