Flutter处理GraphQL响应时嵌套数据类空值转换异常求助
解决GraphQL响应中嵌套类字段为Null时的类型转换异常
问题概述
处理GraphQL响应的User数据类时,当LegalGuardian、Birthdate等嵌套类字段为null时,抛出以下异常:
[VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: type 'Null' is not a subtype of type 'Map<String, dynamic>'
问题根源
手动实现的fromJson方法中,直接调用嵌套类的fromJson方法但未做null判断:
- User类的
fromJson里,birthdate: Birthdate.fromJson(data['birthdate'])这类代码,若data['birthdate']为null,会将null传入要求Map<String, dynamic>类型的Birthdate.fromJson,触发类型转换异常。 - LegalGuardian类的
birthdate处理中,json.decode(data['birthdate'])未判断null,若data['birthdate']为null,json.decode(null)会引发错误;同时若GraphQL返回的birthdate本身是Map而非JSON字符串,json.decode属于多余操作。
解决方案
方案1:手动修复fromJson方法,添加Null判断
修改User类的fromJson方法,对嵌套字段添加null校验:
factory User.fromJson(Map<String, dynamic> data) { return User( sub: data['sub'], email: data['email'], username: data['username'], roles: data['roles'], name: data['name'], firstName: data['firstName'], lastName: data['lastName'], newsletterSubscription: data['newsletterSubscription'], avatarUrl: data['avatarUrl'], backgroundUrl: data['backgroundUrl'], emailVerified: data['emailVerified'], // 添加null判断,仅当字段不为null时调用fromJson birthdate: data['birthdate'] != null ? Birthdate.fromJson(data['birthdate'] as Map<String, dynamic>) : null, address: data['address'] != null ? Address.fromJson(data['address'] as Map<String, dynamic>) : null, legalGuardian: data['legalGuardian'] != null ? LegalGuardian.fromJson(data['legalGuardian'] as Map<String, dynamic>) : null, externalSource: data['externalSource'], ); }
修改LegalGuardian类的fromJson方法,修复birthdate的null处理:
factory LegalGuardian.fromJson(Map<String, dynamic> data) { return LegalGuardian( email: data['email'], firstName: data['firstName'], lastName: data['lastName'], phone: data['phone'], // 若birthdate是JSON字符串,先判断null再解码;若为Map则直接传入 birthdate: data['birthdate'] != null ? Birthdate.fromJson(json.decode(data['birthdate']) as Map<String, dynamic>) : null, // 若GraphQL返回的birthdate是Map类型,替换为下面这行: // birthdate: data['birthdate'] != null ? Birthdate.fromJson(data['birthdate'] as Map<String, dynamic>) : null, consent: data['consent'], ); }
方案2:使用json_annotation自动生成序列化代码(推荐)
手动编写fromJson和toJson容易出错,推荐依赖json_annotation自动生成代码,自动处理null场景:
- 简化User类代码,保留注解和构造函数,删除手动实现的
fromJson和toJson:
import 'package:json_annotation/json_annotation.dart'; import '/src/dataclasses/user_address.dart'; import '/src/dataclasses/user_birthdate.dart'; import '/src/dataclasses/user_legal_guardian.dart'; part 'user.g.dart'; @JsonSerializable() class User { String? sub; String? email; String? username; List<dynamic>? roles; String? name; String? firstName; String? lastName; bool? newsletterSubscription; String? avatarUrl; String? backgroundUrl; bool? emailVerified; Birthdate? birthdate; Address? address; LegalGuardian? legalGuardian; String? externalSource; User({ this.email, this.username, this.roles, this.name, this.firstName, this.lastName, this.newsletterSubscription, this.avatarUrl, this.backgroundUrl, this.emailVerified, this.sub, this.birthdate, this.address, this.legalGuardian, this.externalSource, }); // 自动生成的fromJson和toJson factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json); Map<String, dynamic> toJson() => _$UserToJson(this); }
- 简化LegalGuardian类代码:
import 'dart:convert'; import 'package:json_annotation/json_annotation.dart'; import '/src/dataclasses/user_birthdate.dart'; part 'user_legal_guardian.g.dart'; @JsonSerializable() class LegalGuardian { String? email; String? firstName; String? lastName; String? phone; Birthdate? birthdate; bool? consent; LegalGuardian({ this.email, this.firstName, this.lastName, this.phone, this.birthdate, this.consent, }); LegalGuardian.empty(); // 自动生成的fromJson和toJson factory LegalGuardian.fromJson(Map<String, dynamic> json) => _$LegalGuardianFromJson(json); Map<String, dynamic> toJson() => _$LegalGuardianToJson(this); }
- 运行命令自动生成序列化代码:
flutter pub run build_runner build
自动生成的代码会自动处理嵌套字段的null情况,当字段为null时不会调用对应类的fromJson,直接赋值为null,彻底避免类型转换异常。
内容的提问来源于stack exchange,提问作者Ala Ha
相关产品推荐
相关产品推荐

