user2070136
user2070136

Reputation: 21

How to end up with a strongly typed list of objects from a json string using Dart?

I'm just beginning to learn dart and I'm wanting to try to create a simple list of objects from a json string. I'm using the AngularJS phonecat tutorial to try and convert it to Dart... so given that, in my dart file I have this....

import "dart:json" as json;
import "package:json_object/json_object.dart";

String jsonPhones = """
  [{"name": "Nexus S",
    "snippet": "Fast just got faster with Nexus S."},
   {"name": "Motorola XOOM™ with Wi-Fi",
    "snippet": "The Next, Next Generation tablet."},
   {"name": "MOTOROLA XOOM™",
    "snippet": "The Next, Next Generation tablet."}]
""";


class Phone {
  String name;
  String snippet;
}

class PhoneImpl extends JsonObject implements Phone {
  PhoneImpl();

  factory PhoneImpl.fromJsonString(string) {
    return new JsonObject.fromJsonString(string, new PhoneImpl());
  }
}

List<Phone> Phones;

void main() {
  PhoneImpl pi = new PhoneImpl.fromJsonString(jsonPhones);
  for(var i = 0; i < pi.length; i++) {
    print(pi[i].name);
  }
}

So, when I run this, it prints the name of each phone. But, if I try Phones.add(pi[i]) I get an error of type 'noSuchMethod()' on the member name add. I assume that pi[i] at this point is a JsonObject and will not automatically convert to type Phone. Ultimately what I'm trying to do is use...

<li template iterate="phone in Phones"> 

in the html to iterate through the phones. I've tried doing this with the PhoneImpl but then I get another error saying NoSuchMethodError memberName "containsKey". So I'm assuming that I need to figure out a way to get my list from PhoneImpl to List and so far I seem to be getting nowhere fast. Also, I'd rather not have to extend all of my models with JsonObject. In fact, I've also tried doing all of this with out the json_object package, and still can't seem to get it to work.

Upvotes: 1

Views: 487

Answers (3)

Daniel Rodriguez
Daniel Rodriguez

Reputation: 1483

Give this library a try. It uses reflection to do what you want, but because Dart only has an async API for reading and setting values using reflection, you wave to wait for the returned future to complete.

https://github.com/chrisbu/dartwatch-JsonObject

Upvotes: 0

Chris Buckett
Chris Buckett

Reputation: 14398

tjameson's answer is the approach I would take at the moment, but here is some background on the issues you're having with JsonObject.

Part of the problem that you are having is that although JsonObject does convert a list of Json objects into a list, JsonObject itself does not implement the List interface.

The line:

PhoneImpl pi = new PhoneImpl.fromJsonString(jsonPhones);

actually causes pi to contain a list of JsonObjects, rather than a single JsonOjbect. Then, when the phone in phones iterator tries to iterate that list, it can't find an iterator object (because JsonObject doesn't implement the List interface - feel free to raise an issue so I can track it - and add support.

If you're interested in using mirrors, then there is an experimental mirrors API for JsonObject in this branch

Upvotes: 0

beatgammit
beatgammit

Reputation: 20215

This is the way I'd approach it:

import "dart:json";

String jsonPhones = """
  [{"name": "Nexus S",
    "snippet": "Fast just got faster with Nexus S."},
   {"name": "Motorola XOOM™ with Wi-Fi",
    "snippet": "The Next, Next Generation tablet."},
   {"name": "MOTOROLA XOOM™",
    "snippet": "The Next, Next Generation tablet."}]
""";

class Phone {
  String name;
  String snippet;

  Phone(this.name, this.snippet);
}

List<Phone> Phones;
void main() {
  Phones = parse(jsonPhones).map((e) => new Phone(e["name"], e["snippet"]);
  // do something with Phones...
}

In this case, parse() will return a List, but that isn't always true, so in production, I'd recommend doing a check on parse() to make sure you're actually getting what you expect. This pattern obviates your PhoneImpl class, which seems like it was only a shim anyway.

The Dart team will hopefully implement reflection so this can be nicer and marshal directly to a Phone instance, but that hasn't been done yet.

Upvotes: 3

Related Questions