1

我将项目升级到 Null-Safety,但是在运行 build_runner 时将属性定义为 null 时出现错误:

@JsonKey()
late Guid? colonizedStellarObjectId;

Guid 类型来自此处,但我对其进行了修改以支持空安全:

import 'package:uuid/uuid.dart';
import 'package:validators/validators.dart';

/// Class that emulates as closely as possible the C# Guid type.
class Guid {
  static const String _defaultGuid = "00000000-0000-0000-0000-000000000000";

  /// The Guid whose value is the default sequence of characters that represent a 'zero-value' UUID in .Net "00000000-0000-0000-0000-000000000000"
  static Guid get defaultValue => new Guid(_defaultGuid);

  String? _value;

  /// Constructor, expects a valid UUID and will throw an exception if the value provided is invalid.
  Guid(String v) {
    _failIfNotValidGuid(v);
    _value = v;
  }

  /// Generates a new v4 UUID and returns a GUID instance with the new UUID.
  static Guid get newGuid {
    return new Guid(Uuid().v4());
  }

  /// Checks whether a value is a valid Guid
  /// Returns false if 'guid' is null or has an invalid value
  /// Returns true if guid is valid
  static bool isValid(Guid? guid) {
    if (guid == null) {
      return false;
    } else {
      return isUUID(guid.value);
    }
  }

  _failIfNotValidGuid(String? v) {
    if (v == null || v.isEmpty) {
      v = _defaultGuid;
    }
    final isInvalid = isUUID(v) == false;
    if (isInvalid) {
      throw new FlutterGuidError("Value '$v' is not a valid UUID");
    }
  }

  /// Gets the UUID value contained by the Guid object as a string.
  String get value {
    if (_value == null || _value!.isEmpty) {
      return _defaultGuid;
    } else {
      return _value!;
    }
  }

  /// Performs a case insensitive comparison on the UUIDs contained in two Guid objects.
  /// Comparison is by value and not by reference.
  bool operator ==(other) {
    return this.value.toLowerCase() == other.toString().toLowerCase();
  }

  /// Returns the hashCode.
  @override
  int get hashCode {
    return super.hashCode;
  }

  /// Gets the UUID value contained by the Guid object as a string.
  @override
  String toString() {
    return value;
  }
}

class FlutterGuidError extends Error {
  final String message;

  FlutterGuidError(this.message);
}

Could not generate `fromJson` code for `colonizedStellarObjectId`.
To support the type `Guid` you can:
* Use `JsonConverter`
  https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonConverter-class.html
* Use `JsonKey` fields `fromJson` and `toJson`
  https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonKey/fromJson.html
  https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonKey/toJson.html
package:astrogame_app/models/stellar/base_types/colonizable_stellar_object.dart:14:14
   ╷
14 │   late Guid? colonizedStellarObjectId;
   │              ^^^^^^^^^^^^^^^^^^^^^^^^
   ╵

我为 json 序列化编写了一个转换器:

class GuidConverter implements JsonConverter<Guid, String> {
  const GuidConverter();

  @override
  Guid fromJson(String json) {
    return Guid(json);
  }

  @override
  String toJson(Guid object) {
    return object.toString();
  }
}

当我将属性设置为非空时,一切都很好。我在这里想念什么?

4

1 回答 1

1

我遇到过这个问题不是 json_serializable 而是 floor (它处理序列化 dart 类以存储在 sqlite 数据库中),但我会说它的机制是相同的。您的 JsonConverter 能够序列化 Guid 实例,但由于 Colonizedstellarobjectid 字段可以为 null,因此 toJson() 方法也应该接受 null。

然后你的 GuidConverter 必须子类化JsonConverter<Guid?, String>

但是,通常,如果转换器甚至必须序列化 null 值,则即使将其用作可空类型的输出也很有用,因此在您的情况下,基类将是JsonConverter<Guid?, String?>.

例子:

class GuidConverter implements JsonConverter<Guid?, String?> {
  const GuidConverter();

  @override
  Guid? fromJson(String? json) {
    if (json==null) {
      return null;      
    }
    return Guid(json);
  }

  @override
  String? toJson(Guid? object) {
    if (object==null) {
      return null;
    }
    return object.toString();
  }
}
于 2021-07-27T19:13:09.087 回答