Updated FAQ (markdown)

Benoît Blanchon
2016-04-21 10:37:41 +02:00
parent d54b725e3b
commit 3c63318e77

570
FAQ.md

@@ -1,7 +1,342 @@
### Table of content:
* [Part 1 - Common questions](#part-1---common-questions)
* [Compilation fails? Device crashes? Nothing on serial console?](#compilation-fails-device-crashes-nothing-on-serial-console)
* [Why does my device crash or reboot?](#why-does-my-device-crash-or-reboot)
* [What are the differences between `StaticJsonBuffer` and `DynamicJsonBuffer`?](#what-are-the-differences-between-staticjsonbuffer-and-dynamicjsonbuffer)
* [How to determine the buffer size?](#how-to-determine-the-buffer-size)
* [I found a memory leak in the library!](#i-found-a-memory-leak-in-the-library)
* [How to reuse a `JsonBuffer`?](#how-to-reuse-a-jsonbuffer)
* [What's the best way to use the library?](#whats-the-best-way-to-use-the-library)
* [How to write a function that works with both `JsonArray` and `JsonObject`?](#how-to-write-a-function-that-works-with-both-jsonarray-and-jsonobject)
* [Part 2 - Serialization questions](#part-2---serialization-questions)
* [How do I create complex nested objects?](#how-do-i-create-complex-nested-objects)
* [The first serialization succeeds, why do the next ones fail?](#the-first-serialization-succeeds-why-do-the-next-ones-fail)
* [Part 3 - Deserialization questions](#part-3---deserializationparsing-questions)
* [Can I parse data from a stream?](#can-i-parse-data-from-a-stream)
* [Should I call `parseArray()` or `parseObject()`?](#should-i-call-parsearray-or-parseobject)
* [Why parsing fails?](#why-parsing-fails)
* [The first parsing succeeds, why do the next ones fail?](#the-first-parsing-succeeds-why-do-the-next-ones-fail)
* [Parsing succeeds but I can't read the values!](#parsing-succeeds-but-i-cant-read-the-values)
* [How to know the type of a value?](#how-to-know-the-type-of-a-value)
* [How to fix error "Ambiguous overload for 'operator='"](#how-to-fix-error-ambiguous-overload-for-operator)
## Part 1 - Common questions
### Compilation fails? Device crashes? Nothing on serial console?
See [Compatibility issues](Compatibility issues) first.
### Why does my device crash or reboot?
99.999% of the time, this is caused by a "stack overflow", i.e. you have too many variables in the "stack".
The solution is to move variables to the "heap".
First, replace the `StaticJsonBuffer` by a `DynamicJsonBuffer`.
Then, use dynamic allocation for the JSON input.
For instance, if you have a program like this:
```c++
char content[MAX_CONTENT_SIZE];
StaticJsonBuffer<JSON_BUFFER_SIZE> jsonBuffer;
receive(content);
JsonObject& root = jsonBuffer.parseObject(content);
Serial.println(root["name"].asString());
```
you should transform it like that:
```c++
char* content = malloc(MAX_CONTENT_SIZE);
DynamicJsonBuffer jsonBuffer(JSON_BUFFER_SIZE);
receive(content);
JsonObject& root = jsonBuffer.parseObject(content);
Serial.println(root["name"].asString());
free(content);
```
Of course, this is only possible if your target has enough memory.
Sometimes, it's just impossible because the MCU is too small.
See issues [#233](https://github.com/bblanchon/ArduinoJson/issues/233), [#234](https://github.com/bblanchon/ArduinoJson/issues/234) and [#262](https://github.com/bblanchon/ArduinoJson/issues/262)
### What are the differences between `StaticJsonBuffer` and `DynamicJsonBuffer`?
| `StaticJsonBuffer` | `DynamicJsonBuffer`
---------------- | ------------------- | -------------------
Size | fixed | variable :+1:
Location | stack<sup>(1)</sup> | heap
Memory overhead | small :+1: | big
Code size | small :+1: | big
Speed | fast :+1: | slow<sup>(4)</sup>
Cleanup | automatic<sup>(2)</sup> | automatic
Reusable | no<sup>(3)</sup> | no<sup>(3)</sup>
<sup>(1)</sup> preferably, but if you need you could allocate it in the heap with `new StaticJsonBuffer<200>()` <br>&nbsp;&nbsp;&nbsp;This can be useful on platforms where stack size is limited.
<sup>(2)</sup> if allocated on the stack, see <sup>(1)</sup>
<sup>(3)</sup> there is a workaround (see issues [#72](https://github.com/bblanchon/ArduinoJson/issues/72) and [#115](https://github.com/bblanchon/ArduinoJson/issues/115)) for those who are looking for troubles.
<sup>(4)</sup> A `DynamicJsonBuffer` calls `malloc()` to allocate its memory, and it may have to do this several times if it needs to grow. However, you can specify an initial size to the constructor, so as to make sure that the buffer is big enough and that no further allocation will be needed.
As a general rule, if your `StaticJsonBuffer` is bigger than 2K, then it may be a good time to switch to a `DynamicJsonBuffer`.
### How to determine the buffer size?
There are basically tree approaches here:
1. either you can predict the content of the object tree,
2. you know how much memory is available.
3. you try and look at current size
In the first case, you know some constraints on the object tree. For instance, let's say that you know in advance (and by that I mean "at compilation time") that you want to generate an object with 3 values, one of them being an array with 2 values, like the following:
{"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
To determine the memory usage of this object tree, you use the two macros `JSON_ARRAY_SIZE(n)` and `JSON_OBJECT_SIZE(n)`, both take the number of elements as an argument.
For the example above, it would be:
const int BUFFER_SIZE = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2);
StaticJsonBuffer<BUFFER_SIZE> jsonBuffer;
In the second case, let's say you dynamically generate a JSON object tree of a random complexity so you can't put a limit based on that. But on the other hand, you don't want your program to crash because the object tree doesn't fit in memory.
The solution here is to determine how much memory is available, or in other words how much memory you can afford for the JSON object tree.
The third solution is to run your program an print `jsonBuffer.size()` to get the current size of the buffer.
**WARNING**: if you use `String` to create your JSON keys or values, there content will automatically be duplicated in the `JsonBuffer`, so you need to add the total length of all strings in the size of the `JsonBuffer`.
See issue [#243](https://github.com/bblanchon/ArduinoJson/issues/243)
### I found a memory leak in the library!
This is very unlikely. You're probably using the library incorrectly.
The typical problem comes from reusing a `JsonBuffer` several time.
Each time you call `parseArray()`, `parseObject()`, `createArray()` and `createObject()`, you consume memory in the `JsonBuffer`.
To avoid running out of memory, you should discard unused data as soon as possible.
The recommended practice is to do the JSON handling in a dedicated function, with a local `JsonBuffer` that will be automatically reclaimed when the function exits.
This means that you cannot return a `JsonArray` or a `JsonObject` from that function, because they would contains dangling pointers to what used to be the `JsonBuffer`.
Instead, you should convert the content of the `JsonArray` to a custom array or `vector`; or the content of the `JsonObject` to your own data structure.
This seems like a constrain, but remember that you're programming for an embedded platform with very limited resources; and that requires special techniques.
A positive side effect of following this recommandation is that the code is safe and memory efficient. It also encourage the separation of responsibilities: the function is only in charge of the JSON serialization an no specific JSON data leaks elsewhere is the program.
See issues [#72](https://github.com/bblanchon/ArduinoJson/issues/72), [#87](https://github.com/bblanchon/ArduinoJson/issues/87), [#115](https://github.com/bblanchon/ArduinoJson/issues/115), [#135](https://github.com/bblanchon/ArduinoJson/issues/135)
See [ArduinoJson: Avoiding pitfalls](https://github.com/bblanchon/ArduinoJson/wiki/Avoiding%20pitfalls)
### How to reuse a `JsonBuffer`?
`StaticJsonBuffer` and `DynamicJsonBuffer` are designed to be throwaway memory pools, they are not intended to be reused.
If you beleive you need to reuse a `JsonBuffer`, it's because [you're not using the library correctly](https://github.com/bblanchon/ArduinoJson/wiki/FAQ#whats-the-best-way-to-use-the-library).
##### 1. There is a reason behind this.
Imagine a `clear()` function is available, someone could write:
```c++
JsonObject& myObject = jsonBuffer.createObject();
jsonBuffer.clear();
JsonArray& myArray = jsonBuffer.createArray();
```
And in this case `myObject` and `myArray` would point to the exact same location.
Therefore, any modification of one would corrupt the other.
That's why `StaticJsonBuffer` and `DynamicJsonBuffer` have been design to force you to use them in a scope.
If you believe you need a `clear()` function, then you're not using the library properly.
##### 2. Allocating a `StaticJsonBuffer` is not expensive
Destructing an constructing a new `StaticJsonBuffer` is not expensive, it's exactly the same cost as the `clear()` function above.
##### 3. A workaround
You can find a very simple workaround in the [Bag of tricks](https://github.com/bblanchon/ArduinoJson/wiki/Bag-of-Tricks#reuse-jsonbuffer).
This will never be a part of the library.
See issues [#72](https://github.com/bblanchon/ArduinoJson/issues/72), [#115](https://github.com/bblanchon/ArduinoJson/issues/115), [#141](https://github.com/bblanchon/ArduinoJson/issues/141) and [#242](https://github.com/bblanchon/ArduinoJson/issues/242)
See [ArduinoJson: Avoiding pitfalls](https://github.com/bblanchon/ArduinoJson/wiki/Avoiding-pitfalls#4-dont-reuse-the-same-jsonbuffer)
### What's the best way to use the library?
Here is the canonical example for serializing and deserializing with ArduinoJson.
By following this example, you are making the best usage of your memory and you maintain a good software design.
```c++
struct SensorData {
const char* name;
int time;
float value;
};
#define SENSORDATA_JSON_SIZE (JSON_OBJECT_SIZE(3))
bool deserialize(SensorData& data, char* json)
{
StaticJsonBuffer<SENSORDATA_JSON_SIZE> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(json);
data.name = root["name"];
data.time = root["time"];
data.value = root["value"];
return root.success();
}
void serialize(const SensorData& data, char* json, size_t maxSize)
{
StaticJsonBuffer<SENSORDATA_JSON_SIZE> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["name"] = data.name;
root["time"] = data.time;
root["value"] = data.value;
root.printTo(json, maxSize);
}
```
As you can see the `StaticJsonBuffer` is kept in memory as short as possible, so that the remain of your program is unaffected by the JSON serialization.
Also you can see that neither `JsonArray` nor `JsonObject` leak out of the serialization code. This maintain a good isolation and reduce the coupling with the library.
### How to write a function that works with both `JsonArray` and `JsonObject`?
There is no base class for `JsonArray` and `JsonObject`.
(Back in version 3.0, they used to derive from `Printable`, but this inheritance has been removed to reduce the memory footprint.)
However, both `JsonArray` and `JsonObject` can be "stored" in a `JsonVariant`. (I put "stored" in quotes because the `JsonVariant` only contains a reference, not a copy.)
So here is your function:
```c++
void sendJson(JsonVariant json) {
char buffer[512];
json.printTo(buffer, sizeof(buffer));
g_server.send(200, "application/json", buffer);
}
```
But in that case, you loose some specificities of the `JsonObject` class.
In particular, you don't have the `containsKey()` method.
If you need this function, you must cast the `JsonVariant` back to a `JsonObject&`.
For instance:
```c++
void myFunction(JsonVariant variant)
{
if (variant.is<JsonArray&>())
{
JsonArray& array = variant;
// ...
}
else if (variant.is<JsonObject&>())
{
JsonObject& object = variant;
// ...
}
else
{
// ...
}
}
```
See issue [#195](https://github.com/bblanchon/ArduinoJson/issues/195) and [#196](https://github.com/bblanchon/ArduinoJson/issues/196)
## Part 2 - Serialization questions
### How do I create complex nested objects?
To create a nested object, call `createNestedObject()`.
To create a nested array, call `createNestedArray()`.
For example:
```c++
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
JsonObject& weather = root.createNestedObject("weather");
weather["temperature"] = 12;
weather["condition"] = "cloudy";
JsonArray& coords = root.createNestedArray("coords");
coords.add(48.7507371, 7);
coords.add(2.2625587, 7);
root.prettyPrintTo(Serial);
```
will generate:
```json
{
"weather": {
"temperature": 12,
"condition": "cloudy"
},
"coords": [
48.7507371,
2.2625587
]
}
```
### The first serialization succeeds, why do the next ones fail?
This is usually caused by a reused `JsonBuffer`.
The solution is simply to NOT reuse the `JsonBuffer`.
See [The first parsing succeeds, why do the next ones fail?](#the-first-parsing-succeeds-why-do-the-next-ones-fail)
## Part 3 - Deserialization/parsing questions
### Can I parse data from a stream?
No.
@@ -33,6 +368,8 @@ If this is not acceptable, you should have a look at other libraries, like [aJso
See issues [#60](https://github.com/bblanchon/ArduinoJson/issues/60), [#119](https://github.com/bblanchon/ArduinoJson/issues/119), [#194](https://github.com/bblanchon/ArduinoJson/issues/194), [#200](https://github.com/bblanchon/ArduinoJson/issues/200) and [#223](https://github.com/bblanchon/ArduinoJson/issues/223).
### Should I call `parseArray()` or `parseObject()`?
This is a very common question as people are often confused when the JSON input contains mixed arrays and objects.
@@ -58,6 +395,8 @@ then you must call `parseArray()` because the root is an array.
Finally, if you cannot know in advance the type of the root, please open an issue. Don't worry this can be implemented very easily, it's just that nobody asked for it.
### Why parsing fails?
The parsing functions, `parseArray()` and `parseObject()`, may fail for 3 reasons:
@@ -99,9 +438,9 @@ To avoid any duplication, make sure you use an input of type `char*` or `char[]`
See issues [#154](https://github.com/bblanchon/ArduinoJson/issues/154), [#177](https://github.com/bblanchon/ArduinoJson/issues/177), [#179](https://github.com/bblanchon/ArduinoJson/issues/179) and [#223](https://github.com/bblanchon/ArduinoJson/issues/223).
### The first parsing succeeds, why do the next ones fail?
or
### The first serialization succeeds, why do the next ones fail?
This can be due to two causes.
@@ -196,44 +535,7 @@ for (int i=0; i<10; i++) {
See issue [#153](https://github.com/bblanchon/ArduinoJson/issues/153) and [#160](https://github.com/bblanchon/ArduinoJson/issues/160).
### Why does my device crash or reboot?
99.999% of the time, this is caused by a "stack overflow", i.e. you have too many variables in the "stack".
The solution is to move variables to the "heap".
First, replace the `StaticJsonBuffer` by a `DynamicJsonBuffer`.
Then, use dynamic allocation for the JSON input.
For instance, if you have a program like this:
```c++
char content[MAX_CONTENT_SIZE];
StaticJsonBuffer<JSON_BUFFER_SIZE> jsonBuffer;
receive(content);
JsonObject& root = jsonBuffer.parseObject(content);
Serial.println(root["name"].asString());
```
you should transform it like that:
```c++
char* content = malloc(MAX_CONTENT_SIZE);
DynamicJsonBuffer jsonBuffer(JSON_BUFFER_SIZE);
receive(content);
JsonObject& root = jsonBuffer.parseObject(content);
Serial.println(root["name"].asString());
free(content);
```
Of course, this is only possible if your target has enough memory.
Sometimes, it's just impossible because the MCU is too small.
See issues [#233](https://github.com/bblanchon/ArduinoJson/issues/233), [#234](https://github.com/bblanchon/ArduinoJson/issues/234) and [#262](https://github.com/bblanchon/ArduinoJson/issues/262)
### Parsing succeeds but I can't read the values!
@@ -303,6 +605,8 @@ const char* world = root["hello"][0]["new"];
See issues [#187](https://github.com/bblanchon/ArduinoJson/issues/187), [#203](https://github.com/bblanchon/ArduinoJson/issues/203) and [#245](https://github.com/bblanchon/ArduinoJson/issues/245).
### How to know the type of a value?
`JsonVariant`, which is the type that hold the values in `JsonArray` and `JsonObject`, provides the method `is<T>()` that returns `true` if the value is of type `T`.
@@ -323,195 +627,7 @@ array[0].is<JsonObject&>(); // return false
See issues [#148](https://github.com/bblanchon/ArduinoJson/issues/148), [#175](https://github.com/bblanchon/ArduinoJson/issues/175) and [#213](https://github.com/bblanchon/ArduinoJson/issues/213).
### How to write a function that works with both `JsonArray` and `JsonObject`?
There is no base class for `JsonArray` and `JsonObject`.
(Back in version 3.0, they used to derive from `Printable`, but this inheritance has been removed to reduce the memory footprint.)
However, both `JsonArray` and `JsonObject` can be "stored" in a `JsonVariant`. (I put "stored" in quotes because the `JsonVariant` only contains a reference, not a copy.)
So here is your function:
```c++
void sendJson(JsonVariant json) {
char buffer[512];
json.printTo(buffer, sizeof(buffer));
g_server.send(200, "application/json", buffer);
}
```
But in that case, you loose some specificities of the `JsonObject` class.
In particular, you don't have the `containsKey()` method.
If you need this function, you must cast the `JsonVariant` back to a `JsonObject&`.
For instance:
```c++
void myFunction(JsonVariant variant)
{
if (variant.is<JsonArray&>())
{
JsonArray& array = variant;
// ...
}
else if (variant.is<JsonObject&>())
{
JsonObject& object = variant;
// ...
}
else
{
// ...
}
}
```
See issue [#195](https://github.com/bblanchon/ArduinoJson/issues/195) and [#196](https://github.com/bblanchon/ArduinoJson/issues/196)
### What are the differences between `StaticJsonBuffer` and `DynamicJsonBuffer`?
| `StaticJsonBuffer` | `DynamicJsonBuffer`
---------------- | ------------------- | -------------------
Size | fixed | variable :+1:
Location | stack<sup>(1)</sup> | heap
Memory overhead | small :+1: | big
Code size | small :+1: | big
Speed | fast :+1: | slow<sup>(4)</sup>
Cleanup | automatic<sup>(2)</sup> | automatic
Reusable | no<sup>(3)</sup> | no<sup>(3)</sup>
<sup>(1)</sup> preferably, but if you need you could allocate it in the heap with `new StaticJsonBuffer<200>()` <br>&nbsp;&nbsp;&nbsp;This can be useful on platforms where stack size is limited.
<sup>(2)</sup> if allocated on the stack, see <sup>(1)</sup>
<sup>(3)</sup> there is a workaround (see issues [#72](https://github.com/bblanchon/ArduinoJson/issues/72) and [#115](https://github.com/bblanchon/ArduinoJson/issues/115)) for those who are looking for troubles.
<sup>(4)</sup> A `DynamicJsonBuffer` calls `malloc()` to allocate its memory, and it may have to do this several times if it needs to grow. However, you can specify an initial size to the constructor, so as to make sure that the buffer is big enough and that no further allocation will be needed.
As a general rule, if your `StaticJsonBuffer` is bigger than 2K, then it may be a good time to switch to a `DynamicJsonBuffer`.
### How to determine the buffer size?
There are basically tree approaches here:
1. either you can predict the content of the object tree,
2. you know how much memory is available.
3. you try and look at current size
In the first case, you know some constraints on the object tree. For instance, let's say that you know in advance (and by that I mean "at compilation time") that you want to generate an object with 3 values, one of them being an array with 2 values, like the following:
{"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
To determine the memory usage of this object tree, you use the two macros `JSON_ARRAY_SIZE(n)` and `JSON_OBJECT_SIZE(n)`, both take the number of elements as an argument.
For the example above, it would be:
const int BUFFER_SIZE = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2);
StaticJsonBuffer<BUFFER_SIZE> jsonBuffer;
In the second case, let's say you dynamically generate a JSON object tree of a random complexity so you can't put a limit based on that. But on the other hand, you don't want your program to crash because the object tree doesn't fit in memory.
The solution here is to determine how much memory is available, or in other words how much memory you can afford for the JSON object tree.
The third solution is to run your program an print `jsonBuffer.size()` to get the current size of the buffer.
**WARNING**: if you use `String` to create your JSON keys or values, there content will automatically be duplicated in the `JsonBuffer`, so you need to add the total length of all strings in the size of the `JsonBuffer`.
See issue [#243](https://github.com/bblanchon/ArduinoJson/issues/243)
### I found a memory leak in the library!
This is very unlikely. You're probably using the library incorrectly.
The typical problem comes from reusing a `JsonBuffer` several time.
Each time you call `parseArray()`, `parseObject()`, `createArray()` and `createObject()`, you consume memory in the `JsonBuffer`.
To avoid running out of memory, you should discard unused data as soon as possible.
The recommended practice is to do the JSON handling in a dedicated function, with a local `JsonBuffer` that will be automatically reclaimed when the function exits.
This means that you cannot return a `JsonArray` or a `JsonObject` from that function, because they would contains dangling pointers to what used to be the `JsonBuffer`.
Instead, you should convert the content of the `JsonArray` to a custom array or `vector`; or the content of the `JsonObject` to your own data structure.
This seems like a constrain, but remember that you're programming for an embedded platform with very limited resources; and that requires special techniques.
A positive side effect of following this recommandation is that the code is safe and memory efficient. It also encourage the separation of responsibilities: the function is only in charge of the JSON serialization an no specific JSON data leaks elsewhere is the program.
See issues [#72](https://github.com/bblanchon/ArduinoJson/issues/72), [#87](https://github.com/bblanchon/ArduinoJson/issues/87), [#115](https://github.com/bblanchon/ArduinoJson/issues/115), [#135](https://github.com/bblanchon/ArduinoJson/issues/135)
See [ArduinoJson: Avoiding pitfalls](https://github.com/bblanchon/ArduinoJson/wiki/Avoiding%20pitfalls)
### How to reuse a `JsonBuffer`?
`StaticJsonBuffer` and `DynamicJsonBuffer` are designed to be throwaway memory pools, they are not intended to be reused.
If you beleive you need to reuse a `JsonBuffer`, it's because [you're not using the library correctly](https://github.com/bblanchon/ArduinoJson/wiki/FAQ#whats-the-best-way-to-use-the-library).
##### 1. There is a reason behind this.
Imagine a `clear()` function is available, someone could write:
```c++
JsonObject& myObject = jsonBuffer.createObject();
jsonBuffer.clear();
JsonArray& myArray = jsonBuffer.createArray();
```
And in this case `myObject` and `myArray` would point to the exact same location.
Therefore, any modification of one would corrupt the other.
That's why `StaticJsonBuffer` and `DynamicJsonBuffer` have been design to force you to use them in a scope.
If you believe you need a `clear()` function, then you're not using the library properly.
##### 2. Allocating a `StaticJsonBuffer` is not expensive
Destructing an constructing a new `StaticJsonBuffer` is not expensive, it's exactly the same cost as the `clear()` function above.
##### 3. A workaround
You can find a very simple workaround in the [Bag of tricks](https://github.com/bblanchon/ArduinoJson/wiki/Bag-of-Tricks#reuse-jsonbuffer).
This will never be a part of the library.
See issues [#72](https://github.com/bblanchon/ArduinoJson/issues/72), [#115](https://github.com/bblanchon/ArduinoJson/issues/115), [#141](https://github.com/bblanchon/ArduinoJson/issues/141) and [#242](https://github.com/bblanchon/ArduinoJson/issues/242)
See [ArduinoJson: Avoiding pitfalls](https://github.com/bblanchon/ArduinoJson/wiki/Avoiding-pitfalls#4-dont-reuse-the-same-jsonbuffer)
### What's the best way to use the library?
Here is the canonical example for serializing and deserializing with ArduinoJson.
By following this example, you are making the best usage of your memory and you maintain a good software design.
```c++
struct SensorData {
const char* name;
int time;
float value;
};
#define SENSORDATA_JSON_SIZE (JSON_OBJECT_SIZE(3))
bool deserialize(SensorData& data, char* json)
{
StaticJsonBuffer<SENSORDATA_JSON_SIZE> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(json);
data.name = root["name"];
data.time = root["time"];
data.value = root["value"];
return root.success();
}
void serialize(const SensorData& data, char* json, size_t maxSize)
{
StaticJsonBuffer<SENSORDATA_JSON_SIZE> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["name"] = data.name;
root["time"] = data.time;
root["value"] = data.value;
root.printTo(json, maxSize);
}
```
As you can see the `StaticJsonBuffer` is kept in memory as short as possible, so that the remain of your program is unaffected by the JSON serialization.
Also you can see that neither `JsonArray` nor `JsonObject` leak out of the serialization code. This maintain a good isolation and reduce the coupling with the library.
### How to fix error "Ambiguous overload for 'operator='"