Using StandardJsonPlugin with built_value for Flutter

Or why do I get type '_InternalLinkedHashMap' is not a subtype of type 'Iterable' in type cast error when deserializing json objects using built_value.

TL;DR jump to the solution.


The setup

When using built_value in a project, what I find useful is to use the json to built_value tool in order to create my model from a json I already have from the REST API.

For our example let’s use the default json the tool prefills.

 {
      "id": 157538,
      "date": "2017-07-21T10:30:34",
      "date_gmt": "2017-07-21T17:30:34",
      "type": "post",
      "link": "https://example.com",
      "title": {
          "rendered": "Json 2 dart built_value converter"
      },
      "tags": [
          1798,
          6298
      ]
}

This json will produce the following model.

In addition, you have to register the above model types in your Serializers instance.

Run the generator

Once everything is setup you need to run the built_value‘s generator to generate the .g.dart files with the following command:

flutter packages pub run build_runner build

The error

After you have successfully generated the serialization code you can test it out with a very simple test.

void main() {
  test('should deserialize sucessfully', () {
    final json = "{\"id\":157538,\"date\":\"2017-07-21T10:30:34\",\"date_gmt\":\"2017-07-21T17:30:34\",\"type\":\"post\",\"link\":\"https://example.com\",\"title\":{\"rendered\":\"Json 2 dart built_value converter\"},\"tags\":[1798,6298]}";

    RootDto.fromJson(json);
  });
}

Running the above test will produce the following, infamous by now, error:

Deserializing '{id: 157538, date: 2017-07-21T10:30:34, date_gmt: 2017-07-21T17:30:34, type: ...' to 'RootDto' failed due to: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Iterable<dynamic>' in type cast

The cause

If you follow the stack you will find that it originates from in BuiltJsonSerializers._deserialize method and more specifically in line 153 of package:built_value/src/built_json_serializers.dart. In that line, the library tries to cast the object as an Iterable, but it finds an _InternalLinkedHashMap.

serializer.deserialize(this, object as Iterable, specifiedType: specifiedType);

The solution

Add the StandardJsonPlugin to the Serializers.

final Serializers serializers = (_$serializers.toBuilder()..addPlugin(StandardJsonPlugin())).build();

This plugin will actually convert the Map to a list in its beforeDeserialize method. This way the serializer will always have an Iterable to process and will not fail the cast.


Bottom line, always register the StandardJsonPlugin in your Serializers instance, when you are deserializing a json you got over the wire.

Please follow and like us:
error