You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter嵌套JSON序列化失效?已设置explicitToJson: true仍无效

Flutter嵌套JSON解析测试失败问题解决

我是Flutter新手,正在开发一个从本地模拟数据库拉取嵌套JSON结构数据的小型API。不管怎么操作,都无法输出实际JSON数据,得到的总是“Instance of 'Class'”。以下是相关代码和测试报错情况:

模型代码

Exercise模型

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);
}

Sets模型

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);
}

测试代码

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}
      ]);
    });
  });
}

测试错误信息

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

我试过把类型从Map<String, dynamic>改成Map<String, Object>,也创建过单独的build.yaml文件,但都没解决问题!


解决方案

问题根源

测试用例里你期望setList是Map数组,但Exercise.fromJson解析后,setList实际是Sets对象数组,类型不匹配导致测试失败。而直接打印对象显示“Instance of 'Sets'”,是因为Dart默认的对象toString()方法只会输出类实例标识。

具体解决步骤

  1. 修正测试断言逻辑
    不要直接对比对象数组和Map数组,而是验证每个Sets对象的属性,或者把对象转成Map后再对比:

    • 方式一:逐个验证属性
      test('exercise object correct properties', () {
        final exerciseData = Exercise.fromJson(json);
        expect(exerciseData.exerciseId, 2);
        expect(exerciseData.exerciseName, 'Bicep Curl');
        expect(exerciseData.exerciseType, 'Arms');
        
        // 验证setList的长度和每个对象的属性
        expect(exerciseData.setList.length, 3);
        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);
      });
      
    • 方式二:将对象转成Map数组后对比
      test('exercise object correct properties', () {
        final exerciseData = Exercise.fromJson(json);
        expect(exerciseData.exerciseId, 2);
        expect(exerciseData.exerciseName, 'Bicep Curl');
        expect(exerciseData.exerciseType, 'Arms');
        
        // 调用toJson()把每个Sets对象转成Map,再对比
        expect(
          exerciseData.setList.map((set) => set.toJson()).toList(),
          [
            {'setId': 1, 'weightKg': 30, 'reps': 15},
            {'setId': 2, 'weightKg': 30, 'reps': 14},
            {'setId': 3, 'weightKg': 30, 'reps': 12}
          ]
        );
      });
      
  2. 解决对象打印显示“Instance of 'Class'”的问题

    • 重写类的toString()方法,自定义输出格式:
      // 在Sets类中添加
      @override
      String toString() {
        return 'Sets(setId: $setId, weightKg: $weightKg, reps: $reps)';
      }
      
      // 在Exercise类中添加
      @override
      String toString() {
        return 'Exercise(exerciseId: $exerciseId, exerciseName: $exerciseName, exerciseType: $exerciseType, setList: $setList)';
      }
      
    • 或者直接输出JSON格式字符串:
      import 'dart:convert';
      
      // 打印Exercise对象的JSON字符串
      print(jsonEncode(exerciseData.toJson()));
      
  3. 确保代码生成正确
    重新运行代码生成命令,确保嵌套JSON解析的.g.dart文件正确生成:

    flutter pub run build_runner build
    

内容的提问来源于stack exchange,提问作者Nova From OUTER SPACE

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 04:42:05