当前位置: 首页 > 工具软件 > ArduinoJson > 使用案例 >

ArduinoJson 5升级到ArduinoJson 6

雍飞雨
2023-12-01

Migrating from version 5 to 6

References

With ArduinoJson 5, JsonArray and JsonObject were always returned by reference, to emphasize the fact that they reside in the JsonBuffer.

// ArduinoJson 5
JsonObject& obj = ...

ArduinoJson 6 simplifies that by returning wrapper classes: JsonArray, JsonObject, and JsonVariant. Be careful though, the memory for these objects is still held somewhere else, as we’ll see.

// ArduinoJson 6
JsonObject obj = ...

As you can see, you just need to remove the ampersand (&).

JsonDocument

With ArduinoJson 5, it was very difficult to use a JsonObject or a JsonArray as a class member because you had to make sure that the JsonBuffer stayed in memory too. The trick was to add the JsonBuffer as a class member too, but it was more complicated than it should be.

ArduinoJson 6 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.

Since a JsonDocument can contain any kind of value, you need to cast it to read the content. For example:

JsonObject root = doc.as<JsonObject>(); // get the root object

Similarly, a JsonDocument can be repurposed to hold any kind of values. That is done via JsonDocument::to<T>(). For example, you can reset a JsonDocument to hold a JsonObject like that:

JsonObject root = doc.to<JsonObject>(); // clear and replace with a new JsonObject

Lastly, you can assign a JsonDocument to another to get a deep copy:

DynamicJsonDocument doc2 = doc1; // makes a copy

Automatic conversion

Most of the time, you can skip the call to JsonDocument::to<T>() because the JsonDocument automatically converts to the right type on the first call.

In the following example, the JsonDocument implicitly converts to an object:

doc["hello"] = "world";

// The above line is equivalent to:
JsonObject root = doc.to<JsonObject>();
root["hello"] = "world";

In the following example, the JsonDocument implicitly converts to an array:

doc.add("hello");

// The above line is equivalent to:
JsonArray root = doc.to<JsonArray>();
root.add("hello");

Of course, the automatic conversion only occurs when the JsonDocument is empty.

StaticJsonDocument and DynamicJsonDocument

As the JsonBuffer, there are two versions of the JsonDocument.

The first is StaticJsonDocument, which is the equivalent of StaticJsonBuffer:

// ArduinoJson 5
StaticJsonBuffer<256> jb;

// ArduinoJson 6
StaticJsonDocument<256> doc;

The second is DynamicJsonDocument, which is the equivalent of DynamicJsonBuffer:

// ArduinoJson 5
DynamicJsonBuffer jb;

// ArduinoJson 6
DynamicJsonDocument doc(1024);

DynamicJsonDocument has a fixed capacity that you must specify to the constructor. Unlike the DynamicJsonBuffer, DynamicJsonDocument doesn’t automatically expand.

deserializeJson()

With ArduinoJson 5, you invoked the JSON parser by calling JsonBuffer::parseObject() or JsonBuffer::parseArray().

// ArduinoJson 5
JsonObject& obj = jb.parseObject(input);

With ArduinoJson 6, you call the function deserializeJson() and pass the JsonDocument and the input as arguments.

// ArduinoJson 6
deserializeJson(doc, input);

Each time you call deserializeJson(), it clears the JsonDocument. This feature allows reusing the same JsonDocument several times, which was not possible with the JsonBuffer. Please do not see that as an invitation to use a global JsonDocument as it’s an inelegant and inefficient solution.

DeserializationError

With ArduinoJson 5, you used JsonObject::success() or JsonArray::success() to check whether the parsing succeeded or not, and you had no information on what went wrong.

// ArduinoJson 5
JsonObject& obj = jb.parseObject(input);
if (!obj.success()) {
   Serial.println("parseObject() failed");
   return;
}

With ArduinoJson 6, 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().

Here is an example:

// ArduinoJson 6
auto error = deserializeJson(doc, input);
if (error) {
    Serial.print(F("deserializeJson() failed with code "));
    Serial.println(error.c_str());
    return;
}

serializeJson() and serializeJsonPretty()

With ArduinoJson 5, when you wanted to serialize a JsonArray or a JsonObject to a JSON document, you called JsonArray::printTo() or JsonObject::printTo().

// ArduinoJson 5
obj.printTo(Serial);

With ArduinoJson 6, you call the function serializeJson() and pass the JsonArray, JsonObject, or the JsonDocument.

// ArduinoJson 6
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().

// ArduinoJson 5
size_t len = obj.measureLength();

