728x90

아래 코드는 factory 생성자를 일일이 타이핑을 해야 하는 번거로움이 있다.

import 'package:rest/restaurant/component/restaurant_card.dart';
 
import '../../common/const/data.dart';
 
enum RestaurantPriceRange {
  expensive,
  medium,
  cheap,
}
 
class RestaurantModel {
  final String id;
  final String name;
  final String thumbUrl;
  final List<String> tags;
  final RestaurantPriceRange priceRange;
  final double ratings;
  final int ratingsCount;
  final int deliveryTime;
  final int deliveryFee;
 
  RestaurantModel({
    required this.id,
    required this.name,
    required this.thumbUrl,
    required this.tags,
    required this.priceRange,
    required this.ratings,
    required this.ratingsCount,
    required this.deliveryTime,
    required this.deliveryFee,
  });
 
  factory RestaurantModel.fromJson({
    required Map<String, dynamic> json,
  }) {
    return RestaurantModel(
      id: json['id'],
      name: json['name'],
      thumbUrl: 'http://$realIp${json['thumbUrl']}',
      tags: List<String>.from(json['tags']),
      priceRange: RestaurantPriceRange.values.firstWhere(
        (e) => e.name == json['priceRange'],
      ),
      ratings: json['ratings'],
      ratingsCount: json['ratingsCount'],
      deliveryTime: json['deliveryTime'],
      deliveryFee: json['deliveryFee'],
    );
  }
 
}

 

 

위 코드에서 factory 생성자 코드 부분을 자동 생성하는 방법으로 JSON Serialize 를 이용한다.

1. https://pub.dev/packages/json_serializable 에서 최신버전을 확인한다.

Readme 탭에서 Setup 부분의 example 을 누르면 pubspec.yaml 에 추가할 버전이 나온다.

아래의 라이브러리를 추가하고 flutter pub get 명령을 실행한다.

dependencies:
  json_annotation: ^4.8.0
 
dev_dependencies:
  build_runner: ^2.3.3
  json_serializable: ^6.7.1

 

 

Class 위에 @JsonSerializable() 을 추가하고, part 'restaurant_model.g.dart'; 코드를 추가한다.

그리고 나서 터미널 창을 열면 프로젝트 root 폴더가 된다.

root에서 dart run build_runner build 를 입력하고 실행한다.

매번 입력하기 귀찮다면 dart run build_runner watch 명령어를 실행하면 된다.

import 'package:json_annotation/json_annotation.dart';
import 'package:rest/common/utils/data_utils.dart';
 
part 'restaurant_model.g.dart';
 
/**
* 수정 사항이 생기면 터미널에서 dart run build_runner build 를 다시 실행한다.
 * 그러면 자동으로 g.dart 파일을 업데이트한다.
 */
 
enum RestaurantPriceRange {
  expensive,
  medium,
  cheap,
}
 
@JsonSerializable()
class RestaurantModel {
  final String id;
  final String name;
  @JsonKey(
    fromJson: DataUtils.pathToUrl,
  )
  final String thumbUrl;
  final List<String> tags;
  final RestaurantPriceRange priceRange;
  final double ratings;
  final int ratingsCount;
  final int deliveryTime;
  final int deliveryFee;
 
  RestaurantModel({
    required this.id,
    required this.name,
    required this.thumbUrl,
    required this.tags,
    required this.priceRange,
    required this.ratings,
    required this.ratingsCount,
    required this.deliveryTime,
    required this.deliveryFee,
  });
 
  factory RestaurantModel.fromJson(Map<String, dynamic> json)
  => _$RestaurantModelFromJson(json);
 
  Map<String, dynamic> toJson() => _$RestaurantModelToJson(this);
 
 
  // factory RestaurantModel.fromJson({
  //   required Map<String, dynamic> json,
  // }) {
  //   return RestaurantModel(
  //     id: json['id'],
  //     name: json['name'],
  //     thumbUrl: 'http://$realIp${json['thumbUrl']}',
  //     tags: List<String>.from(json['tags']),
  //     priceRange: RestaurantPriceRange.values.firstWhere(
  //       (e) => e.name == json['priceRange'],
  //     ),
  //     ratings: json['ratings'],
  //     ratingsCount: json['ratingsCount'],
  //     deliveryTime: json['deliveryTime'],
  //     deliveryFee: json['deliveryFee'],
  //   );
  // }
 
}

 

모델 클래스 내부에 fromJson과 toJson을 정의해 두면 해당 메서드를 호출할 때마다 오타를 걱정할 필요가 없어진다.

 

 

칼럼에서 별도 변경이 필요하면

  @JsonKey(
    fromJson: DataUtils.pathToUrl,
  )

와 같이 추가하고 나서 dart run build_runner build 를 다시 실행한다.

그러면 restaurant_model.g.dart 파일이 업데이트되어 자동 생성된다.

 

// GENERATED CODE - DO NOT MODIFY BY HAND
 
part of 'restaurant_model.dart';
 
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
 
RestaurantModel _$RestaurantModelFromJson(Map<String, dynamic> json) =>
    RestaurantModel(
      id: json['id'as String,
      name: json['name'as String,
      thumbUrl: DataUtils.pathToUrl(json['thumbUrl'as String),
      tags: (json['tags'as List<dynamic>).map((e) => e as String).toList(),
      priceRange:
          $enumDecode(_$RestaurantPriceRangeEnumMap, json['priceRange']),
      ratings: (json['ratings'as num).toDouble(),
      ratingsCount: json['ratingsCount'as int,
      deliveryTime: json['deliveryTime'as int,
      deliveryFee: json['deliveryFee'as int,
    );
 
Map<String, dynamic> _$RestaurantModelToJson(RestaurantModel instance) =>
    <String, dynamic>{
      'id': instance.id,
      'name': instance.name,
      'thumbUrl': instance.thumbUrl,
      'tags': instance.tags,
      'priceRange': _$RestaurantPriceRangeEnumMap[instance.priceRange]!,
      'ratings': instance.ratings,
      'ratingsCount': instance.ratingsCount,
      'deliveryTime': instance.deliveryTime,
      'deliveryFee': instance.deliveryFee,
    };
 
const _$RestaurantPriceRangeEnumMap = {
  RestaurantPriceRange.expensive: 'expensive',
  RestaurantPriceRange.medium: 'medium',
  RestaurantPriceRange.cheap: 'cheap',
};
 

 

 

블로그 이미지

Link2Me

,