在这种情况下如何从 json 解码?

How to decode from json in this situation?

我将整个 class 作为 json 对象保存在我的 Parse Back4App 服务器上。将对象解析为 json 很痛苦,因为我需要将许多属性转换为嵌套 class Book 和主要 class DatabaseSyncItem 中的字符串。现在我不知道如何将这个 json 对象变回 DatabaseSyncObject。我假设将嵌套的 json 书籍对象返回对象模型也是如此,也就是说它不会以这种方式工作。

我遇到错误并且没有成功。如果我尝试从 main 中的 json 对象列表访问特定索引,我可以找到某个地方,但这非常混乱。在这个情况下,你会怎么做?在这里帮助我,我第一次使用 json。

尝试应用这些帖子但没有成功:

import 'dart:convert';
import 'dart:io';
import 'package:hive/hive.dart';
import 'package:parse_server_sdk/parse_server_sdk.dart';
import 'package:service_database_sync/data/books_hardcoded.dart';
import 'package:service_database_sync/models/book_model.dart';
import 'package:service_database_sync/models/database_sync_model.dart';
import 'package:service_database_sync/services/demo_services.dart';
import 'package:service_database_sync/services/server_database_services.dart';

Future<void> main(List<String> arguments) async {
  Hive.init('hive_database');
  Hive.registerAdapter(BookAdapter());
  await Parse().initialize(
    ServerDatabaseServices().keyApplicationId,
    ServerDatabaseServices().keyParseServerUrl,
    clientKey: ServerDatabaseServices().keyClientKey,
    debug: true,
  );

  final test = updateLocalDatabase();
  Future<List> getList() {
    return Future.value(test);
  }

  var list = await getList();
  var jsonObject = list[2]['DatabaseSyncItem'];
  // var backToObject = jsonDecode(jsonObject); // error: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String'
  var backToObject = DatabaseSyncItem.fromJson(jsonObject); // error: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Book'
  print(backToObject);
}

// This method will get server database
  Future<List<ParseObject>> updateLocalDatabase() async {
    final events = QueryBuilder<ParseObject>(ParseObject('Event'));
    final apiResponse = await events.query();
    if (apiResponse.success && apiResponse.result != null) {
      return apiResponse.results;
    } else {
      return [];
    }
  }

part 'database_sync_model.g.dart';

@HiveType(typeId: 1)
class DatabaseSyncItem {
  @HiveField(0)
  Book previousBookValue;

  @HiveField(1)
  Book updatedBookValue;

  @HiveField(2)
  DateTime dateAdded;

  @HiveField(3)
  DateTime lastModified;

  @HiveField(4)
  DatabaseAction entryAction;

  DatabaseSyncItem({
    this.previousBookValue,
    this.updatedBookValue,
    this.dateAdded,
    this.lastModified,
    this.entryAction,
  });

  @override
  String toString() {
  return '''
  previousValue: $previousBookValue
  updatedValue: $updatedBookValue
  dateAdded: $dateAdded
  lastModified: $lastModified
  entryAction: $entryAction
  ''';
   }

  // Turn json back into data model
  DatabaseSyncItem.fromJson(Map<String, dynamic> json)
      : previousBookValue = json['previousBookValue'],
        updatedBookValue = json['updatedBookValue'],
        dateAdded = json['dateAdded'],
        lastModified = json['lastModified'],
        entryAction = json['entryAction'];

  // Turn data model into json
  Map<String, dynamic> toJson() => {
        'previousBookValue': previousBookValue,
        'updatedBookValue': updatedBookValue,
        'dateAdded': dateAdded,
        'lastModified': lastModified,
        'entryAction': entryAction.toString(),
      };
}

enum DatabaseAction {
  create,
  update,
  delete,
}

import 'package:hive/hive.dart';
part 'book_model.g.dart';

@HiveType(typeId: 0)
class Book {
  @HiveField(0)
  String title;

  @HiveField(1)
  String author;

  @HiveField(2)
  DateTime publishingDate;

  @HiveField(3)
  DateTime dateAdded;

  @HiveField(4)
  DateTime lastModified;

