Flutter 에서 Json을 사용하다보면 json_serializable를 많이 사용한다.
사용하다보면, property 중 실제로는 동일한 데이터 이지만
json에서의 type과 model에서의 type이 다를경우가 있다.
예를들어 색상을 나타낼경우 JSON에서는 아래와 같이 String으로 적지만
{
"color": "0xFF0000FF"
}
Model에서는 Color라는 Type으로 사용하는것 같은 경우를 말한다
class Foo {
final Color color;
}
여러가지 방법이 있겠지만, 가장 보편적인 방법은 JsonConverter를 사용 하는것이다
// Only Json Serializable
import 'dart:ui';
import 'package:json_annotation/json_annotation.dart';
part 'foo.g.dart';
// JsonConverter<T, S>
// 여기서 T가 model, S가 JSON에서의 TYPE이다
//
// JsonConverter를 implements 하고
// fromJson : JSON에서 들어온 입력을 MODEL로 어떻게 출력할지
// toJson: MODEL의 값을 JSON으로 어떻게 출력할지
// 정의 해줌
class _ColorConverter implements JsonConverter<Color?, String?> {
const _ColorConverter();
@override
Color? fromJson(String? value) {
try {
return Color(int.parse(value!));
} catch (exception) {
return null;
}
}
@override
String? toJson(Color? value) {
if (value != null) {
return "0x${value.value.toRadixString(16)}";
} else {
return null;
}
}
}
@JsonSerializable()
class Foo {
// MODEL에서 지정된 Property만을 위한 Converter를 지정
// 지정 해주면, JsonSerializable이
//
// toJson, fromJson 자동 생성 시
// 지정된 Perperty 처리 시 아래 Converter를 사용함
@_ColorConverter()
final Color? color;
Foo({
required this.color,
});
Map<String, dynamic> toJson() => _$FooToJson(this);
factory Foo.fromJson(Map<String, dynamic> json) => _$FooFromJson(json);
}
Freezed도 많이 사용하는데 아래와 같이 하면 된다
// Freezed Using Json Serializable
import 'dart:ui';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:json_annotation/json_annotation.dart';
part 'foo.freezed.dart';
part 'foo.g.dart';
class _ColorConverter implements JsonConverter<Color?, String?> {
// Only Json Serializable 예제와 동일함
// ...
}
@freezed
class Foo {
const factory Foo({
@_ColorConverter() // 여기에 Annotation
required this.color,
}) = _Foo;
factory Foo.fromJson(Map<String, Object?> json) => _$FooFromJson(json);
}
예를들어 String? name; 이라는 필드가 있을때 그냥 copyWith를 만들면
object.copyWith(
name: "HELLO",
);
// name에 Hello를 할당해서 복사
object.copyWith(
name: null,
);
object.copyWith(
);
// 그냥 copyWith에서 위 두개는 완전히 동일하다
// null 혹은 empty 일경우 해당 필드는 Preserve 시키기 때문에
근데 freezed가 생성 해주는 copyWith는 기가 막히게도 null과 empty를 구분 해준다.
아 진심 너무 편하다 ;;
이 외에도
Firebase <-> Dart간
Timestmap <-> DateTime
에도 사용 해보자.
FirebaseFirestore의 collection 혹은 doc 는 withConverter라는 method를 갖고있다.
이걸 freezed와 연결.. 계속
https://purefun.dev/posts/firestore-and-freezed/