Flutter에서 서버와 json을 통해 통신을 할때 주로 class.fromJson, class.toJson의 방식으로 변환하여 주고받게 된다.
이를 클래스에서 직접 메소드로 만들어 줘야하는데
이는 클래스의 속성이 조금만 더 커지더라도 써야할 코드가 곱절로 늘어나게 되고, 사람의 실수가 발생하기 쉽고, 모델 클래스의 가독성이 떨어질 수 있다.
이를 해당 패키지를 사용함으로써 코드가 간결해지고, 다른 사람이 이를 보았을때도 한눈에 코드의 구조를 파악할 수 있다.
json_serializable은 freezed에서도 사용되는데, freezed는 상속이 아닌 합성을 하는 방식을 택하므로 상속 등 다양한 커스텀이 필요한 상황에서는 json_serializable이 더 나은 선택이 될 수 있다.
class Person {
final String firstName;
final String lastName;
final DateTime? dateOfBirth;
Person({required this.firstName, required this.lastName, this.dateOfBirth});
factory Person.fromJson(Map<String, dynamic> json) => Person(
firstName: json['firstName'] as String,
lastName: json['lastName'] as String,
dateOfBirth: json['dateOfBirth'] == null
? null
: DateTime.parse(json['dateOfBirth'] as String),
);
Map<String, dynamic> toJson() => {
'firstName': instance.firstName,
'lastName': instance.lastName,
'dateOfBirth': instance.dateOfBirth?.toIso8601String(),
};
}
import 'package:json_annotation/json_annotation.dart';
part 'example.g.dart';
()
class Person {
final String firstName;
final String lastName;
final DateTime? dateOfBirth;
Person({required this.firstName, required this.lastName, this.dateOfBirth});
factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json);
Map<String, dynamic> toJson() => _$PersonToJson(this);
}
json_annotaion과 json_serializable, build_runner을 설치한다.
dart pub add json_annotation
dart pub add --dev build_runner json_serializable
Code Generate을 실행하려면 다음 명령 중 하나를 수행한다.
dart run build_runner build
dart run build_runner watch
대부분의 코드 생성기와 마찬가지로 json_serializable는 어노테이션을 import한다.
그리고 파일 상단에 part 키워드를 적어야한다.(파일명과 동일)
import 'package:json_annotation/json_annotation.dart';
part 'my_file.g.dart';
explicitToJson
genericArgumentFactories
name
fromJson, toJson
defaultValue
unknownEnumValue
includeFromJson
includeToJson
includeIfNull
disallowNullValue
enum 사용시 맵핑될 값을 정해준다.
enum PersonType{
('Student')
student,
('Teacher')
teacher,
}
enhance enum을 사용시 JsonValue대신 맵핑을 해주는 용도이다.
즉, 각각의 enum마다 @JsonValue 다는것이 아닌 enum의 속성(field)를 사용하겠다는 의미.
(valueField: 'code') //final int "code"와 같게 써주면 된다.
enum PersonCode{
man(10),
women(20);
const PersonCode(this.code);
final int code;
}
(genericArgumentFactories: true)
class CursorPagination<T> extends CursorPaginationBase {
bool hasNext;
List<T> content;
CursorPagination({
required this.hasNext,
required this.content,
});
factory CursorPagination.fromJson(
Map<String, dynamic> json, T Function(Object? json) fromJsonT) =>
_$CursorPaginationFromJson(json, fromJsonT);
CursorPagination<T> copyWith({
bool? hasNext,
List<T>? content,
}) {
return CursorPagination<T>(
hasNext: hasNext ?? this.hasNext,
content: content ?? this.content,
);
}
}
import 'package:json_annotation/json_annotation.dart';
part 'person.g.dart';
(explicitToJson: true)
class Person {
final String name;
final int age;
(fromJson: DataUtils.imgUrlToString)
final String imUrl;
(name: 'home_phone')
final String homePhone;
final PersonType type;
final School school;
Person({
required this.name,
required this.age,
required this.imUrl,
required this.homePhone,
required this.type,
required this.school,
});
factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json);
Map<String, dynamic> toJson() => _$PersonToJson(this);
}
()
class School{
final String name;
final String address;
School(this.name,this.address);
factory School.fromJson(Map<String, dynamic> json) => _$SchoolFromJson(json);
Map<String, dynamic> toJson() => _$SchoolToJson(this);
}
(valueField: 'english')
enum PersonType{
student('Student','학생'),
teacher('Teacher','선생님');
const PersonType(this.english,this.korean);
final String english;
final String korean;
}
class DataUtils{
static String imgUrlToString(String url){
return 'http://$ip$url';
}
}
const ip = "127.0.0.1:8080";