How to upgrade from ArduinoJson 5 to 7
ArduinoJson has changed a lot since version 5, so the upgrade process is quite complicated. I recommend that you read the whole document before starting and then proceed step by step.
ArduinoJson 7 is significantly bigger ⚠️
ArduinoJson 5 had a strong focus on code size because 8-bit microcontrollers were largely dominant at the time. ArduinoJson 7 loosened the code size constraint to focus on ease of use. As a result, version 7 is significantly bigger than version 5.
If your program targets 8-bit microcontrollers, I recommend upgrading to version 6 instead, which size is comparable to version 5.
References
In ArduinoJson 5, JsonArray
and JsonObject
were always returned by reference to emphasize that they reside in the JsonBuffer
.
In ArduinoJson 7, JsonArray
, JsonObject
, and JsonVariant
are smart pointers, so they are returned by value.
- JsonObject& obj = ...
+ JsonObject obj = ...
- JsonArray& arr = ...
+ JsonArray arr = ...
Don’t be fooled by the fact that they are returned by value: they don’t contain a copy of the array/object but a pointer to the original one located in the JsonDocument
(see next item).
JsonDocument
With ArduinoJson 5, it was very difficult to use a JsonObject
or a JsonArray
as a class member because you had to ensure that the JsonBuffer
also stayed in memory. The trick was to add the JsonBuffer
as a class member too, but it was more complicated than it should be.
ArduinoJson 7 replaces the concept of JsonBuffer
with the concept of JsonDocument
. The JsonDocument
owns the memory and contains the root of the object tree. You can see a JsonDocument
as a combination of JsonBuffer
and JsonVariant
. Also, there is no need to specify the capacity anymore.
- StaticJsonBuffer<200> jsonBuffer;
+ JsonDocument doc;
- DynamicJsonBuffer jsonBuffer(200);
+ JsonDocument doc;
Automatic conversion
In ArduinoJson 5, you had to call either JsonBuffer::createArray()
or JsonBuffer::createObject()
to create an empty array or object.
In ArduinoJson 7, you don’t need to choose because the JsonDocument
automatically switches to the right type (array or object) according to the way you use it.
For example, in the following snippet, the JsonDocument
implicitly converts to an object:
JsonDocument doc;
doc["hello"] = "world";
// doc contains {"hello":"world"}
Whereas in the next snippet, it converts to an array:
JsonDocument doc;
doc.add("hello");
doc.add("world");
// doc contains ["hello","world"]
This automatic conversion occurs when the JsonDocument
is empty, but you can also force a conversion by calling to<T>()
:
JsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
obj["hello"] = "world";
This can be useful when you need to create an empty object or array.
deserializeJson()
In ArduinoJson 5, you invoked the JSON parser by calling JsonBuffer::parseObject()
or JsonBuffer::parseArray()
.
In ArduinoJson 7, you call the function deserializeJson()
and pass the JsonDocument
and input as arguments.
- JsonObject& obj = jb.parseObject(input);
+ deserializeJson(doc, input);
Each time you call deserializeJson()
, it clears the JsonDocument
, so you can reuse a JsonDocument
several times, which was not possible with JsonBuffer
.
DeserializationError
In ArduinoJson 5, you used JsonObject::success()
or JsonArray::success()
to check whether the parsing succeeded, and you had no information on what went wrong.
In ArduinoJson 7, you can look at the DeserializationError
returned by deserializeJson()
. You can test individual values like DeserializationError::InvalidInput
or DeserializationError::NoMemory
, or you can simply convert the error to a string by calling .c_str()
.
- JsonObject& obj = jb.parseObject(input);
+ DeserializationError error = deserializeJson(doc, input);
- if (!obj.success()) {
+ if (error) {
- Serial.println("parseObject() failed");
+ Serial.print("deserializeJson() returned ");
+ Serial.println(error.c_str());
return;
}
createNestedArray()
and createNestedObject()
In ArduinoJson 5, createNestedArray()
and createNestedObject()
allowed adding a new array or object in an existing array or object.
In ArduinoJson 7, these functions are replaced with add<T>()
and to<T>()
.
For example, to create an array of objects, you could write:
- JsonObject& phineas = root.createNestedObject();
+ JsonObject phineas = doc.add<JsonObject>();
phineas["first"] = "Phineas";
phineas["last"] = "Flynn";
- JsonObject& ferb = root.createNestedObject();
+ JsonObject ferb = doc.add<JsonObject>();
ferb["first"] = "Ferb";
ferb["last"] = "Fletcher";
And to create an array in an object, you could write:
- JsonArray& ports = doc.createNestedArray("ports");
+ JsonArray ports = doc["ports"].to<JsonArray>();
ports.add(80);
ports.add(443);
containsKey()
In ArduinoJson 5, containsKey()
checked if an object contained a specific key.
In ArduinoJson 7, you must use operator[]
followed by is<T>()
.
- if (obj.containsKey("key")) {
+ if (obj["key"].is<int>()) {
int value = obj["key"];
// ...
}
This syntax not only checks that the key exists but also that the value is of the expected type. It was already available in ArduinoJson 5.
serializeJson()
and serializeJsonPretty()
In ArduinoJson 5, when you wanted to serialize a JsonArray
or a JsonObject
, you called JsonArray::printTo()
or JsonObject::printTo()
.
In ArduinoJson 7, you call the function serializeJson()
and pass it the JsonDocument
.
- obj.printTo(Serial);
+ serializeJson(doc, Serial);
Similarly, you can call serializeJsonPretty()
to produce a prettified JSON document.
measureJson()
and measureJsonPretty()
With ArduinoJson 5, you could compute the length of the serialized document by calling JsonArray::measureLength()
or JsonObject::measureLength()
.
With ArduinoJson 7, you call measureJson()
to do that.
- size_t len = obj.measureLength();
+ size_t len = measureJson(doc);
Similarly, measureJsonPretty()
replaces JsonArray::measurePrettyLength()
and JsonObject::measureJsonPretty()
.
Nesting limit
In ArduinoJson 5, you could change the nesting limit by passing an optional argument to JsonBuffer::parseArray()
or JsonBuffer::parseObject()
.
In ArduinoJson 7, you must pass this value to deserializeJson()
and cast it to DeserializationOption::NestingLimit
:
- JsonObject& obj = jb.parseObject(input, 20);
+ deserializeJson(doc, input, DeserializationOption::NestingLimit(20));
serialized()
In ArduinoJson 5, when you wanted to insert a preformatted piece of JSON, you called RawJson()
.
In ArduinoJson 7, you call serialized()
:
- obj["raw"] = RawJson("[1,2,3]");
+ doc["raw"] = serialized("[1,2,3]");
JsonPair
In ArduinoJson 5, when you enumerated the members of a JsonObject
, you received a JsonPair
with two member variables: key
and value
. The first was a const char*
and the second a JsonVariant
.
In ArduinoJson 7, JsonPair::key()
and JsonPair::value()
are member functions. Also, key
doesn’t return a const char*
but a JsonString
, so you must call JsonString::c_str()
to get the pointer.
for (JsonPair p : obj) {
for (JsonPair p : obj) {
- const char* key = p.key;
+ const char* key = p.key().c_str();
- JsonVariant value = p.value;
+ JsonVariant value = p.value();
...
}
copyArray()
In ArduinoJson 5, you could easily copy values between a JsonArray
and a C array using JsonArray::copyFrom()
and JsonArray::copyTo()
.
In ArduinoJson 7, you must call copyArray()
instead. There is only one function for both operations.
The first argument is the source, and the second is the destination.
int values[] = {1,2,3};
- arr.copyFrom(values);
+ copyArray(values, arr);
- arr.copyTo(values);
+ copyArray(arr, values);
JsonVariant
is a reference
In ArduinoJson 5, JsonVariant
had value semantic, and you could create an instance without a JsonBuffer
.
In ArduinoJson 7, JsonVariant
has reference semantics, like JsonArray
and JsonObject
, and you need a JsonDocument
to create one.
- JsonVariant var = 42;
+ JsonDocument doc;
+ JsonVariant var = doc.to<JsonVariant>();
+ var.set(42);
But you could also set the value directly on the JsonDocument
:
- JsonVariant var = 42;
+ JsonDocument doc;
+ doc.set(42);
isNull()
In ArduinoJson 5, you checked if an array or an object was valid by calling success()
.
In ArduinoJson 7, you use isNull()
instead:
- if (!obj.success()) ...
+ if (obj.isNull()) ...
isNull()
is not the exact opposite of success()
: when the value is defined but is null
, both isNull()
and success()
return true
.
Also, note that, in ArduinoJson 5, is<const char*>()
returned true
if the value was null
; it’s no longer the case in version 7.
Lastly, there is also a conversion to boolean, which returns false
if the value of the JsonArray
, JsonObject
, or JsonVariant
is null
or false
. So, in most cases, you can simply write:
- if (!obj.success()) ...
+ if (!obj) ...
Naked char
ArduinoJson 7 no longer supports the char
type, so you must replace it with either signed char
, unsigned char
, int8_t
, uint8_t
, or any other integral type.
- char age = obj["age"];
+ int8_t age = doc["age"];
- auto height = obj["height"].as<char>();
+ auto height = doc["height"].as<int8_t>();
Non-const char*
ArduinoJson 7 doesn’t support non-const char*
, so you must always use const char*
.
- Serial.println(obj["msg"].as<char*>());
+ Serial.println(doc["msg"].as<const char*>());