본문 바로가기
카테고리 없음

[Flutter] freezed와 toJson()의 관계: 왜 fromJson()이 필요할까?

by demonic_ 2025. 2. 24.
반응형

Flutter에서 freezed를 사용하면 불변 객체와 함께 JSON 직렬화도 쉽게 할 수 있습니다. 하지만 toJson()을 자동 생성하려면 반드시 fromJson()도 선언해야 한다는 점을 궁금해하는 분들이 많습니다.

 

이 글에서는 왜 fromJson()이 있어야 toJson()이 자동 생성되는지, 그리고 toJson()만 필요할 때 해결 방법은 무엇인지 자세히 알아보겠습니다.

 


 

freezed에서 toJson()만 선언하면 발생하는 문제

 

보통 freezed를 사용할 때, JSON 변환을 위해 아래와 같이 toJson()을 직접 선언하는 경우가 있습니다.

@freezed
class ToggleValuedCustomerEntity with _$ToggleValuedCustomerEntity {
  @JsonSerializable(explicitToJson: true)
  factory ToggleValuedCustomerEntity({
    required int partnerId,
    required int customerId,
    required bool toggleValue,
  }) = _ToggleValuedCustomerEntity;

  Map<String, dynamic> toJson() => _$ToggleValuedCustomerEntityToJson(this);
}

 

이렇게 작성하고 build_runner를 실행하면 컴파일 오류가 발생합니다.

Error: The method '_$ToggleValuedCustomerEntityToJson' isn't defined for the class 'ToggleValuedCustomerEntity'.

 

문제점: _ToggleValuedCustomerEntityToJson()이 자동 생성되지 않습니다.

이유: fromJson()이 없으면, json_serializable이 이 클래스가 JSON 변환이 필요하다고 판단하지 않기 때문입니다.

 


 

왜 fromJson()을 선언해야 toJson()이 자동 생성될까?

Dart의 json_serializable 패키지는 fromJson()을 기준으로 해당 클래스가 JSON 변환이 필요하다고 판단합니다.

즉, fromJson()이 없으면 이 클래스는 JSON 변환이 필요 없다고 간주하고, toJson()도 생성하지 않습니다.

 

 

json_serializable의 작동 원칙

1. fromJson()이 선언되어 있으면, 객체를 JSON으로 변환할 가능성이 있다고 판단toJson()도 자동 생성.

2. toJson()만 있으면, JSON을 객체로 변환할 필요가 없을 수도 있다고 판단toJson()을 자동 생성하지 않음.

 

 

즉, fromJson()을 선언해야 json_serializable이 **“이 클래스는 JSON 직렬화가 필요하다!”**고 인식하는 것입니다.

 


 

해결 방법: toJson()만 필요할 때 어떻게 해야 할까?

 

방법1: fromJson()을 추가하여 toJson() 자동 생성 유지

가장 간단한 방법은 fromJson()을 추가하는 것입니다.

이렇게 하면 build_runner 실행 시 toJson()도 자동 생성됩니다.

@freezed
class ToggleValuedCustomerEntity with _$ToggleValuedCustomerEntity {
  @JsonSerializable(explicitToJson: true)
  factory ToggleValuedCustomerEntity({
    required int partnerId,
    required int customerId,
    required bool toggleValue,
  }) = _ToggleValuedCustomerEntity;

  // ✅ fromJson 추가 (이걸 추가해야 toJson도 자동 생성됨!)
  factory ToggleValuedCustomerEntity.fromJson(Map<String, dynamic> json) =>
      _$ToggleValuedCustomerEntityFromJson(json);

  Map<String, dynamic> toJson() => _$ToggleValuedCustomerEntityToJson(this);
}

 

fromJson()을 추가하면 toJson()도 정상적으로 자동 생성됨!

flutter pub run build_runner build 실행 후 정상적으로 JSON 변환이 가능해집니다.

 

 

방법2: freezed 없이 일반 클래스로 만들기

만약 fromJson()이 필요 없고 toJson()만 필요하다면, freezed 없이 일반 클래스를 만들 수도 있습니다.

class ToggleValuedCustomerEntity {
  final int partnerId;
  final int customerId;
  final bool toggleValue;

  ToggleValuedCustomerEntity({
    required this.partnerId,
    required this.customerId,
    required this.toggleValue,
  });

  Map<String, dynamic> toJson() => {
        'partnerId': partnerId,
        'customerId': customerId,
        'toggleValue': toggleValue,
      };
}

 

이렇게 하면 toJson()만 직접 정의해서 사용할 수 있습니다.

❌ 하지만 freezed의 불변 객체 및 copyWith() 기능을 사용할 수 없습니다.

 


 

결론: freezed에서 toJson()을 자동 생성하려면?

json_serializablefromJson()이 있을 때만 toJson()을 자동 생성합니다.

toJson()만 있다고 해서 json_serializablefromJson()을 만들지는 않습니다 → JSON 변환이 필요하다는 확신이 없기 때문.

freezed를 유지하면서 toJson()을 자동 생성하려면 반드시 fromJson()을 추가해야 합니다.

fromJson() 없이 toJson()만 필요하다면, 일반 클래스로 만들고 toJson()을 직접 구현하는 것이 더 적절할 수 있습니다.

 

 

 

마무리하며

만약 API 요청을 보낼 때만 toJson()이 필요하고, JSON 응답을 파싱할 일이 없다면,

굳이 fromJson()을 추가하지 않고 일반 클래스로 만들고 toJson()을 직접 구현하는 방법도 고려해 볼 수 있습니다.

 

하지만 freezed의 강력한 기능(불변 객체, copyWith(), == 비교 등)을 활용하고 싶다면, fromJson()을 추가해서 자동 생성하는 것이 좋습니다. 

 

반응형

댓글