Dart:无需JSON往返转换生成oauth2.Credentials列表
Dart OAuth2 Credentials.fromJson 冗余JSON往返问题解决
问题场景
实现基于JSON文件的多凭证存储时,直接使用已解析的JSON Map调用Credentials.fromJson()会触发类型错误,必须先将Map重新编码为JSON字符串再传入才能正常运行,这种方式冗余且不够优雅。
原始代码
import 'dart:convert'; import 'dart:io'; import 'package:oauth2/oauth2.dart'; class CredentialStore { List<Credentials> get credentials { // credentials.json 存储通过 oauth2.Credentials.toJson() 生成的对象数组 final file = File('credentials.json'); final jsonString = file.readAsStringSync(); final List cred = jsonDecode(jsonString); return List<Credentials>.from(cred.map((e) => Credentials.fromJson(e))); } }
运行时错误
Unhandled exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String'
临时冗余解决方案
将已解析的Map重新编码为JSON字符串后传入,代码可正常运行:
return List<Credentials>.from(cred.map((e) => Credentials.fromJson(jsonEncode(e))));
原因分析与优化方案
原因
Credentials.fromJson()的参数设计确实只接受JSON字符串,而非已解析的Map对象。该方法内部会自行执行JSON解码操作,直接传入Map会导致类型不匹配错误。
优化方案
如果想避免冗余的JSON往返转换,可采用以下两种方式:
- 手动构造Credentials对象
直接从Map中提取对应字段创建对象,完全避免重复编解码:
return cred.map((map) { return Credentials( map['accessToken'], refreshToken: map['refreshToken'], idToken: map['idToken'], tokenEndpoint: Uri.parse(map['tokenEndpoint']), scopes: List<String>.from(map['scopes'] ?? []), expiration: map['expiration'] != null ? DateTime.fromMillisecondsSinceEpoch(map['expiration']) : null, ); }).toList();
注意字段名必须与Credentials.toJson()输出的字段完全一致,同时要处理空值场景。
- 封装转换工具方法
如果需要多次使用,可封装一个复用性方法:
Credentials credentialsFromMap(Map<String, dynamic> map) { return Credentials( map['accessToken'], refreshToken: map['refreshToken'], idToken: map['idToken'], tokenEndpoint: Uri.parse(map['tokenEndpoint']), scopes: List<String>.from(map['scopes'] ?? []), expiration: map['expiration'] != null ? DateTime.fromMillisecondsSinceEpoch(map['expiration']) : null, ); } // 在getter中调用 return cred.map((e) => credentialsFromMap(e)).toList();
内容的提问来源于stack exchange,提问作者basse
相关产品推荐
相关产品推荐

