Dart에서 JSON 직렬화 / 역직렬화 알아보자

개발렬·2025년 7월 17일

Flutter

목록 보기
7/10

Flutter에서 API와 데이터를 주고받을 때 필수인 json_serializable과 json_annotation 사용법을 정리합니다.
직렬화/역직렬화를 자동화하면 코드가 간결해지고, 유지보수가 쉬워집니다.

📌 직렬화와 역직렬화란?

  • 직렬화 (Serialization) Dart 객체 → JSON User → { name: 홍길동 }
  • 역직렬화 (Deserialization) JSON → Dart 객체 { name: 홍길동 } → User

사용하는 패키지

dependencies:
  json_annotation: ^4.9.0

dev_dependencies:
  build_runner: ^2.4.9
  json_serializable: ^6.8.0
json_annotation: 어노테이션 정의용

json_serializable: 변환 코드 자동 생성

build_runner: 자동 생성 실행 도구

예시 모델: Vlog

import 'package:json_annotation/json_annotation.dart';

part 'vlog.g.dart';

()
class Vlog {
  final String title;
  final String url;
  final DateTime publishedAt;
  final bool isFavorite;

  Vlog({
    required this.title,
    required this.url,
    required this.publishedAt,
    required this.isFavorite,
  });

  factory Vlog.fromJson(Map<String, dynamic> json) => _$VlogFromJson(json);
  Map<String, dynamic> toJson() => _$VlogToJson(this);
}

⚙️ 코드 생성

flutter pub run build_runner build

📁 .g.dart 파일의 역할은?
part 'vlog.g.dart';에 의해 연결된 .g.dart 파일은
fromJson, toJson에 사용되는 자동 생성 함수들이 들어있는 파일입니다.

Vlog _$VlogFromJson(Map<String, dynamic> json) => Vlog(
  title: json['title'] as String,
  url: json['url'] as String,
  publishedAt: DateTime.parse(json['publishedAt'] as String),
  isFavorite: json['isFavorite'] as bool,
);

Map<String, dynamic> _$VlogToJson(Vlog instance) => <String, dynamic>{
  'title': instance.title,
  'url': instance.url,
  'publishedAt': instance.publishedAt.toIso8601String(),
  'isFavorite': instance.isFavorite,
};

⚠️ .g.dart 파일은 직접 수정하지 않으며, 삭제 후 다시 생성해도 됩니다.

🛠 다양한 예제들
✅ 1. List 직렬화

()
class Playlist {
  final String name;
  final List<Vlog> vlogs;

  Playlist({required this.name, required this.vlogs});

  factory Playlist.fromJson(Map<String, dynamic> json) => _$PlaylistFromJson(json);
  Map<String, dynamic> toJson() => _$PlaylistToJson(this);
}

내부에 Vlog 모델을 포함한 리스트도 자동으로 처리됩니다.

✅ 2. nullable 필드

()
class Comment {
  final String? content;
  final String? author;

  Comment({this.content, this.author});

  factory Comment.fromJson(Map<String, dynamic> json) => _$CommentFromJson(json);
  Map<String, dynamic> toJson() => _$CommentToJson(this);
}

null 값도 문제 없이 변환됩니다.

✅ 3. enum 변환

enum VideoType { vlog, tutorial, review }


()
class Video {
  final String title;
  final VideoType type;

  Video({required this.title, required this.type});

  factory Video.fromJson(Map<String, dynamic> json) => _$VideoFromJson(json);
  Map<String, dynamic> toJson() => _$VideoToJson(this);
}

enum은 자동으로 type: 'vlog' 형태로 변환되며,
옵션으로 @JsonValue()를 사용해 커스터마이징할 수 있습니다.

✅ 4. DateTime 포맷 커스터마이징

()
class Event {
  (fromJson: _fromJson, toJson: _toJson)
  final DateTime start;

  Event({required this.start});

  static DateTime _fromJson(String date) => DateTime.parse(date);
  static String _toJson(DateTime date) => date.toIso8601String();

  factory Event.fromJson(Map<String, dynamic> json) => _$EventFromJson(json);
  Map<String, dynamic> toJson() => _$EventToJson(this);
}

@JsonKey()를 활용하면 원하는 포맷으로 날짜를 처리할 수 있습니다.

✅ 5. freezed와 함께 쓰기

import 'package:freezed_annotation/freezed_annotation.dart';

part 'user.freezed.dart';
part 'user.g.dart';


class User with _$User {
  const factory User({
    required String name,
    required int age,
  }) = _User;

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}

freezed는 immutable class, copyWith, equality 등을 자동 생성해줍니다.

JSON 관련 기능도 json_serializable로 연동됩니다.

.g.dart와 .freezed.dart 두 파일이 생성됩니다.

flutter pub run build_runner build

🧪 테스트 예시

void main() {
  final json = {
    "title": "Flutter 브이로그",
    "url": "https://example.com/vlog1",
    "publishedAt": "2025-07-16T12:00:00Z",
    "isFavorite": true
  };

  final vlog = Vlog.fromJson(json);
  print(vlog.title); // Flutter 브이로그

  final backToJson = vlog.toJson();
  print(backToJson);
}
profile
Flutter

0개의 댓글