Dart(flutter) json序列化 踩坑

刚接触Dart,发请求返回json,进行序列化,官方给了方案,也给了推荐的工具,json_serializable。但是这个工具真的有坑!记录一下。
数据结构如下:

{"jsonrpc":"2.0","result":"123","id":0}
{"jsonrpc":"2.0","error":{"code":-1,"message":"error"},"id":0}

交易成功没有error,result可能是不同的结构,其他结构不变,所以需要用到泛型。
json_serializable操作过程请看自行看flutter网或者github
出来的结果是这样的。

import 'package:json_annotation/json_annotation.dart';

part 'response.g.dart';

class Response<T> {
  Response(this.id, this.jsonrpc, this.result, this.error);
  int id;
  String jsonrpc;
  T result;
  Error error;
}

@JsonSerializable()
class Error {
  Error(this.code, this.message, this.data);
  int code;
  String message;
  String data;

  factory Error.fromJson(Map<String, dynamic> json) => _$ErrorFromJson(json);
  Map<String, dynamic> toJson() => _$ErrorToJson(this);
}

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'response.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

Error _$ErrorFromJson(Map<String, dynamic> json) {
  return Error(
      json['code'] as int, json['message'] as String, json['data'] as String);
}

Map<String, dynamic> _$ErrorToJson(Error instance) => <String, dynamic>{
      'code': instance.code,
      'message': instance.message,
      'data': instance.data
    };

import './response.dart';
import 'package:json_annotation/json_annotation.dart';

part 'son.g.dart';

@JsonSerializable()
class SonRes extends Response<String> {
  SonRes(id, jsonrpc, result, error) : super(id, jsonrpc, result, error);
  getBlockHash() {
    return result;
  }

  factory SonRes.fromJson(Map<String, dynamic> json) => _$SonResFromJson(json);
  Map<String, dynamic> toJson() => _$SonResToJson(this);
}

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'son.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

SonRes _$SonResFromJson(Map<String, dynamic> json) {
  return SonRes(json['id'], json['jsonrpc'], json['result'], json['error']);
}

Map<String, dynamic> _$SonResToJson(SonRes instance) => <String, dynamic>{
      'id': instance.id,
      'jsonrpc': instance.jsonrpc,
      'result': instance.result,
      'error': instance.error
    };

实际运行之后,交易成功解析没问题,但是交易失败解析会报错

type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Error'

是不是超级坑爹,然而可以很明显的看到是Error类出问题了。
这个工具是为了节省时间,自动生成解析代码,但是其实是有问题的,需要修改。(被误导了)
简单来说就是定义一个fromjson的方法,然后手动去转换。
看这段代码

SonRes _$SonResFromJson(Map<String, dynamic> json) {
  return SonRes(json['id'], json['jsonrpc'], json['result'], json['error']);
}

问题出在最后一个参数json[‘error’],我们取出来的其实Map<String, dynamic>这么一个map,但我们也需要将他序列化,所以修改成

SonRes _$SonResFromJson(Map<String, dynamic> json) {
  return SonRes(json['id'], json['jsonrpc'], json['result'], Error.fromJson(json['error']));
}

再次运行,失败的时候可以正常解析,但是成功的时候又不可以了,报错:

Unhandled exception:
NoSuchMethodError: The method '[]' was called on null.
Receiver: null
Tried calling: []("code")

原因是成功的时候没有error字段,但是序列化的时候依然会去解析error,导致类似空指针的问题,只能去做一次判断

factory SonRes.fromJson(Map<String, dynamic> json) {
     return SonRes(json['id'], json['jsonrpc'], json['result'],
        json['error'] == null ? null : Error.fromJson(json['error']));
  }

到这儿就可以正常解析了。没必要用part引入,所以直接把代码放一起。去掉工具
完整代码

class Response<T> {
  Response(this.id, this.jsonrpc, this.result, this.error);
  int id;
  String jsonrpc;
  T result;
  Error error;
}

class Error {
  Error(this.code, this.message, this.data);
  int code;
  String message;
  String data;

  factory Error.fromJson(Map<String, dynamic> json) {
    return Error(
        json['code'] as int, json['message'] as String, json['data'] as String);
  }

  Map<String, dynamic> toJson() => <String, dynamic>{
        'code': this.code,
        'message': this.message,
        'data': this.data
      };
}

import './response.dart';

class SonRes extends Response<String> {
  SonRes(id, jsonrpc, result, error) : super(id, jsonrpc, result, error);
  getBlockHash() {
    return result;
  }

  factory SonRes.fromJson(Map<String, dynamic> json) {
     return SonRes(json['id'], json['jsonrpc'], json['result'],
        json['error'] == null ? null : Error.fromJson(json['error']));
  }
  Map<String, dynamic> toJson() => <String, dynamic>{
        'id': this.id,
        'jsonrpc': this.jsonrpc,
        'result': this.result,
        'error': this.error
      };
}

和java序列化比起来,真的是太难用了。

    原文作者:秋月夜
    原文地址: https://blog.csdn.net/b805887485/article/details/86174762
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