type 不是 Map<String、dynamic>、@JsonSerializable() 类型的子类型



我有一些问题与我的json序列化,我使用json_serializable: ^6.2.0,所以我的代码是:

shift.dart:

import 'package:hive/hive.dart';
import 'package:json_annotation/json_annotation.dart';
part 'shift.g.dart';
@HiveType(typeId: 1)
@JsonSerializable()
class Shift extends HiveObject {
@HiveField(0)
final DateTime? start;
@HiveField(1)
final DateTime? end;
@HiveField(2, defaultValue: Duration(hours: 8))
final Duration? duration;
Shift({required this.start, required this.end, Duration? duration})
: duration = duration ?? const Duration(hours: 8);
Shift copyWith({
DateTime? start,
DateTime? end,
Duration? duration,
}) {
return Shift(
start: start ?? this.start,
end: end ?? this.end,
duration: duration ?? this.duration,
);
}
Map<String, dynamic> toJson() => _$ShiftToJson(this);
factory Shift.fromJson(Map<String, dynamic> json) => _$ShiftFromJson(json);
// Equatable does not work with HiveObjects, necessary to override hashCode ==
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is Shift &&
runtimeType == other.runtimeType &&
start == other.start &&
end == other.end &&
duration == other.duration;
@override
int get hashCode => start.hashCode ^ end.hashCode ^ duration.hashCode;
}

shift.g.dart:

// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'shift.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class ShiftAdapter extends TypeAdapter<Shift> {
@override
final int typeId = 1;
@override
Shift read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return Shift(
start: fields[0] as DateTime?,
end: fields[1] as DateTime?,
duration:
fields[2] == null ? const Duration(hours: 8) : fields[2] as Duration?,
);
}
@override
void write(BinaryWriter writer, Shift obj) {
writer
..writeByte(3)
..writeByte(0)
..write(obj.start)
..writeByte(1)
..write(obj.end)
..writeByte(2)
..write(obj.duration);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is ShiftAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Shift _$ShiftFromJson(Map<String, dynamic> json) => Shift(
start: json['start'] == null
? null
: DateTime.parse(json['start'] as String),
end: json['end'] == null ? null : DateTime.parse(json['end'] as String),
duration: json['duration'] == null
? null
: Duration(microseconds: json['duration'] as int),
);
Map<String, dynamic> _$ShiftToJson(Shift instance) => <String, dynamic>{
'start': instance.start?.toIso8601String(),
'end': instance.end?.toIso8601String(),
'duration': instance.duration?.inMicroseconds,
};

shift_cubit.dart:

import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:timer/cubit/shift/shift_state.dart';
import '../../model/shift.dart';
class ShiftCubit extends HydratedCubit<ShiftState> {
ShiftCubit()
: super(
ShiftState(
shift: Shift(
start: null,
end: null,
duration: const Duration(hours: 8),
),
enabledStart: true,
enabledEnd: false,
status: ShiftStateStatus.initial,
),
);
void updateStart(DateTime start) {
emit(
ShiftState(
shift: Shift(
start: start,
end: null,
duration: const Duration(hours: 8),
),
enabledStart: false,
enabledEnd: true,
status: ShiftStateStatus.startTapped,
),
);
}
void updateEnd(DateTime end) {
emit(
ShiftState(
shift: Shift(
start: state.shift.start,
end: end,
duration: const Duration(hours: 8),
),
enabledStart: false,
enabledEnd: false,
status: ShiftStateStatus.endTapped,
),
);
}
void resetNewDay() {
emit(
ShiftState(
shift: Shift(
start: null,
end: null,
duration: const Duration(hours: 8),
),
enabledStart: true,
enabledEnd: false,
status: ShiftStateStatus.initial,
),
);
}
@override
ShiftState fromJson(Map<String, dynamic> json) {
return ShiftState.fromJson(json);
}
@override
Map<String, dynamic> toJson(ShiftState state) {
return state.toJson();
}
}

shift_state.dart:

import 'dart:convert';
import 'package:equatable/equatable.dart';
import 'package:json_annotation/json_annotation.dart';
import '../../model/shift.dart';
part 'shift_state.g.dart';
enum ShiftStateStatus { initial, startTapped, endTapped }
@JsonSerializable()
class ShiftState extends Equatable {
final Shift shift;
final bool enabledStart;
final bool enabledEnd;
final ShiftStateStatus status;
const ShiftState({
required this.shift,
required this.enabledStart,
required this.enabledEnd,
required this.status,
});
@override
List<Object> get props => [shift, enabledStart, enabledEnd, status];
Map<String, dynamic> toJson() => _$ShiftStateToJson(this);
factory ShiftState.fromJson(Map<String, dynamic> json) =>
_$ShiftStateFromJson(json);
}

shift_state.g.dart:

// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'shift_state.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
ShiftState _$ShiftStateFromJson(Map<String, dynamic> json) => ShiftState(
shift: Shift.fromJson(json['shift'] as Map<String, dynamic>),
enabledStart: json['enabledStart'] as bool,
enabledEnd: json['enabledEnd'] as bool,
status: $enumDecode(_$ShiftStateStatusEnumMap, json['status']),
);
Map<String, dynamic> _$ShiftStateToJson(ShiftState instance) =>
<String, dynamic>{
'shift': instance.shift,
'enabledStart': instance.enabledStart,
'enabledEnd': instance.enabledEnd,
'status': _$ShiftStateStatusEnumMap[instance.status],
};
const _$ShiftStateStatusEnumMap = {
ShiftStateStatus.initial: 'initial',
ShiftStateStatus.startTapped: 'startTapped',
ShiftStateStatus.endTapped: 'endTapped',
};
我试着像这样测试我的代码:
group('toJson/fromJson', () {
test('work properly', () async {
await mockHydratedStorage(() {
final shiftCubit = ShiftCubit();
expect(
shiftCubit.fromJson(shiftCubit.toJson(shiftCubit.state)),
shiftCubit.state,
);
});
});
});

,结果为:type 'Shift' is not a subtype of type 'Map<String, dynamic>' in type cast这个应用程序似乎工作得很好,但是我想知道为什么这个序列化不能工作。

编辑:

异常堆栈:

package:timer/cubit/shift/shift_state.g.dart 10:43  _$ShiftStateFromJson
package:timer/cubit/shift/shift_state.dart 32:7     new ShiftState.fromJson
package:timer/cubit/shift/shift_cubit.dart 68:23    ShiftCubit.fromJson
testblocbloc_test.dart 40:24                      main.<fn>.<fn>.<fn>.<fn>
package:hydrated_bloc/src/hydrated_bloc.dart 62:22  HydratedBlocOverrides.runZoned.<fn>.<fn>
type 'Shift' is not a subtype of type 'Map<String, dynamic>' in type cast

shift_state.g.dart出现问题:

ShiftState _$ShiftStateFromJson(Map<String, dynamic> json) => ShiftState(
shift: Shift.fromJson(json['shift'] as Map<String, dynamic>),
enabledStart: json['enabledStart'] as bool,
enabledEnd: json['enabledEnd'] as bool,
status: $enumDecode(_$ShiftStateStatusEnumMap, json['status']),
);
Map<String, dynamic> _$ShiftStateToJson(ShiftState instance) =>
<String, dynamic>{
'shift': instance.shift,
'enabledStart': instance.enabledStart,
'enabledEnd': instance.enabledEnd,
'status': _$ShiftStateStatusEnumMap[instance.status],
};

请注意,您的toJson方法正在用instance.shift填充键为'shift'的值,但您的fromJson期望Map,而不是Shift类型的实例对象。修复方法很简单,您需要将explicitToJson设置为true,如:

@JsonSerializable(explicitToJson: true)
class ShiftState extends Equatable {

文档注释:

{bool? explicitToJson}
If true, generated toJson methods will explicitly call toJson on nested objects.
When using JSON encoding support in dart:convert, toJson is automatically called on objects, so the default behavior (explicitToJson: false) is to omit the toJson call.

请注意,这正是我们想要的,在你的例子中,我们希望toJson在嵌套对象上调用。

相关内容

最新更新