The JSON parser works in two different modes, depending on whether the input is read-only or not.

Mode 1: read-only input

ArduinoJson uses the “read-only” mode when you pass one of the following types to deserializeJson():

  1. const char*
  2. std::string
  3. std::istream
  4. String
  5. Stream
  6. const __FlashStringHelper*

In this mode, the parser copies relevant pieces of the input in the JsonDocument.

Examples:

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

String json = "{\"hello\":\"world\"}";
deserializeJson(doc, json);

Mode 2: zero-copy

ArduinoJson uses the “zero-copy” mode when you pass one of the following types to deserializeJson():

  1. char*
  2. char[]

In this mode, the JSON parser modifies the input in place. The following modifications are performed:

  1. '\0' are inserted at the end of each string
  2. Escaped special characters (like \n) are unescaped

Example:

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

After executing the line above, the input variable probably contains something like "hello\0world\0".

Calling deserializeJson() twice

Because the input buffer is altered, if you call deserializeJson() twice, the second call will return InvalidInput, as in the example below:

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

Switching to classic mode

Usually, the “zero-copy” mode is what you want because it reduces memory usage. However, if you need to switch back to the “classic” mode, you can cast the input pointer to const char*, like so:

char[] json = "{\"hello\":\"world\"}";
deserializeJson(doc, (const char*)json);  // cast to avoid "zero-copy" mode

See also

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