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_serializable은 fromJson()이 있을 때만 toJson()을 자동 생성합니다.
• toJson()만 있다고 해서 json_serializable이 fromJson()을 만들지는 않습니다 → JSON 변환이 필요하다는 확신이 없기 때문.
• freezed를 유지하면서 toJson()을 자동 생성하려면 반드시 fromJson()을 추가해야 합니다.
• fromJson() 없이 toJson()만 필요하다면, 일반 클래스로 만들고 toJson()을 직접 구현하는 것이 더 적절할 수 있습니다.
마무리하며
만약 API 요청을 보낼 때만 toJson()이 필요하고, JSON 응답을 파싱할 일이 없다면,
굳이 fromJson()을 추가하지 않고 일반 클래스로 만들고 toJson()을 직접 구현하는 방법도 고려해 볼 수 있습니다.
하지만 freezed의 강력한 기능(불변 객체, copyWith(), == 비교 등)을 활용하고 싶다면, fromJson()을 추가해서 자동 생성하는 것이 좋습니다.
댓글