Search code examples
jsonflutterdartjsonserializerjson-serializable

Nested Json Serialization Doesn't Work Event With explicitToJson: TRUE?


I am new to flutter and have been developing a small api that would pull data from a local mock database I created. The database has a nested Json within it, and no matter what I did, I can't get it to output anything other than "instance of 'Class'" instead of the actual Json within it. The code gets data from a Json that has mock data on an gym exercise and the sets and reps done

Here is the first model:

import 'package:json_annotation/json_annotation.dart';
import 'package:workout_card_api/src/models/sets.dart';

part 'exercise.g.dart';

@JsonSerializable(explicitToJson: true)
class Exercise {
  Exercise({
    required this.exerciseId,
    required this.exerciseName,
    required this.exerciseType,
    required this.setList,
  });

  int exerciseId;
  String exerciseName;
  String exerciseType;
  List<Sets> setList;

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

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

Here is the second model:

import 'package:json_annotation/json_annotation.dart';

part 'sets.g.dart';

@JsonSerializable()
class Sets {
  Sets({required this.setId, required this.weightKg, required this.reps});

  int setId;
  int weightKg;
  int reps;

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

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

Here is the test code:

void main() {
  group('Sets', () {
    late Map<String, dynamic> json;

    setUp(() {
      json = {'setId': 1, 'weightKg': 30, 'reps': 15};
    });

    test('set object correct properties', () {
      final setData = Sets.fromJson(json);
      expect(setData.setId, 1);
      expect(setData.weightKg, 30);
      expect(setData.reps, 15);
    });
  });

  group('Exercise', () {
    late Map<String, dynamic> json;

    setUp(() {
      json = {
        'exerciseId': 2,
        'exerciseName': 'Bicep Curl',
        'exerciseType': 'Arms',
        'setList': [
          {'setId': 1, 'weightKg': 30, 'reps': 15},
          {'setId': 2, 'weightKg': 30, 'reps': 14},
          {'setId': 3, 'weightKg': 30, 'reps': 12}
        ]
      };
    });

    test('exercise object correct properties', () {
      final exerciseData = Exercise.fromJson(json);
      expect(exerciseData.exerciseId, 2);
      expect(exerciseData.exerciseName, 'Bicep Curl');
      expect(exerciseData.exerciseType, 'Arms');
      expect(exerciseData.setList, [
        {'setId': 1, 'weightKg': 30, 'reps': 15},
        {'setId': 2, 'weightKg': 30, 'reps': 14},
        {'setId': 3, 'weightKg': 30, 'reps': 12}
      ]);
    });
  });
}

The first part tests the sets model which works fine. The second part tests the exercise model which always outputs the following:

Expected: [
            {'setId': 1, 'weightKg': 30, 'reps': 15},
            {'setId': 2, 'weightKg': 30, 'reps': 14},
            {'setId': 3, 'weightKg': 30, 'reps': 12}
          ]
  Actual: [Instance of 'Sets', Instance of 'Sets', Instance of 'Sets']
   Which: at location [0] is <Instance of 'Sets'> which expected a map

I tried a lot of things like changing the type from Map<String, dynamic> to Map<String, Object> and creating a seperate build.yaml file. But no luck!


Solution

  • Error occurs because the expect function is comparing the setList of Exercise with a list of maps, but setList is actually a list of Sets objects.

    Here's a solution:

    One Way:

     test('exercise object correct properties', () {
          final exerciseData = Exercise.fromJson(json);
          expect(exerciseData.exerciseId, 2);
          expect(exerciseData.exerciseName, 'Bicep Curl');
          expect(exerciseData.exerciseType, 'Arms');
    
          expect(exerciseData.setList.length, 3);
    
          // Check the properties of each set
          expect(exerciseData.setList[0].setId, 1);
          expect(exerciseData.setList[0].weightKg, 30);
          expect(exerciseData.setList[0].reps, 15);
    
          expect(exerciseData.setList[1].setId, 2);
          expect(exerciseData.setList[1].weightKg, 30);
          expect(exerciseData.setList[1].reps, 14);
    
          expect(exerciseData.setList[2].setId, 3);
          expect(exerciseData.setList[2].weightKg, 30);
          expect(exerciseData.setList[2].reps, 12);
        });
    

    Another Way:

     test('exercise object correct properties', () {
          final exerciseData = Exercise.fromJson(json);
          expect(exerciseData.exerciseId, 2);
          expect(exerciseData.exerciseName, 'Bicep Curl');
          expect(exerciseData.exerciseType, 'Arms');
          expect(exerciseData.setList, [
            Sets(setId: 1, weightKg: 30, reps: 15),
            Sets(setId: 2, weightKg: 30, reps: 14),
            Sets(setId: 3, weightKg: 30, reps: 12),
          ]);
        });