Study Record

[Flutter] JSON (json_serializable 라이브러리) 본문

Flutter/라이브러리

[Flutter] JSON (json_serializable 라이브러리)

초코초코초코 2023. 4. 17. 22:30
728x90

🎁 Json serializable

Json 을 사용하여 데이터를 다루는 것을 좀 더 쉽게 해주는 라이브러리이다.

 

 

json_serializable | Dart Package

Automatically generate code for converting to and from JSON by annotating Dart classes.

pub.dev

 

 

😶 설치(installing)

pubspec.yaml 파일에 다음과 같이 라이브러리들을 추가한 뒤 pub get 버튼을 눌러 프로젝트에 적용해 준다.

dependencies:
  json_annotation: ^4.8.0
  
dev_dependencies:
  json_serializable: ^6.0.0

 

 

😶 간단한 사용법

서버와의 통신을 통해 Json 형식으로 데이터를 다음과 같이 받는다고 한다면,

{
  "id": 1,
  "name": "ndfs",
  "doubleValue": 3.9,
  "range": "middle",
  "listItem": ["item1", "item2", "item3"],
}

 

서버에서 받은 Json 형식의 데이터를 사용하기 쉽게 데이터 클래스를 만들 때, 데이터 클래스 이름 위에 @JsonSerializable() 어노테이션을 붙이고 "part '{현재 파일 이름}.g.dart';" 를 상단에 추가하면 일단은 준비가 끝난다.

import 'package:json_annotation/json_annotation.dart';

part 'test.g.dart';

enum enumRange { high, middle, low }

@JsonSerializable()
class TestData {
  final int id;
  final String name;
  final enumRange range;
  final double doubleValue;
  final List<String> listItem;

  TestData({
    required this.id,
    required this.name,
    required this.range,
    required this.doubleValue,
    required this.listItem,
  });
}

 

터미널에서 flutter pub run build_runner build 를 실행하면 {현재 파일 이름}.g.dart 파일이 생성된다.("part '{현재 파일 이름}.g.dart';" 이 부분이 없으면 파일이 생성되지 않는다.) 이 파일에는 Json 데이터를 쉽게 다룰 수 있는 여러가지 코드들이 들어있다.

 

{현재 파일 이름}.g.dart 파일에는  [Json 데이터 → 데이터 클래스] 형식으로 바로 변환해 주는 함수인 _$TestDataFromJson() 함수와 [데이터 클래스 → Json 데이터] 형식으로 바꿔주는 _$TestDataToJson() 함수를 사용하여 코드를 간단하게 할 수 있다. 데이터 클래스의 이름을 토대로 _${이름}FromJson() 혹은 _${이름}ToJson() 함수가 자동으로 {현재 파일이름}.g.dart 에 생성된다.

 

이를 토대로 원래 예시의 TestData 클래스 코드를 보충하면 다음과 같다.

import 'package:json_annotation/json_annotation.dart';

part 'test.g.dart';

enum enumRange { high, middle, low }

@JsonSerializable()
class TestData {
  final int id;
  final String name;
  final enumRange range;
  final double doubleValue;
  final List<String> listItem;

  TestData({
    required this.id,
    required this.name,
    required this.range,
    required this.doubleValue,
    required this.listItem,
  });
  
  factory TestData.fromJson(Map<String, dynamic> json) => _$TestDataFromJson(json);

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

 

실제로 사용한다고 하면 다음과 같다.

// 서버에서 받은 데이터로 가정
final jsonData = {
  "id": 1,
  "name": "ndfs",
  "doubleValue": 3.9,
  "range": "middle",
  "listItem": ["item1", "item2", "item3"],
};

// Json to 데이터 클래스
TestData testData = TestData.fromJson(jsonData);

// 데이터클래스 to json
Map<String, dynamic> convertJsonData = testData.toJson();

 

 

😶 @JsonKey()

@JsonSerializable()
class TestData {
  final int id;
  @JsonKey(
    fromJson: valueToName,
    toJson: nameToValue,
  )
  final String name;

  TestData({
    required this.id,
    required this.name,
  });

  factory TestData.fromJson(Map<String, dynamic> json) => _$TestDataFromJson(json);

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

  static String valueToName(String value) {
    return "kim$value";
  }

  static String nameToValue(String name) {
    return name.replaceAll("kim", "");
  }
}

jsonKey 어노테이션을 통해 값이 fromJson 일 경우 설정한 static 함수를 거쳐 반영되고 마찬가지로 toJson 일 경우 설정한 static 함수를 거쳐 반영된다.

 

{현재파일이름}.g.dart 예시)

...
TestData _$TestDataFromJson(Map<String, dynamic> json) => TestData(
      id: json['id'] as int,
      name: TestData.valueToName(json['name'] as String),
    );

Map<String, dynamic> _$TestDataToJson(TestData instance) => <String, dynamic>{
      'id': instance.id,
      'name': TestData.nameToValue(instance.name),
    };
...

 

 

😶 데이터 클래스 변수에 다른 클래스 변수가 있을 경우

만약 데이터가 다음과 같은 형식을 갖는다면,

{
  "id": 1,
  "name": "namsd",
  "subData": {
    "number": 3,
    "rank": "master",
  }
}

 

subData 의 데이터 클래스도 똑같이 @JsonSerializable() 어노테이션과 fromJson 생성자, toJson 함수가 필요할 수 있다.

import 'package:json_annotation/json_annotation.dart';

part 'test.g.dart';

@JsonSerializable()
class TestData {
  final int id;
  final String name;
  final subTestData subData;

  TestData({
    required this.id,
    required this.name,
    required this.subData,
  });

  factory TestData.fromJson(Map<String, dynamic> json) => _$TestDataFromJson(json);

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


@JsonSerializable()
class subTestData {
  int number;
  String rank;

  subTestData({required this.number, required this.rank});

  factory subTestData.fromJson(Map<String, dynamic> json) => _$subTestDataFromJson(json);

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

 

728x90