Let’s first establish a detail. In the following code
import 'dart:convert' as JSON;
void main() {
var jsonStr = """{"count": 3}""";
final json = JSON.jsonDecode(jsonStr);
print(json['count']); // 3
}
the string to be parsed is {"count": 3}
and not {count: 3}
(with quotes around count
).
Now suppose when
persisting
by
writing and then reading,
we do not persist just the counter string on disk (as in the example at this last URL).
Suppose we persist in a JSON file instead.
When writeJson()
below runs, it saves {count: 3}
(and not {"count": 3}
).
Hence it’s no surprise that a subsequent loading in
final json = JSON.jsonDecode(jsonString);
fails—as we saw in the code above.
@JsonSerializable(explicitToJson: true)
class CounterModel {
int count = 0;
...
factory CounterModel.fromJson(Map<String, dynamic> json) => _$CounterModelFromJson(json);
Map<String, dynamic> toJson() => _$CounterModelToJson(this);
}
class CounterStorage {
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile async {
final path = await _localPath;
return File('$path/counter.json');
}
Future<CounterModel> readJson() async {
try {
final file = await _localFile;
final jsonStr = await file.readAsString();
final json = JSON.jsonDecode(jsonStr);
final counter = CounterModel.fromJson(json);
return counter;
} catch (e) {
return CounterModel(0);
}
}
Future<File> writeJson(CounterModel counter) async {
final file = await _localFile;
final stringToWrite = counter.toJson().toString();
return file.writeAsString(stringToWrite);
}
}
Should (or shouldn’t) the values in Flutter JSON files be quoted?
Generated Code
For reference, the generated code follows.
CounterModel _$CounterModelFromJson(Map<String, dynamic> json) => CounterModel(
json['count'] as int,
);
Map<String, dynamic> _$CounterModelToJson(CounterModel instance) =>
<String, dynamic>{
'count': instance.count,
};
2
Answers
if you pointing to the printed in console, it should look like this:
result:
The confusion arises from the fact the a typical Dart
toJson
method returns aMap<String, dynamic>
– just as in your example. This isn’t (yet) a string representation of JSON. However it is easily converted with:Instead, if you
toString
the map, or callprint
which will implicitly toString it, you’ll see Dart’s default representation of a map contents e.g.{foo:1}
. This is simplyMap
‘s implementation oftoString
– note – not meant to look like JSON.So, why doesn’t a typical
toJson
return a string in JSON format? Why the need to usejson.encode()
to encode it? This is to allow nesting of more complex objects. A top level object’stoJson
might return aMap<String, dynamic>
where some or all of thedynamic
s are other maps and lists created by nested calls totoJson
. Only at the end isjson.encode()
called on the top of that tree to convert it all, in one go, to a single JSON string.So
toJson
is meant to return either a map (which will be encoded to a JSON object – inside{}
) or a list (which will be encoded to a JSON array – inside[]
) or even just a JSON primitive (string, number, bool). These can then be nested inside each other. The encoder does the conversion to JSON – adding the quotes, braces and brackets.In conclusion you should change your code to: