skip to Main Content

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


  1. if you pointing to the printed in console, it should look like this:

    import 'dart:convert';
    
    void main() {
      CounterModel modl = CounterModel(count: 3);
    
      print(modl.toJson());  // {count: 3}
      print("--------");
      print(jsonEncode(modl));  // {"count":3}
    }
    
    class CounterModel {
      int count;
    
      CounterModel({this.count = 0});
      Map<String, dynamic> toJson() => {"count": count};
    }
    

    result:

    enter image description here

    Login or Signup to reply.
  2. The confusion arises from the fact the a typical Dart toJson method returns a Map<String, dynamic> – just as in your example. This isn’t (yet) a string representation of JSON. However it is easily converted with:

    final stringLookingLikeJson = json.encode(map); // {"foo":1}
    

    Instead, if you toString the map, or call print which will implicitly toString it, you’ll see Dart’s default representation of a map contents e.g. {foo:1}. This is simply Map‘s implementation of toString – note – not meant to look like JSON.

    So, why doesn’t a typical toJson return a string in JSON format? Why the need to use json.encode() to encode it? This is to allow nesting of more complex objects. A top level object’s toJson might return a Map<String, dynamic> where some or all of the dynamics are other maps and lists created by nested calls to toJson. Only at the end is json.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:

      final stringToWrite = json.encode(counter.toJson());
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search