0

I have worked on decoding/encoding JSONs in my Flutter/Dart app. The decoding works just fine, but I have a very nasty problem when encoding my objects to JSON.

These are nested objects. Every one of them has its toJson and fromJson methods, in order to ensure that jsonEncode and Decode works. A small snippet of my work:

class App {
  factory App.fromJson(Map<String, dynamic> json) => App(
        langPref: json["langPref"],
        langFallb: json["langFallb"],
        users: List.of(json["users"]).map((i) => i).toList(),
      );

  String langPref;
  String langFallb;
  List<User> users;

  /// JSON-Export
  Map<String, dynamic> toJson() => {
        "langPref": langPref,
        "langFallb": langFallb,
        "users": jsonEncode(users),
      };
}

and the nested class:

class User {
  int userid;
// actually there's more, including more nested objects


  /// JSON-Import
  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      userid: int.parse(json["userid"]),
    );
  }

  /// JSON-Export
  Map<String, dynamic> toJson() {
    return {
      "userid": this.userid,
    };
  }
}

The problem is: When I encode the top level class "App", it correctly calls the toJson() method of the nested class. However, the corresponding JSON should read like this:

{
    "langPref":"de-DE",
    "langFallb":"en-GB",
    "users":
        [
            {
                "userid": 1
// and so on

It does, however, look like this:

{
    "langPref":"de-DE",
    "langFallb":"en-GB",
    "users":"[{\"userid\":1
// and so on

So, the jsonEncode somehow introduces additional double quotes, which even makes sense somehow. It produces a String, and inside the JSON a string should be encoded .... But I guuess I'm just doing something wrong and missing something obvious .... How can I tell jsonEncode to accept the result of the operation, instead of encoding it as a string?

Can somebody help me?

2 Answers 2

1

This problem rises because you use jsonEncode() which return string object

you must use jsonDecode() that return a Map<String, dynamic> and your App class will be like following

class App {
  factory App.fromJson(Map<String, dynamic> json) => App(
        langPref: json["langPref"],
        langFallb: json["langFallb"],
        users: List.of(json["users"]).map((i) => i).toList(),
      );

  String langPref;
  String langFallb;
  List<User> users;

  /// JSON-Export
  Map<String, dynamic> toJson() => {
        "langPref": langPref,
        "langFallb": langFallb,
        "users": jsonEDecode(users),
      };
}

Update

2nd method is to remove jsonEncode() without use jsonDecode()

3rd method use tojson() method in user class like following code

"users": users.map((user) => user.tojson()).toList(),

4th method the best method use json_serializable library with json_annotation library to generate json serialization for annotated classes, Flutter team approve this method as the best and the official one as described in Official Flutter Documentation.

app.dart

import 'package:json_annotation/json_annotation.dart';

part 'app.g.dart';

@JsonSerializable()
class App{
  String langPref;
  String langFallb;
  List<User> users;
  
  App({this.langPref, this.langFallb, this.users});

  factory App.fromJson(Map<String, dynamic> json) => _$AppFromJson(json);

  Map<String, dynamic> toJson() => _$AppToJson(this);

}

user.dart

import 'package:json_annotation/json_annotation.dart';

part 'user.g.dart';

@JsonSerializable()
class User{
  int userId;
  
  User({this.userId});

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);

  Map<String, dynamic> toJson() => _$UserToJson(this);
}
Sign up to request clarification or add additional context in comments.

2 Comments

First of all thank you for the answer.... Hmmm, better jsonDecode, like you proposed, or just directly throw in the users? .... It works in my test case, but maybe your solution is safer?
I updated my answer with 3 other methods the best way for json serializing is the 4th method
0

Great .... I will answer my own question. :-)

Further experiments lead to the following conclusion:

class App {
  factory App.fromJson(Map<String, dynamic> json) => App(
        langPref: json["langPref"],
        langFallb: json["langFallb"],
        users: List.of(json["users"]).map((i) => i).toList(),
      );

  String langPref;
  String langFallb;
  List<User> users;

  /// JSON-Export
  Map<String, dynamic> toJson() => {
        "langPref": langPref,
        "langFallb": langFallb,
        "users": users,
      };
}

New is only the last line .... I can directly pass the users list. It's not necessary to use jsonEncode for all of the nested objects and lists and maps etc.

Sorry for stealing the time of the readers, but maybe this answer will help others.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.