ArduinoJson: F.A.Q

How to reuse a JsonBuffer?

This is a very popular question, make sure you understand the following statement:

A JsonBuffer cannot be reused.
You must create a new instance if you need a fresh buffer.

Why is there no clear() or reset() function?

Many users want to reuse their buffer, so they don’t understand why JsonBuffer doesn’t have a clear() or reset() function.

This is a legitimate request, but can you spot the error in the following code?

// 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:

  • inputObject is a pointer to an object whose memory is in jsonBuffer.
  • clear() resets the memory pool in jsonBuffer, allowing to reuse the memory of inputObject
  • outputObject is created at the same address as inputObject
  • inputObject is now a dangling pointer and the behavior is undefined.

How to fix this code?

The error in the code above is caused by the clear() function.
That is why no such function exists in ArduinoJson.

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);
}

I get your point, but I don’t care!

OK smartypants, do you know that you can write your own clear() or reset() function?

template<typename T>
void clear(T& instance)
{
    instance = T();
}

Be sure to understand the consequence before using this.

See also

Fork me on GitHub