ArduinoJson 6.20 is finally out! This long-awaited release contains many changes on the inside but not so much on the outside. Indeed, in the year that passed since 6.19.0, I regularly committed changes to the code, but I didn’t publish a new release because I wanted to complete the internal cleanup before doing so.
In this article, I’ll review all the visible changes that 6.20 brings:
- a new “shallow copy” feature for
- a slightly stricter JSON parser,
- documentation for most public symbols,
- the rename of internal symbols,
- the removal of many undocumented functions,
- a new overload of
- the removal of support for naked
Up till now, we had to copy all the data into a huge
JsonDocument, like so:
DynamicJsonDocument gpsConfig = getGpsConfig(); DynamicJsonDocument gpioConfig = getGpioConfig(); DynamicJsonDocument config(4096); config["gps"] = gpsConfig; config["gpio"] = gpioConfig; serializeJson(config, file);
Now, we can use
JsonVariant::shallowCopy() to include the data without making a copy:
DynamicJsonDocument gpsConfig = getGpsConfig(); DynamicJsonDocument gpioConfig = getGpioConfig(); StaticJsonDocument<128> config; config["gps"].shallowCopy(gpsConfig); config["gpio"].shallowCopy(gpioConfig); serializeJson(config, file);
By avoiding the deep copy, this feature reduces the size of the final
JsonDocument and improves performance.
Of course, since the new
JsonDocument refers to the nested ones, you must ensure they remain in memory for the whole operation.
Stricter JSON parser
ArduinoJson’s JSON parser has always favored code size over strict conformance. It never rejects a valid JSON document, but it may accept an invalid JSON document in some cases.
For example, up till now, the parser avoided string comparisons for the
Instead, it just looked at the first character and the string length.
In other words, it accepted any four-letter word starting with
Unfortunately, the optimization made the parser confuse error messages with valid JSON documents.
For example, a user reported that
deserializeJson(doc, "force esp exception") returned
This is a small problem, but the diagnosis can take some time; that’s why I decided to remove this optimization.
Now, ArduinoJson 6.20 checks the entire word for
There remain some cases where the parser will overlook errors in the input; for example, it will not report incorrect UTF-16 surrogates pairs.
I added a short comment on the top of almost every public symbol of the library. These comments should appear in your IDE when you hover a symbol.
As you can see, I didn’t use any markup in the comments because I couldn’t not find something that worked correctly in both Visual Studio and Visual Studio Code. As a result, each comment is a one- or two-line description followed by a link to the full documentation.
Unfortunately, the Arduino IDE is not showing symbol comments, but hopefully, it will do in the future.
Massive internal renames
While I liked the flexibility and expressiveness these names gave me, I now think it was a bad idea.
The first issue is that the internal names frequently appear in the error messages, which confuses users.
The second issue is that I had to use
typedef to rename the symbols, and Visual Studio Code refused to show the documentation for those.
That is why I decided to rename every internal symbol to match the public ones.
Another issue we used to have with IDEs is that they suggested functions reserved for internal use, and some users ended up using them as if they were part of the official API.
For example, I saw some of you use functions like
getOrCreateMember() even though they were supposed to be internal to the library.
As part of this “developer experience” package, I decided to hide as much internal stuff as possible. Of course, this is a breaking change, but that’s what happens when one uses undocumented APIs. Fortunately, you can easily recreate the behavior of internal functions with the public API.
Here is how you can update you code:
// before JsonVariant a = variant.getElement(idx); JsonVariant b = variant.getOrAddElement(idx); JsonVariant c = variant.getMember(key); JsonVariant d = variant.getOrAddMember(key); // after JsonVariant a = variant[idx]; JsonVariant b = idx < variant.size() ? variant[idx] : variant[idx].to<JsonVariant>(); JsonVariant c = variant[key]; JsonVariant d = variant.containsKey(key) ? variant[key] : variant[key].to<JsonVariant>();
New overload of
In all these removed internal functions,
addElement() couldn’t be easily recreated with the public ones, so I decided to rename it and make it part of the public API. It’s now available as the parameterless overload of
This function appends an empty element to an array and returns a reference to the new element. I don’t expect this function to be very popular, but I call it in many places in the library, so I figured I might as well make it available to everyone.
Fun fact: this undocumented function used to be named
JsonArray::add() three years ago when ArduinoJson 6 was still in beta. I literally went full circle on that one.
Removed support for
Support for naked
chars was marked deprecated since ArduinoJson 6.18 because it caused issues with
After a year and a half, I removed this deprecated code.
This is a breaking change: you must replace
char with either
unsigned char, or any other integer type.
Similarly, you must replace
// before char age = doc["age"]; auto name = doc["name"].as<char*>(); // after int8_t age = doc["age"]; auto name = doc["name"].as<const char*>();
As usual, I try to keep the library as small as possible, so I constantly monitor the size of the five most representative examples. You can see the evolution in the two charts below.
The library grew a little because of a simplification I introduced in the string adapters. These classes allow ArduinoJson to support several types of string (
const char*, Flash strings,
std::string_view), and I wanted to simplify the API so that you could easily add your custom string adapter in the future.
The next version of ArduinoJson should come very soon but will not bring any new features because I’ll dedicate the release to dropping support for C++03.
Apparently, I was one of the last library developers still caring about old C++ compilers. Chances are that all ArduinoJson users switched to modern compilers a long time ago; that’s why I’ll make C++11 a requirement for version 6.21.
As you should see in the banner at the top of
arduinojson.org, I’m currently running a survey to know if any of you still need support for C++03. If that’s your case, now is your last chance to raise your voice!
See you next year!
...or subscribe to the RSS feed