guricode

Dart에서 JSON 직렬화/역직렬화 완벽 정리 - toJson & fromJson 메서드 활용법 본문

앱/Flutter&Dart

Dart에서 JSON 직렬화/역직렬화 완벽 정리 - toJson & fromJson 메서드 활용법

agentrakugaki 2025. 7. 28. 20:52

Flutter나 Dart로 앱을 개발하다 보면 외부 API와 데이터를 주고받을 일이 많습니다. 이때 사용하는 것이 바로 JSON 직렬화와 역직렬화입니다.
오늘은 아래 코드를 바탕으로 jsonEncode, jsonDecode, toJson, fromJson의 동작 원리와 작성법을 차근히 정리해보겠습니다.


✅ 전체 코드 미리 보기

import 'dart:convert';

void main() {
  Map<String, dynamic> map = {
    "name": "이영상",
    "age": 33,
  };

  String jsonData = jsonEncode(map);

  String jsonSampleData = """
{
  "name": "이영상",
  "age": 33
}
""";

  var decodedData = jsonDecode(jsonSampleData);
  Human human = Human.fromJson(decodedData);
  print(human);
  print(human.toJson());
}

class Human {
  String name;
  int age;

  Human({required this.name, required this.age});

  Human.fromJson(Map<String, dynamic> map)
      : this(
          name: map['name'],
          age: map['age'],
        );

  Map<String, dynamic> toJson() {
    return {'name': name, 'age': age};
  }
}

1. JSON 직렬화란?

**직렬화(Serialization)**는 객체를 JSON 문자열로 변환하는 과정입니다.
반대로 **역직렬화(Deserialization)**는 JSON 문자열을 다시 객체로 되돌리는 과정입니다.

직렬화 흐름

객체 → Map → JSON(String)

역직렬화 흐름

JSON(String) → Map → 객체


2. jsonEncode로 Map을 JSON으로 변환

String jsonData = jsonEncode(map);
  • jsonEncode()는 Map<String, dynamic>을 JSON 문자열로 바꿔줍니다.
  • 콘솔 출력 시:
  • {"name":"이영상","age":33}

3. jsonDecode로 JSON을 Map으로 변환

var decodedData = jsonDecode(jsonSampleData);
  • jsonDecode()는 문자열 형태의 JSON 데이터를 Dart에서 사용할 수 있는 Map으로 변환합니다.
  • 위 예제에서는 decodedData는 다음과 같은 Map이 됩니다:
  • { "name": "이영상", "age": 33 }

4. fromJson 네임드 생성자

Human.fromJson(Map<String, dynamic> map)
  • Map 데이터를 바탕으로 클래스 인스턴스를 생성하기 위한 생성자입니다.
  • 위에서 decodedData를 받아 객체로 만들어주는 역할을 합니다.
Human human = Human.fromJson(decodedData);

5. toJson 메서드

Map<String, dynamic> toJson() {
  return {'name': name, 'age': age};
}
  • 클래스 인스턴스를 다시 Map으로 변환해주는 메서드입니다.
  • API에 데이터를 보낼 때 혹은 저장 시 사용합니다.

6. 전체 흐름 요약

단계 역할

jsonEncode Map → JSON String 변환
jsonDecode JSON String → Map 변환
fromJson Map → 객체 생성
toJson 객체 → Map 변환

7. 주의할 점

  • jsonEncode()에 직접 클래스를 넣을 수 없습니다. 반드시 toJson()을 구현한 클래스만 직렬화 가능합니다.
  • fromJson()은 생성자 형식으로 만들어야 하며, 보통 이름이 일관되게 fromJson으로 사용됩니다.
  • JSON 키 이름과 클래스의 변수 이름이 일치해야 합니다. 그렇지 않으면 null 값이 나올 수 있습니다.

8. 실제 활용 예시

REST API에서 받아온 JSON 응답을 바로 객체로 바꾸고자 할 때:

final response = await http.get(...);
final Map<String, dynamic> data = jsonDecode(response.body);
final user = User.fromJson(data);

보내는 경우:

final jsonString = jsonEncode(user.toJson());

9. 결론

  • Dart에서 JSON 처리를 위해서는 toJson과 fromJson 메서드 구현이 필수입니다.
  • jsonEncode, jsonDecode와 함께 쓰면 어떤 형태의 데이터든 쉽게 주고받을 수 있습니다.
  • API 통신이나 로컬 저장소 등 다양한 곳에 활용되므로 꼭 익혀두는 것이 좋습니다.

 

 

 

** 네임드 생성자 형태에 관해

  Human.fromJson(Map<String, dynamic> map)
      : this(
          name: map['name'],
          age: map['age'],
        );

 

위에 코드 예시를 보면 이렇게 네임드 생성자 형태가 보인다.

fromJson은 호출하면 : 받은 map 컬렉션의 인자들로 this로 생성자를 초기화 하는 형태인것 같다.

콜론 : 의 뒤는 초기화 리스트라고 불린다.

 

네임드 생성자를 쓰는 이유?(from GTP선생님...)

 

1. 의미 있는 이름으로 생성자 역할 구분

클래스를 생성할 때 단 하나의 생성자만 있으면 다양한 초기화 방식이 힘들어.
이럴 때 이름이 있는 생성자를 사용하면 용도를 구분해서 더 명확하게 만들 수 있어.

예시:

Human.fromJson(...)    // JSON으로부터 초기화
Human.empty()          // 기본값으로 초기화
Human.withRandomAge()  // 랜덤 나이로 초기화

각각 어떤 방식으로 생성되는지 이름만 보고도 알 수 있어.


2. 복잡한 초기화 로직 분리 가능

기본 생성자에서는 단순한 값 설정만 해야 하지만,
네임드 생성자에선 JSON 파싱, 유효성 검사, 파일 읽기 등 복잡한 로직을 자유롭게 넣을 수 있어.

예시:

Human.fromJson(Map<String, dynamic> map) {
  if (!map.containsKey('name') || !map.containsKey('age')) {
    throw FormatException("Invalid JSON format");
  }
  name = map['name'];
  age = map['age'];
}

3. 기본 생성자와 공존 가능

기본 생성자 Human(...) 외에 Human.fromJson(...), Human.withRandomAge(...) 등
여러 방식으로 객체를 생성할 수 있어 유연한 설계가 가능해.

 

✅ 역할 분리 다양한 생성 방식 구분 가능 (fromJson, empty, copy)
✅ 복잡한 로직 처리 기본 생성자보다 자유롭게 초기화 로직 작성 가능
✅ 코드 가독성 향상 생성자 이름만 봐도 어떤 식으로 객체가 생성되는지 이해 가능