skip to Main Content

I need to convert JSON to a Dart class. The structure of the JSON is a List of Maps.

Everything I have done works except for when I am assigning a Map with 0 items to "features:"

This is the PropertyInformation class:

 class PropertyInformation {
  String? addressLine1;
  String? city;
  String? state;
  String? zipCode;
  String? formattedAddress;
  String? assessorId;
  int? bedrooms;
  String? county;
  String? legalDescription;
  int? squareFootage;
  String? subdivision;
  int? yearBuilt;
  int? bathrooms;
  int? lotSize;
  String? propertyType;
  DateTime? lastSaleDate;
  Features features;
  TaxAssessment taxAssessment;
  PropertyTax propertyTaxes;
  Owner? owner;
  String? id;
  double? longitude;
  double? latitude;

  PropertyInformation({
    required this.addressLine1,
    required this.city,
    required this.state,
    required this.zipCode,
    required this.formattedAddress,
    required this.assessorId,
    required this.bedrooms,
    required this.county,
    required this.legalDescription,
    required this.squareFootage,
    required this.subdivision,
    required this.yearBuilt,
    required this.bathrooms,
    required this.lotSize,
    required this.propertyType,
    required this.lastSaleDate,
    required this.features,
    required this.taxAssessment,
    required this.propertyTaxes,
    required this.owner,
    required this.id,
    required this.longitude,
    required this.latitude,
  });

  factory PropertyInformation.fromJson(Map<String, dynamic> json) {

    return PropertyInformation(
      addressLine1: json['addressLine1'],
      city: json['city'],
      state: json['state'],
      zipCode: json['zipCode'],
      formattedAddress: json['formattedAddress'],
      assessorId: json['assessorId'],
      bedrooms: json['bedrooms'],
      county: json['county'],
      legalDescription: json['legalDescription'],
      squareFootage: json['squareFootage'],
      subdivision: json['subdivision'],
      yearBuilt: json['yearBuilt'],
      bathrooms: json['bathrooms'],
      lotSize: json['lotSize'],
      propertyType: json['propertyType'],
      lastSaleDate: json['lastSaleDate'] == null
          ? DateTime.now()
          : DateTime.parse(json['lastSaleDate']),
      features: Features.fromJson(json['features'] as Map<String, dynamic>),
      taxAssessment: TaxAssessment.fromJson(json["taxAssessment"] as Map<String, dynamic>),
      propertyTaxes: PropertyTax.fromJson(json["propertyTaxes"] as Map<String, dynamic>),
      owner: Owner.fromJson(json['owner']),
      id: json['id'],
      longitude: json['longitude'],
      latitude: json['latitude'],
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'addressLine1': addressLine1,
      'city': city,
      'state': state,
      'zipCode': zipCode,
      'formattedAddress': formattedAddress,
      'assessorId': assessorId,
      'bedrooms': bedrooms,
      'county': county,
      'legalDescription': legalDescription,
      'squareFootage': squareFootage,
      'subdivision': subdivision,
      'yearBuilt': yearBuilt,
      'bathrooms': bathrooms,
      'lotSize': lotSize,
      'propertyType': propertyType,
      'lastSaleDate': lastSaleDate?.toIso8601String(),
      //'features': features?.toJson(),
      // 'taxAssessment': taxAssessment
      //     .map((k, v) => MapEntry<String?, dynamic>(k, v.toJson())),
      // 'propertyTaxes': propertyTaxes
      //     .map((k, v) => MapEntry<String?, dynamic>(k, v.toJson())),
      'owner': owner?.toJson(),
      'id': id,
      'longitude': longitude,
      'latitude': latitude,
    };
  }

  @override
  String toString() {
    //return 'PropertyInformation{addressLine1: $addressLine1, city: $city, state: $state, zipCode: $zipCode, formattedAddress: $formattedAddress, assessorId: $assessorId, bedrooms: $bedrooms, county: $county, legalDescription: $legalDescription, squareFootage: $squareFootage, subdivision: $subdivision, yearBuilt: $yearBuilt, bathrooms: $bathrooms, lotSize: $lotSize, propertyType: $propertyType, lastSaleDate: $lastSaleDate, features: $features, taxAssessment: $taxAssessment, propertyTaxes: $propertyTaxes, owner: $owner, id: $id, longitude: $longitude, latitude: $latitude}';
    return 'PropertyInformation{addressLine1: $addressLine1, city: $city, state: $state, zipCode: $zipCode, formattedAddress: $formattedAddress, assessorId: $assessorId, bedrooms: $bedrooms, county: $county, legalDescription: $legalDescription, squareFootage: $squareFootage, subdivision: $subdivision, yearBuilt: $yearBuilt, bathrooms: $bathrooms, lotSize: $lotSize, lastSaleDate: $lastSaleDate, features: $features, owner: $owner, id: $id, longitude: $longitude, latitude: $latitude}';
  }
}

