JsonConverter

BYSON STUDIO·2023년 9월 15일
0

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
에도 사용 해보자.

Firestore

FirebaseFirestore의 collection 혹은 doc 는 withConverter라는 method를 갖고있다.

이걸 freezed와 연결.. 계속
https://purefun.dev/posts/firestore-and-freezed/

0개의 댓글