lrhn / json-tool

Dart Package with experimental JSON tools.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

JsonReader.hasNext should work in object

xvrh opened this issue · comments

Could hasNext also work for object keys?

So we could read an object like this:

    reader.expectObject();
    while (reader.hasNext()) {
      switch (reader.nextKey()) {
        case 'a':
          //...
          break;
        default:
          reader.skipAnyValue();
      }
    }
    reader.endObject();

I would like to convert some code written for the moshi parser but I'm not sure how to convert code like this with the current api:
https://github.com/xvrh/lottie-flutter/blob/master/lib/src/parser/animatable_transform_parser.dart#L34

The code here works for an JSON object (aka. a Dart Map<String,?>).

The JSON object reader is not intended as as general Dart data structure traversal. The API is tuned to JSON-like structures.

I think that you're asking for a way to reflectively introspect arbitrary objects, and that is definitely not going to happen here.
That would require dart:mirrors.
If you have an interface that you want to treat as if it was a JSON object (with string-key/JSON-value properties), then you can write your own JsonReader for it, but there won't be any automatic "Object reader" which can do that for any object.

Sorry for the confusion. This is not related to introspection or dart:mirrors.

This is just a question about the design of the API to parse a JSON object.

From what I understand, currently if I want to read a JSON object:

void main() {
  var reader = JsonReader.fromString('{"foo": 1, "bar": 2}');
  num foo, bar;

  reader.expectObject();
  loop:
  while (true) {
    switch (reader.tryKey(['bar', 'foo'])) {
      case 'foo':
        foo = reader.expectNum();
        break;
      case 'bar':
        bar = reader.expectNum();
        break;
      default:
        if (!reader.skipObjectEntry()) break loop;
    }
  }

  print('$foo $bar');
}

Can we simplify this code? For example:

  • No need to repeat the keys twice (in tryKey and switch)
  • Remove the label on the loop.

I was able to write it like that:

void main() {
  var reader = JsonReader.fromString('{"foo": 1, "bar": 2}');
  num foo, bar;

  reader.expectObject();

  String key;
  while ((key = reader.nextKey()) != null) {
    switch (key) {
      case 'foo':
        foo = reader.expectNum();
        break;
      case 'bar':
        bar = reader.expectNum();
        break;
      default:
        reader.skipAnyValue();
        break;
    }
  }

  print('$foo $bar');
}

But it requires a temporary key variable.
I was hoping for something like that:

void main() {
  var reader = JsonReader.fromString('{"foo": 1, "bar": 2}');

  num foo, bar;

  reader.expectObject();
  while (reader.hasNext()) {
    switch (reader.nextKey()) { // ERROR
      case 'foo':
        foo = reader.expectNum();
        break;
      case 'bar':
        bar = reader.expectNum();
        break;
      default:
        reader.skipAnyValue();
        break;
    }
  }

  print('$foo $bar');
}

Anyway, it's not very important.
I just had this question when I tried to convert some code written for a similar JSON parser.

Considering whether to add a hasNextKey method.
The design issue is that when it answer false, it's not clear whether that should close the object immediately, or leave it for you to do manually afterwards. It probably should close, so you can do a loop like:

while (r. hasNextKey()) {  
  result[r.nextKey()] = getValue(r);
}

The approach I used to use was:

String? key;
while ((key = r.nextKey()) != null) {
  result[key] = getValue(r);
}

but that doesn't work well with null safety.

Added hasNextKey in version 1.1.0.