class Features {
  String? architectureType;
  bool? cooling;
  String? coolingType;
  String? exteriorType;
  int? floorCount;
  String? foundationType;
  bool? garage;
  String? garageType;
  bool? heating;
  String? heatingType;
  bool? pool;
  String? roofType;
  int? roomCount;
  int? unitCount;

  Features({
    required this.architectureType,
    required this.cooling,
    required this.coolingType,
    required this.exteriorType,
    required this.floorCount,
    required this.foundationType,
    required this.garage,
    required this.garageType,
    required this.heating,
    required this.heatingType,
    required this.pool,
    required this.roofType,
    required this.roomCount,
    required this.unitCount,
  });

  factory Features.fromJson(Map<String, dynamic> json) {
    return Features(
      architectureType: json['architectureType'],
      cooling: json['cooling'],
      coolingType: json['coolingType'],
      exteriorType: json['exteriorType'],
      floorCount: json['floorCount'],
      foundationType: json['foundationType'],
      garage: json['garage'],
      garageType: json['garageType'],
      heating: json['heating'],
      heatingType: json['heatingType'],
      pool: json['pool'],
      roofType: json['roofType'],
      roomCount: json['roomCount'],
      unitCount: json['unitCount'],
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'architectureType': architectureType,
      'cooling': cooling,
      'coolingType': coolingType,
      'exteriorType': exteriorType,
      'floorCount': floorCount,
      'foundationType': foundationType,
      'garage': garage,
      'garageType': garageType,
      'heating': heating,
      'heatingType': heatingType,
      'pool': pool,
      'roofType': roofType,
      'roomCount': roomCount,
      'unitCount': unitCount,
    };
  }

  @override
  String toString() {
    return 'Features{architectureType: $architectureType, cooling: $cooling, coolingType: $coolingType, exteriorType: $exteriorType, floorCount: $floorCount, foundationType: $foundationType, garage: $garage, garageType: $garageType, heating: $heating, heatingType: $heatingType, pool: $pool, roofType: $roofType, roomCount: $roomCount, unitCount: $unitCount}';
  }
}

class Owner {
  List<String> names;
  MailingAddress mailingAddress;

  Owner({
    required this.names,
    required this.mailingAddress,
  });

  factory Owner.fromJson(Map<String, dynamic> json) {
    return Owner(
      names: json['names'].cast<String?>(),
      mailingAddress: MailingAddress.fromJson(json['mailingAddress']),
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'names': names,
      'mailingAddress': mailingAddress.toJson(),
    };
  }

  @override
  String toString() {
    return 'Owner{names: $names, mailingAddress: $mailingAddress}';
  }
}

class MailingAddress {
  String? id;
  String? addressLine1;
  String? city;
  String? state;
  String? zipCode;
  String? addressLine2;

  MailingAddress({
    required this.id,
    required this.addressLine1,
    required this.city,
    required this.state,
    required this.zipCode,
    required this.addressLine2,
  });

  factory MailingAddress.fromJson(Map<String, dynamic> json) {
    return MailingAddress(
      id: json['id'],
      addressLine1: json['addressLine1'],
      city: json['city'],
      state: json['state'],
      zipCode: json['zipCode'],
      addressLine2: json['addressLine2'],
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'addressLine1': addressLine1,
      'city': city,
      'state': state,
      'zipCode': zipCode,
      'addressLine2': addressLine2,
    };
  }

  @override
  String toString() {
    return 'MailingAddress{id: $id, addressLine1: $addressLine1, city: $city, state: $state, zipCode: $zipCode, addressLine2: $addressLine2}';
  }
}

class PropertyTax {
  int total;

  PropertyTax({
    required this.total,
  });

  factory PropertyTax.fromJson(Map<String, dynamic> json) {
    return PropertyTax(
      total: json['total'],
    );
  }

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

  @override
  String toString() {
    return 'PropertyTax{total: $total}';
  }
}

class TaxAssessment {
  int value;
  int land;
  int improvements;

  TaxAssessment({
    required this.value,
    required this.land,
    required this.improvements,
  });

  factory TaxAssessment.fromJson(Map<String, dynamic> json) {
    return TaxAssessment(
      value: json['value'],
      land: json['land'],
      improvements: json['improvements'],
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'value': value,
      'land': land,
      'improvements': improvements,
    };
  }