  Book({
    this.title,
    this.author,
    this.publishingDate,
    this.dateAdded,
    this.lastModified,
  });

  @override
  String toString() {
  return '''
  title: $title
  author: $author
  publishingDate: $publishingDate
  dateAdded: $dateAdded
  lastModified $lastModified
  ''';
   }

  Book.fromJson(Map<String, dynamic> json)
      : title = json['title'],
        author = json['author'],
        publishingDate = json['publishingDate'],
        dateAdded = json['dateAdded'],
        lastModified = json['lastModified'];

  Map<String, dynamic> toJson() => {
        'title': title,
        'author': author,
        'publishingDate': publishingDate.toIso8601String(),
        'dateAdded': dateAdded.toIso8601String(),
        'lastModified': lastModified.toIso8601String()
      };
}

这个答案似乎比我最初预期的要复杂得多。需要使用json可序列化包和json注解包。

这些包是必需的,当您查看为处理类型、null 以及嵌套 class 生成的代码时,您就会明白为什么。以防其他人遇到这个。

import 'package:hive/hive.dart';
import 'package:json_annotation/json_annotation.dart';
part 'book_model.g.dart';

@JsonSerializable(includeIfNull: true)
@HiveType(typeId: 0)
class Book {
  @HiveField(0)
  String title;

  @HiveField(1)
  String author;

  @HiveField(2)
  DateTime publishingDate;

  @HiveField(3)
  DateTime dateAdded;

  @HiveField(4)
  DateTime lastModified;

  Book({
    required this.title,
    required this.author,
    required this.publishingDate,
    required this.dateAdded,
    required this.lastModified,
  });

  factory Book.fromJson(Map<String, dynamic> json) => _$BookFromJson(json);
  Map<String, dynamic> toJson() => _$BookToJson(this);

  @override
  String toString() {
    return '''
  title: $title
  author: $author
  publishingDate: $publishingDate
  dateAdded: $dateAdded
  lastModified $lastModified
  ''';
  }
}

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'book_model.dart';

// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************

class BookAdapter extends TypeAdapter<Book> {
  @override
  final int typeId = 0;

  @override
  Book read(BinaryReader reader) {
    final numOfFields = reader.readByte();
    final fields = <int, dynamic>{
      for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
    };
    return Book(
      title: fields[0] as String,
      author: fields[1] as String,
      publishingDate: fields[2] as DateTime,
      dateAdded: fields[3] as DateTime,
      lastModified: fields[4] as DateTime,
    );
  }

  @override
  void write(BinaryWriter writer, Book obj) {
    writer
      ..writeByte(5)
      ..writeByte(0)
      ..write(obj.title)
      ..writeByte(1)
      ..write(obj.author)
      ..writeByte(2)
      ..write(obj.publishingDate)
      ..writeByte(3)
      ..write(obj.dateAdded)
      ..writeByte(4)
      ..write(obj.lastModified);
  }

  @override
  int get hashCode => typeId.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is BookAdapter &&
          runtimeType == other.runtimeType &&
          typeId == other.typeId;
}

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

Book _$BookFromJson(Map<String, dynamic> json) {
  return Book(
    title: json['title'] as String,
    author: json['author'] as String,
    publishingDate: DateTime.parse(json['publishingDate'] as String),
    dateAdded: DateTime.parse(json['dateAdded'] as String),
    lastModified: DateTime.parse(json['lastModified'] as String),
  );
}

Map<String, dynamic> _$BookToJson(Book instance) => <String, dynamic>{
      'title': instance.title,
      'author': instance.author,
      'publishingDate': instance.publishingDate.toIso8601String(),
      'dateAdded': instance.dateAdded.toIso8601String(),
      'lastModified': instance.lastModified.toIso8601String(),
    };
import 'package:json_annotation/json_annotation.dart';
import 'book_model.dart';
import 'package:hive/hive.dart';
part 'database_sync_model.g.dart';

@JsonSerializable(includeIfNull: true)
@HiveType(typeId: 1)
class DatabaseSyncItem {
  @HiveField(0)
  Book? previousBookValue;

  @HiveField(1)
  Book? updatedBookValue;

