为什么在尝试调用带有 flutter chopper 和内置值的方法时出现错误?

Why am I getting an error when trying to call a method with flutter chopper and built value?

我收到以下错误,我相信这是因为空安全,这意味着没有收到数据或 getSignedInUser() 方法不正确或 class BuiltValueConverter 是原因。

(我用 Postman 测试了令牌并检索了数据)

E/flutter (21792): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: Unhandled error Null check operator used on a null value occurred in Instance of 'AuthBloc'. E/flutter (21792): #0
BuiltValueConverter._deserialize package:todo_list_app/…/auth/built_value_converter.dart:51 E/flutter (21792): #1 BuiltValueConverter._convertToCustomObject package:todo_list_app/…/auth/built_value_converter.dart:36 E/flutter (21792): #2 BuiltValueConverter.convertResponse package:todo_list_app/…/auth/built_value_converter.dart:25

我正在 built_value 酒吧使用切碎机。我正在尝试将即将到来的 json 转换为对象。 示例:

{ "userName": "Jack", "email": "jack2066@gmail.com", "userRole": "USER", "created_at": "2021-07-03T16:49:56.774Z", "updated_at": "2021-07-03T16:49:56.774Z" }

以下错误开始的代码也在本教程中进行了解释Converters & Built Value Integration

import 'package:built_collection/built_collection.dart';
import 'package:chopper/chopper.dart';
import 'package:todo_list_app/infrastructure/remote/auth/models/serializers.dart';

class BuiltValueConverter extends JsonConverter {

  @override
  Request convertRequest(Request request) {
    return super.convertRequest(
      request.copyWith(
        body: serializers.serializeWith(
          serializers.serializerForType(request.body.runtimeType)!,
          request.body,
        ),
      ),
    );
  }

  @override
  Response<BodyType> convertResponse<BodyType, SingleItemType>(
    Response response,
  ) {
    final Response dynamicResponse = super.convertResponse(response);
    final BodyType customBody =
        _convertToCustomObject<SingleItemType>(dynamicResponse.body);//
    return dynamicResponse.copyWith<BodyType>(body: customBody);
  }


  dynamic _convertToCustomObject<SingleItemType>(dynamic element) {
    if (element is SingleItemType) return element;

    if (element is List)
      return _deserializeListOf<SingleItemType>(element);
    else
      return _deserialize<SingleItemType>(element);
  }

  BuiltList<SingleItemType> _deserializeListOf<SingleItemType>(
    List dynamicList,
  ) {
    // Make a BuiltList holding individual custom objects
    return BuiltList<SingleItemType>(
      dynamicList.map((element) => _deserialize<SingleItemType>(element)),
    );
  }

  SingleItemType _deserialize<SingleItemType>(Map<String, dynamic> value,) {
    // We have a type parameter for the BuiltValue type, which should be returned after deserialization.
    return serializers.deserializeWith(
      serializers.serializerForType(SingleItemType)!, // Error Start
      value,
    );
  }

}

这是我的 Chopper 服务代码,getSignedInUser 抛出错误。 不知道getSignedInUser方法的实现是否正确

import 'package:chopper/chopper.dart';
import 'package:injectable/injectable.dart';
import 'package:todo_list_app/infrastructure/remote/auth/built_value_converter.dart';
import 'package:todo_list_app/infrastructure/remote/auth/models/auth_built_model.dart';
import 'package:todo_list_app/infrastructure/remote/core/constants.dart';

part 'auth_service.chopper.dart';

@singleton
@ChopperApi() 
abstract class AuthService extends ChopperService {
  @factoryMethod
  static AuthService create() {
    final client = ChopperClient(
      baseUrl: AUTH_BASE_URL_External,
      services: [
        _$AuthService(),
      ],
      converter: BuiltValueConverter(),
      errorConverter: JsonConverter(),
      interceptors: [
        HttpLoggingInterceptor()
      ],
    );
    return _$AuthService(client);
  }

  @Post(path: '/signup')
  Future<Response> signUp(@Body() RegisterRequestModel body);

  @Post(path: '/signin')
  Future<Response<LoginResponseModel>> singIn(@Body() LoginRequestModel body);

  //headers: {AUTH_HEADER:BEARER+'authValue'}
  @Get(path: '/auth', )//authValue='Bearer Token'
  Future<Response<UserResponseModel>> getSignedInUser(@Header("Authorization") String authValue);//error Unhandled error Null check operator used on a null value
}

知道如何解决这个错误吗? 还有 Chopper 或具有良好文档的替代酒吧的良好文档吗? 谢谢

是的,正如您所说,这是因为空安全。您的 _deserialize return 是一个非空值,而 serializers.deserializeWith 可以 return 一个空值。您可以将 return 类型更改为可为空,或者处理 serializers.deserializeWith 的空大小写。如果你愿意,你可以使用下面的BuiltValueConverter。它来自他们给出的 example,这是通用的,有细微的变化。

import 'package:built_collection/built_collection.dart';
import 'package:built_value/serializer.dart';
import 'package:chopper/chopper.dart';
import 'package:graphical_representation/app/serializers.dart';

class BuiltValueConverter extends JsonConverter {
  T? _deserialize<T>(dynamic value) => serializers.deserializeWith<T>(
    (serializers.serializerForType(T) as Serializer<T>),
    value,
  );

  BuiltList<T> _deserializeListOf<T>(Iterable value) => BuiltList(
    value.map((value) => _deserialize<T>(value)).toList(growable: false),
  );

  dynamic _decode<T>(entity) {
    /// handle case when we want to access to Map<String, dynamic> directly
    /// getResource or getMapResource
    /// Avoid dynamic or unconverted value, this could lead to several issues
    if (entity is T) return entity;

    try {
      if (entity is List) return _deserializeListOf<T>(entity);
      return _deserialize<T>(entity);
    } catch (e) {
      print(e);
      return null;
    }
  }

  @override
  Response<ResultType> convertResponse<ResultType, Item>(Response response) {
    // use [JsonConverter] to decode json
    final jsonRes = super.convertResponse(response);
    final body = _decode<Item>(jsonRes.body);
    return jsonRes.copyWith<ResultType>(body: body);
  }

  @override
  Request convertRequest(Request request) => super.convertRequest(
    request.copyWith(
      body: serializers.serialize(request.body),
    ),
  );
}

我认为您的“serielizers.dart”文件中缺少值,应该如下所示:

    @SerializersFor(const[RegisterRequestModel,LoginRequestModel,UserResponseModel])
final Serializers serializers =
(_$serializers.toBuilder()..addPlugin(StandardJsonPlugin())).build();