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
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:
with this:
But your example has also a lot of problem with:
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
PropertyInformation
class variables nullable. just replace them. with these:That means you’re ensuring these field can be null as your getting nothing in the
Feature
it’s null.