With ArduinoJson 6, you call measureJson() to to that.

// ArduinoJson `6`
size_t len = measureJson(doc);

Similarly, measureJsonPretty() replaces JsonArray::measurePrettyLength() and JsonObject::measureJsonPretty().

Non-zero-terminated inputs

ArduinoJson 5 didn’t impose that the input was zero-terminated, but it was strongly recommended to prevent buffer overruns.

With ArduinoJson 6, you can pass an extra argument to deserializeJson() to specify the maximum size of the input.

For example:

// ArduinoJson 6
deserializeJson(doc, input, inputSize);

Nesting limit

With ArduinoJson 5, you could change the nesting limit by passing an optional argument to JsonBuffer::parseArray() or JsonBuffer::parseObject().

// ArduinoJson 5
JsonObject& obj = jb.parseObject(input, 20);

With ArduinoJson 6, you must pass this value to deserializeJson() and cast it to DeserializationOption::NestingLimit:

// ArduinoJson 6
deserializeJson(doc, input, DeserializationOption::NestingLimit(20));

MessagePack

ArduinoJson 6 supports both serialization and deserialization of MessagePack documents.

However, it currently doesn’t support the following features of MessagePack:

To create a MessagePack document, you use the same technique as for a JSON document, except that you call serializeMsgPack() instead of serializeJson().

// ArduinoJson 6
serializeMsgPack(doc, Serial);

Similarly, to deserialize a MessagePack document, you proceed as for a JSON document, except that you call deserializeMsgPack() instead of deserializeJson(). For example:

// ArduinoJson 6
deserializeMsgPack(doc, input);

serialized()

With ArduinoJson 5, when you wanted to insert a preformatted piece of JSON, you called RawJson().

// ArduinoJson 5
obj["raw"] = RawJson("[1,2,3]");

With ArduinoJson 6, you call serialized() which does exactly the same thing, except that it also supports MessagePack and non-zero-terminated strings.

// ArduinoJson 6
doc["raw"] = serialized("[1,2,3]");

JsonPair

With ArduinoJson 5, when you enumerated the member in a JsonObject, you received a JsonPair with two member variables key and value. The first was a const char* and the second a JsonVariant.

// ArduinoJson 5
for (JsonPair p : obj) {
    const char* key = p.key;
    JsonVariant value = p.value;
    ...
}

In ArduinoJson 6, JsonPair::key and JsonPair::value are member function. Also, key doesn’t return a const char* but a JsonString. You must call JsonString::c_str() to get the pointer.

// ArduinoJson 6
for (JsonPair p : obj) {
    const char* key = p.key().c_str();
    JsonVariant value = p.value();
    ...
}

copyArray()

With ArduinoJson 5, you could easily copy values between a JsonArray and a regular array using JsonArray::copyFrom() and JsonArray::copyTo().

int values[] = {1,2,3};

// ArduinoJson 5
arr.copyFrom(values);
arr.copyTo(values);

With version 6.9, 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};

// ArduinoJson 6
copyArray(values, arr);
copyArray(arr, values);

JsonVariant is a reference

With ArduinoJson 5, JsonVariant had value semantic. It was possible to create a instance without a JsonBuffer.

// ArduinoJson 5
JsonVariant var = 42;

With ArduinoJson 6, JsonVariant has reference semantics, like JsonArray and JsonObject. You need a JsonDocument to initialize a JsonVariant.

// ArduinoJson 6
JsonVariant var = doc.to<JsonVariant>();
var.set(42);

isNull()

With ArduinoJson 5, you checked if an array or an object was valid by calling success():

// ArduinoJson 5
if (!obj.success()) ...

With ArduinoJson 6, you use isNull() instead:

// ArduinoJson 6
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 6.

Summary

Deserialization

// ArduinoJson 5
DynamicJsonBuffer jb;
JsonObject& obj = jb.parseObject(json);
if (!obj.success()) 
  return;
int value = obj["value"];
// ArduinoJson 6
DynamicJsonDocument doc(1024);
DeserializationError error = deserializeJson(doc, json);
if (error)
  return;
int value = doc["value"];

Serialization

// ArduinoJson 5
DynamicJsonBuffer jb;
JsonObject& obj = jb.createObject();
obj["key"] = "value";
obj["raw"] = RawJson("[1,2,3]");
obj.printTo(Serial);
// ArduinoJson 6
DynamicJsonDocument doc(1024);
doc["key"] = "value";
doc["raw"] = serialized("[1,2,3]");
serializeJson(doc, Serial);
 类似资料: