Ad

JsonSerializable. Can't Match Model To Json Schema

- 1 answer

The following json is the response body of a request at Google Place Details Api.

{
    "html_attributions": [],
    "result": {
        "address_components": [
            {
                "long_name": "18",
                "short_name": "18",
                "types": [
                    "street_number"
                ]
            },
            {
                "long_name": "Doiranis",
                "short_name": "Doiranis",
                "types": [
                    "route"
                ]
            },
            {
                "long_name": "Thessaloniki",
                "short_name": "Thessaloniki",
                "types": [
                    "locality",
                    "political"
                ]
            },
            {
                "long_name": "Thessaloniki",
                "short_name": "Thessaloniki",
                "types": [
                    "administrative_area_level_3",
                    "political"
                ]
            },
            {
                "long_name": "Greece",
                "short_name": "GR",
                "types": [
                    "country",
                    "political"
                ]
            },
            {
                "long_name": "546 39",
                "short_name": "546 39",
                "types": [
                    "postal_code"
                ]
            }
        ]
    },
    "status": "OK"
}

The following is my Place model class

import 'package:json_annotation/json_annotation.dart';

part 'place_model.g.dart';

@JsonSerializable(fieldRename: FieldRename.snake)
class Place {
  final String streetName;
  final String streetNumber;
  final String city;
  final String zipCode;

  Place({
    required this.streetName,
    required this.streetNumber,
    required this.city,
    required this.zipCode,
  });

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

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'place_model.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

Place _$PlaceFromJson(Map<String, dynamic> json) => Place(
      streetName: json['street_name'] as String,
      streetNumber: json['street_number'] as String,
      city: json['city'] as String,
      zipCode: json['zip_code'] as String,
    );

Map<String, dynamic> _$PlaceToJson(Place instance) => <String, dynamic>{
      'street_name': instance.streetName,
      'street_number': instance.streetNumber,
      'city': instance.city,
      'zip_code': instance.zipCode,
    };

I need the short_name values in address_components list for my Place model, but currently my model doesn't match the json Schema. I'm an inexperienced developer and this might be simple. But could you suggest me a way to properly generate place_model.g.dart?

Ad

Answer

The response does not match your target class, hence you'll have to convert it first.

Create models for the response:

@JsonSerializable()
class Response {
  final Result result;
  final String status;

  const Response({required this.result, required this.status});

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

@JsonSerializable(fieldRename: FieldRename.snake)
class Result {
  final List<AddressComponents> addressComponents;

  const Result({required this.addressComponents});

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

@JsonSerializable(fieldRename: FieldRename.snake)
class AddressComponents {
  final String longName;
  final String shortName;
  final List<String> types;

  const AddressComponents({
    required this.longName,
    required this.shortName,
    required this.types,
  });

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

Now you may add a factory constructor to the Place model that will build a Place model from the Response:

class Place {
  const Place({
    this.streetName,
    this.streetNumber,
    this.city,
    this.zipCode,
  });

  final String? streetName;
  final String? streetNumber;
  final String? city;
  final String? zipCode;

  factory Place.fromResponse(Response response) {
    final streetNumberComponent = response.result.addressComponents
        .where((c) => c.types.contains('street_number'));
    // .. here the rest of Place fields

    return Place(
      streetNumber: streetNumberComponent.isNotEmpty
          ? streetNumberComponent.first.shortName
          : null,
      // .. here the rest of Place fields
    );
  }
}
Ad
source: stackoverflow.com
Ad