  @HiveField(2)
  DateTime dateAdded;

  @HiveField(3)
  DateTime lastModified;

  @HiveField(4)
  DatabaseAction entryAction;

  DatabaseSyncItem({
    this.previousBookValue,
    this.updatedBookValue,
    required this.dateAdded,
    required this.lastModified,
    required this.entryAction,
  });

  factory DatabaseSyncItem.fromJson(Map<String, dynamic> json) => _$DatabaseSyncItemFromJson(json);
  Map<String, dynamic> toJson() => _$DatabaseSyncItemToJson(this);

  @override
  String toString() {
  return '''
  previousValue: $previousBookValue
  updatedValue: $updatedBookValue
  dateAdded: $dateAdded
  lastModified: $lastModified
  entryAction: $entryAction
  ''';
   }
}

enum DatabaseAction {
  create,
  update,
  delete,
}

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'database_sync_model.dart';

// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************

class DatabaseSyncItemAdapter extends TypeAdapter<DatabaseSyncItem> {
  @override
  final int typeId = 1;

  @override
  DatabaseSyncItem read(BinaryReader reader) {
    final numOfFields = reader.readByte();
    final fields = <int, dynamic>{
      for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
    };
    return DatabaseSyncItem(
      previousBookValue: fields[0] as Book?,
      updatedBookValue: fields[1] as Book?,
      dateAdded: fields[2] as DateTime,
      lastModified: fields[3] as DateTime,
      entryAction: fields[4] as DatabaseAction,
    );
  }

  @override
  void write(BinaryWriter writer, DatabaseSyncItem obj) {
    writer
      ..writeByte(5)
      ..writeByte(0)
      ..write(obj.previousBookValue)
      ..writeByte(1)
      ..write(obj.updatedBookValue)
      ..writeByte(2)
      ..write(obj.dateAdded)
      ..writeByte(3)
      ..write(obj.lastModified)
      ..writeByte(4)
      ..write(obj.entryAction);
  }

  @override
  int get hashCode => typeId.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is DatabaseSyncItemAdapter &&
          runtimeType == other.runtimeType &&
          typeId == other.typeId;
}

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

DatabaseSyncItem _$DatabaseSyncItemFromJson(Map<String, dynamic> json) {
  return DatabaseSyncItem(
    previousBookValue: json['previousBookValue'] == null
        ? null
        : Book.fromJson(json['previousBookValue'] as Map<String, dynamic>),
    updatedBookValue: json['updatedBookValue'] == null
        ? null
        : Book.fromJson(json['updatedBookValue'] as Map<String, dynamic>),
    dateAdded: DateTime.parse(json['dateAdded'] as String),
    lastModified: DateTime.parse(json['lastModified'] as String),
    entryAction: _$enumDecode(_$DatabaseActionEnumMap, json['entryAction']),
  );
}

Map<String, dynamic> _$DatabaseSyncItemToJson(DatabaseSyncItem instance) =>
    <String, dynamic>{
      'previousBookValue': instance.previousBookValue,
      'updatedBookValue': instance.updatedBookValue,
      'dateAdded': instance.dateAdded.toIso8601String(),
      'lastModified': instance.lastModified.toIso8601String(),
      'entryAction': _$DatabaseActionEnumMap[instance.entryAction],
    };

K _$enumDecode<K, V>(
  Map<K, V> enumValues,
  Object? source, {
  K? unknownValue,
}) {
  if (source == null) {
    throw ArgumentError(
      'A value must be provided. Supported values: '
      '${enumValues.values.join(', ')}',
    );
  }

  return enumValues.entries.singleWhere(
    (e) => e.value == source,
    orElse: () {
      if (unknownValue == null) {
        throw ArgumentError(
          '`$source` is not one of the supported values: '
          '${enumValues.values.join(', ')}',
        );
      }
      return MapEntry(unknownValue, enumValues.values.first);
    },
  ).key;
}

const _$DatabaseActionEnumMap = {
  DatabaseAction.create: 'create',
  DatabaseAction.update: 'update',
  DatabaseAction.delete: 'delete',
};