Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] [dart-dio] No builder factory for BuiltMap<String, JsonObject> #6951

Closed
flipch opened this issue Jul 15, 2020 · 11 comments · Fixed by #11011
Closed

[BUG] [dart-dio] No builder factory for BuiltMap<String, JsonObject> #6951

flipch opened this issue Jul 15, 2020 · 11 comments · Fixed by #11011

Comments

@flipch
Copy link

flipch commented Jul 15, 2020

Description

When describing an object whose type is a List<Dictionary<string, object>> dart-dio fails to generate a proper serializor prompting an exception

Deserializing '[a.b, 123]' to 'BuiltMap<String, JsonObject>' failed due to: Bad state: No builder factory for BuiltMap<String, JsonObject>. Fix by adding one, see SerializersBuilder.addBuilderFactory.
openapi-generator version

"@openapitools/openapi-generator-cli": "~1.0.13-4.3.1"

OpenAPI declaration file content or url
"ModelThatFails": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": {
                "type": "object",
                "additionalProperties": false
              }
            },
            "nullable": true
          }
        },
        "additionalProperties": false
      },
Command line used for generation

Options besides this only include the swagger file location and package name/version.
openapi-generator generate --enable-post-process-file -o headset_mobile_api

Steps to reproduce

Include that model and generate the dart code. Try and deserialize it with this example input
'[a.b, 123]'

Related issues/PRs
Suggest a fix

It seems the issue is within the Built_Value serializor or the Model that got generated. Not too knowledgeable in mustache templating

@kuhnroyal
Copy link
Contributor

Can you test this on master?

@kuhnroyal
Copy link
Contributor

Tested this on master:

import 'package:built_collection/built_collection.dart';
import 'package:built_value/json_object.dart';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';

part 'model_that_fails.g.dart';

abstract class ModelThatFails implements Built<ModelThatFails, ModelThatFailsBuilder> {

    @nullable
    @BuiltValueField(wireName: r'data')
    BuiltList<BuiltMap<String, JsonObject>> get data;

    // Boilerplate code needed to wire-up generated code
    ModelThatFails._();

    factory ModelThatFails([updates(ModelThatFailsBuilder b)]) = _$ModelThatFails;
    static Serializer<ModelThatFails> get serializer => _$modelThatFailsSerializer;
}

It also generated this builder factory in serializers.g.dart:

      ..addBuilderFactory(
          const FullType(BuiltList, const [
            const FullType(BuiltMap,
                const [const FullType(String), const FullType(JsonObject)])
          ]),
          () => new ListBuilder<BuiltMap<String, JsonObject>>())

Looks like this is what you were missing.

@flipch
Copy link
Author

flipch commented Dec 23, 2020

I'll have to test and get back at you. Thank you for investigating on your end.

What exactly did you meann with > Looks like this is what you were missing.

@kuhnroyal
Copy link
Contributor

I was talking about the builder factory above. Judging from your issue in built_value this is the one that was missing. Now it is being generated as far as I can tell.

@wing328 wing328 closed this as completed Jan 22, 2021
@Tomucha
Copy link

Tomucha commented Jun 30, 2021

I'm not sure how is this fixed or what's the workaround, but I'm getting the same issue with the latest openapi-generator-cli-5.1.1.jar

@flipch Is it working for you?

@kuhnroyal
Copy link
Contributor

If you are missing a builder factory, you can always add it manually to the serializers and pass the result to your API constructor.

If you have a spec that causes missing builder factories then please share.

@Tomucha
Copy link

Tomucha commented Jun 30, 2021

I have this model object:

    ListResultDTO:
      required:
      - list
      type: object
      properties:
        list:
          type: array
          items:
            type: object
            additionalProperties: true
        page:
          type: integer
          format: int32
        pageSize:
          type: integer
          format: int32

And the resulting Dart object cannot be deserialized:

Deserializing '[list, [{id: nMYzesVjNd, entityType: persons, displayName: Tomáš Z.}], page, ...' to 'ListResultDTO' failed due to: Deserializing '[{id: nMYzesVjNd, entityType: persons, displayName: Tomáš Z.}]' to 'BuiltList<BuiltMap<String, JsonObject>>' failed due to: Deserializing '[id, nMYzesVjNd, entityType, persons, displayName, Tomáš Z.]' to 'BuiltMap<String, JsonObject>' failed due to: Bad state: No builder factory for BuiltMap<String, JsonObject>. Fix by adding one, see SerializersBuilder.addBuilderFactory.

Created ListResultDTO contains this:

  @override
  ListResultDTO deserialize(
      Serializers serializers, Iterable<Object> serialized,
      {FullType specifiedType = FullType.unspecified}) {
    final result = ListResultDTOBuilder();

    final iterator = serialized.iterator;
    while (iterator.moveNext()) {
      final key = iterator.current as String;
      iterator.moveNext();
      final dynamic value = iterator.current;
      switch (key) {
        case r'list':
          result.list.replace(serializers.deserialize(value,
              specifiedType: const FullType(BuiltList, [
                FullType(BuiltMap, [FullType(String), FullType(JsonObject)])
              ])) as BuiltList<BuiltMap<String, JsonObject>>);
          break;
        case r'page':
          result.page = serializers.deserialize(value,
              specifiedType: const FullType(int)) as int;
          break;
        case r'pageSize':
          result.pageSize = serializers.deserialize(value,
              specifiedType: const FullType(int)) as int;
          break;
      }
    }
    return result.build();
  }

So it seem to me it's the same issue: No builder factory for BuiltMap<String, JsonObject> ... I'm not sure how to add it :-/ ?

@Tomucha
Copy link

Tomucha commented Jun 30, 2021

OK I have it, in my case I need to add:

  var customSerializers = (standardSerializers.toBuilder()
        ..addBuilderFactory(const FullType(BuiltMap, const [const FullType(String), const FullType(JsonObject)]),
            () => MapBuilder<String, JsonObject>()))
      .build();

   return MyApiClient(dio: ..., serializers: customSerializers);

I guess it should be part of the "default" build.

@kuhnroyal
Copy link
Contributor

Glad that your workaround works, I will check out what is missing later.

@tristanduyvejonck-wk
Copy link

tristanduyvejonck-wk commented Nov 15, 2021

This is still an issue, though the current workaround still is sufficient. Is it possible to open this back up?

@kuhnroyal
Copy link
Contributor

Could you guys try the fix from the PR branch please.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants