Description

JsonDocument stores a JSON document in memory. It owns the memory referenced by JsonArray, JsonObject, and JsonVariant.

JsonDocument contains a fixed-size memory pool, with a monotonic allocator. This design allows ArduinoJson to be very efficient but requires some discipline on your side:

  1. Because the size is fixed, you need to specify the size when you create the JsonDocument
  2. Because the allocator is monotonic, it cannot release memory when you call JsonObject::remove() for example.

I strongly recommend against using a global JsonDocument because you would be troubled by the monotonic allocator, and would make inefficient use of your RAM.

On the contrary, I recommend declaring a short-lived JsonDocument that you use only in your serialization functions.

For details on how to choose the right capacity for the JsonDocument, please read How to determine the capacity of the JsonDocument?

StaticJsonDocument vs DynamicJsonDocument

You can choose to store your JsonDocument in the stack or in the heap:

You must specify the capacity of a StaticJsonDocument in a template parameter, like that:

StaticJsonDocument<256> doc;

For a DynamicJsonDocument, however, you must use a constructor argument:

DynamicJsonDocument doc(2048);

JsonDocument vs JsonVariant

JsonDocument shares many features with JsonVariant; however, there is one big difference: JsonDocument has value semantics, whereas JsonVariant has reference semantics.

On the one hand, because JsonDocument owns the data, if you copy a JsonDocument, you get a complete clone.

// make a clone of the JsonDocument
DynamicJsonDocument doc2 = doc1;

On the other hand, because JsonVariant is a reference, if you copy a JsonVariant, you only clone the reference:

// make a new reference to the same variant
JsonVariant var2 = var1;

Using a JsonDocument

When you create a JsonDocument, it is initially empty. At this stage, it’s neither an object, nor an array, and JsonDocument::isNull() returns true.

When you insert the first value in the JsonDocument, it automatically changes its type to match the call. If you use the JsonDocument like an array, it becomes an array; if you use the JsonDocument as an object, it becomes an object.

Here is a JsonDocument that implicitly becomes an object:

DynamicJsonDocument doc(1024);
doc["answer"] = 42;
// the doc contains {"answer":42}

Here is a JsonDocument that implicitly becomes an array:

DynamicJsonDocument doc(1024);
doc.add(42);
// the doc contains [42]

Sometimes, however, you’ll need to explicitly convert the JsonDocument without adding a value; for example, because you want to create an empty object. In this case you can call JsonDocument::to<T>():

DynamicJsonDocument doc(1024);
JsonObject obj = doc.to<JsonObject>();
// the doc contains {}

JsonDocument::to<T>() clears the document and converts it to the specified type. Don’t confuse this function with JsonDocument::as<T>() that returns a reference only if the requested type matches the one in the document.

Member functions

  • as<T>() casts the root to the specified type (e.g. JsonArray or JsonObject)
  • add() adds elements to the root array
  • capacity() returns the capacity of the memory pool
  • clear() empties the document and resets the memory pool
  • containsKey() tests if the root object contains the specified key
  • createNestedArray() creates a nested array attached to the root
  • createNestedObject() create a nested object attached to the root
  • garbageCollect() reclaims leaked memory blocks
  • operator[] gets or sets values in the document
  • overflowed() tells if the memory pool was large enough
  • is<T>() tests the type of the root
  • isNull() tells if the document is null or empty
  • memoryUsage() tells how many bytes are used in the memory pool
  • nesting() returns the number of nesting layers in the document
  • remove() removes an element (or member) at the specified index (or key)
  • set() replaces the root with the specified value
  • shrinkToFit() reduces the capacity of the memory pool to match the current usage* size() returns the number of elements (or members) that the root array (or object) contains
  • to<T>() clears the document and converts it to the specified type (e.g. JsonArray or JsonObject)

Example

Here is a program that deserializes a JSON document and stores it in the stack:

StaticJsonDocument<200> doc; // <- a little more than 200 bytes in the stack

char json[] = "{\"hello\":\"world\"}";
deserializeJson(doc, json);

const char* world = doc["hello"];

Here is a program that serializes a JSON document stored in the heap:

DynamicJsonDocument doc(200); // <- 200 bytes in the heap

doc["hello"] = "world";

serializeJson(doc, Serial); // {"hello":"world"}

See also

Global warming stripes by Professor Ed Hawkins (University of Reading)