  @override
  String toString() {
    return 'TaxAssessment{value: $value, land: $land, improvements: $improvements}';
  }
}

This is just one of the items in the JSON body:

[
  {
    "addressLine1":"2880 La Quinta Dr",
    "city":"Missouri City",
    "state":"TX",
    "zipCode":"77459",
    "formattedAddress":"2880 La Quinta Dr, Missouri City, TX 77459",
    "county":"Fort Bend",
    "features":{},  <<<<<<<<<  ERROR OCCURS HERE  >>>>>>>>>>
    "id":"2880-La-Quinta-Dr,-Missouri-City,-TX-77459",
    "longitude":-95.551958,
    "latitude":29.578265
  }
]

This is the data passed to PropertyInformation:

Map (11 items)
0:"addressLine1" -> "6155 Sienna Ranch Rd"
1:"city" -> "Missouri City"
2:"state" -> "TX"
3:"zipCode" -> "77459"
4:"formattedAddress" -> "6155 Sienna Ranch Rd, Missouri City, TX 77459"
5:"county" -> "Fort Bend"
6:"features" -> Map (0 items)
7:"lastSaleDate" -> "2012-05-29T00:00:00.000Z"
8:"id" -> "6155-Sienna-Ranch-Rd,-Missouri-City,-TX-77459"
9:"longitude" -> -95.548935
10:"latitude" -> 29.540808

As you can see, element #6:"features" is a Map (0 items)

The place where the execution throws an error is when it is trying to process a Map with 0 items. This is the line in the JSON where it fails and throws the error: 6:"features" -> Map (0 items)

I have been Googling and searching for an answer but I have not come across this situation documented so far.

How do I process this one line of the JSON Map that is a Map of 0 items?
Thanks

Things I have tried

Try #1:

for (Map<String ,dynamic> feature in json['features']) {
      listOfFeatures.add(Features.fromJson(feature));
    };

Added this to factory PropertyInformation:

features: listOfFeatures as Features,

When I execute the code now I get this error in the for statement, for (Map<String ,dynamic> feature in json[‘features’]) at the json[‘features’] part:
_TypeError (type ‘_Map<String, dynamic>’ is not a subtype of type ‘Iterable’)

Try #2:

    List<Features>? listOfFeatures = [];
    List<TaxAssessment>? listTaxAssessment = [];
    List<PropertyTax>? listPropertyTax = [];

    Map<String, dynamic> taxAssessmentMap = json['taxAssessment'];
    Map<String, dynamic> propertyTaxMap = json['propertyTaxes'];
    Map<String, dynamic> featureMap = json['features'];

    if (featureMap.isEmpty == false) {
      for (Map<String, dynamic> feature in json['features']) {
        listOfFeatures.add(Features.fromJson(feature));
      }
    }

This skips the for loop but then I don’t know what to do with
features:

features: featureMap, <<< This throws an error
      // features: Map.from(json['features']).map((k, v) =>
      //     MapEntry<String?, Features>(
      //         k, Features.fromJson(v as Map<String?, dynamic>))),

How do I handle a JSON such as "features" is a Map of 0 items?

2

Answers


  1. You have a few mistakes in your code:

    Wrong PropertyInformation.fromJson.
    You try to parse features like a List but it isn’t it. Based on your business logic you can have this solution:
    just replace this:

    if (featureList.isEmpty == false) {
        for (Map<String, dynamic> feature in json['features']) {      
            listOfFeatures.add(Features.fromJson(feature));
        }
    }
    

    with this:

    final feature = Feature.fromJson(json['features'] as Map<String, dynamic>);
    

    But your example has also a lot of problem with:

    1. Handling null ( when you decode json you have to check null before you try to decode fromJson )
    2. You use Map<String?, dynamic> instead of Map<String, dynamic> – just replace it because in real world json every time is Map<String, dynamic>.
    3. in PropertyInformation.toJson you try to work with features such us nullable variable but this isn’t it.
    Login or Signup to reply.
  2. Yeah there’s two issues one is stated by the above answer and other one is you’re trying to add null value which is not nullable.

    There’s just small changes to solve it. you need to make these

    Features features;
    TaxAssessment taxAssessment;
    PropertyTax propertyTaxes;
    

    PropertyInformation class variables nullable. just replace them. with these:

    Features? features;
    TaxAssessment? taxAssessment;
    PropertyTax? propertyTaxes;
    

    That means you’re ensuring these field can be null as your getting nothing in the Feature it’s null.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search