ArduinoJson: F.A.Q

How to reuse a JsonBuffer?

Disclaimer

Since ArduinoJson 5.11.0, it’s possible to reuse a JsonBuffer thank to the clear() method. However, it’s very risky and can be avoided most of the time.

Please take a second to see this example:

// STEP1: parse input
StaticJsonBuffer<200> jsonBuffer;
JsonObject& inputObject = jsonBuffer.parseObject(inputJson);

...etc...

// STEP2: generate output
jsonBuffer.clear();
JsonObject& outputObject = jsonBuffer.createObject();
outputObject["hello"] = inputObject["world"];

The program above looks OK but causes an access violation.

An experienced C++ developer would find the error instantly, especially if she has a debugger. But most Arduino developers are new to C++ and none of them have a debugger.

Here is what happens in this buggy program:

How to fix this code?

To rewrite this code without clear(), we have two possibilities.

Suggestion 1: use a bigger JsonBuffer:

// STEP1: parse input
StaticJsonBuffer<400> jsonBuffer;
JsonObject& inputObject = jsonBuffer.parseObject(inputJson);

...etc...

// STEP2: generate output
JsonObject& outputObject = jsonBuffer.createObject();
outputObject["hello"] = inputObject["world"];

Suggestion 2: use a second JsonBuffer:

// STEP1: parse input
StaticJsonBuffer<200> jsonBuffer1;
JsonObject& inputObject = jsonBuffer1.parseObject(inputJson);

...etc...

// STEP2: generate output
StaticJsonBuffer<200> jsonBuffer2;
JsonObject& outputObject = jsonBuffer2.createObject();
outputObject["hello"] = inputObject["world"];

What if I don’t reference the memory after clearing?

You mean, like this?

void sendAll()
{
  // Create JSON buffer
  StaticJsonBuffer<100> jsonBuffer;
  
  // Create object
  JsonObject& root = jsonBuffer.createObject();
  
  // Send volume
  root[F("cmd")] = F("volume");
  root[F("volume")] = dsp.volumeData;
  root[F("slew")] = dsp.volumeSlewData;
  rs485.send(jsonAck, jsonBuffer);

  // Send mux
  // Clear or delete JSON buffer here
  root[F("cmd")] = F("mux");
  root[F("muxdata")] = dsp.muxdata;
  rs485.send(jsonAck, jsonBuffer);

  // ...
}

well, just split the function:

void sendAll()
{
    sendVolume();
    sendMux();
    //...
}

void sendVolume()
{
  StaticJsonBuffer<100> jsonBuffer;
  JsonObject& root = jsonBuffer.createObject();
  root[F("cmd")] = F("volume");
  root[F("volume")] = dsp.volumeData;
  root[F("slew")] = dsp.volumeSlewData;
  rs485.send(jsonAck, jsonBuffer);
}

void sendMux()
{
  StaticJsonBuffer<100> jsonBuffer;
  JsonObject& root = jsonBuffer.createObject();
  root[F("cmd")] = F("mux");
  root[F("muxdata")] = dsp.muxdata;
  rs485.send(jsonAck, jsonBuffer);
}

See also

Where to go next?

In the ArduinoJson ebook, explains extensively how StaticJsonBuffer and DynamicJsonBuffer works. Once you understand how they are made, it becomes obvious why they cannot be reused.

The book also contains a quick C++ course to catch up with pointers, references, and how they cause failures. It describes the concept of RAII (Resource Acquisition Is Initialization) which is the foundation for proper memory management in C++.

Fork me on GitHub