question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[BUG][Dart] Generator creates a model class name that conflicts with a core lib class name (Type)

See original GitHub issue

Bug Report Checklist

  • Have you provided a full/minimal spec to reproduce the issue? Yes:
  • Have you validated the input using an OpenAPI validator (example)?
  • Have you tested with the latest master to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What’s the actual output vs expected output?
  • [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description

When generating Dart code, an OAS is using a reserved(ish) word (Type) which the generator defines a class for which then conflicts and causes errors. (It’s not technically a reserved word of the language, it’s a class in the core library. Something that’s always available and you can’t import it with a namespace)

image

openapi-generator version

5.1.0 release on both dart-dio and dart-dio-next

OpenAPI declaration file content or url

https://cdn-prod.wdesk.com/endpoints-admin/1.342.0/openapi/platform-v1.yaml

Problem arises from line 813

Generation Details

I used the jar release for 5.1.0 with this command: java -jar openapi-generator-cli.jar generate -i https://cdn-prod.wdesk.com/endpoints-admin/1.342.0/openapi/platform-v1.yaml -g dart-dio -o ./ --additional-properties="pubDescription=Workiva Platform API (Dart),pubName=wk,pubVersion=1.0.0"

Steps to reproduce

Generate Dart code with the above command. Have Dart installed (2.12.2) Then run pub get pub run build_runner build --delete-conflicting-outputs -o build (then remove the build directory … you only need to run a build to do built_value code generation Then either open in an IDE with the Dart plugin (VS Code, intelliJ) or just run dartanalyzer . which will show the errors.

Related issues/PRs
Suggest a fix

I’m not actually sure what a good fix would be. I might actually prefer if generation failed when creating the code and suggested a way to work around it, possibly by using the [--reserved-words-mappings <reserved word mappings>...] option ?

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:14 (7 by maintainers)

github_iconTop GitHub Comments

2reactions
lam-nvcommented, Apr 12, 2021

Hi @kuhnroyal

I have an issue with imports in *_api.dart (generated by .templates/dart-dio/api.mustache), see details below:

.templates/dart-dio/api.mustache

{{>header}}
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:built_value/serializer.dart';

{{#operations}}
{{#imports}}import '{{.}}';
{{/imports}}

class {{classname}} {

  final Dio _dio;

  final Serializers _serializers;

  const {{classname}}(this._dio, this._serializers);

  {{#operation}}
  /// {{{summary}}}
  ///
  /// {{{notes}}}
  Future<Response<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}}>> {{nickname}}({{^hasRequiredParams}}{ {{/hasRequiredParams}}{{#requiredParams}}
    {{{dataType}}} {{paramName}},{{#-last}} { {{/-last}}{{/requiredParams}}{{#optionalParams}}
    {{{dataType}}} {{paramName}},{{/optionalParams}}
    CancelToken cancelToken,
    Map<String, dynamic> headers,
    Map<String, dynamic> extra,
    ValidateStatus validateStatus,
    ProgressCallback onSendProgress,
    ProgressCallback onReceiveProgress,
  }) async {
    final _request = RequestOptions(
      path: r'{{{path}}}'{{#pathParams}}.replaceAll('{' r'{{{baseName}}}' '}', {{{paramName}}}.toString()){{/pathParams}},
      method: '{{#lambda.uppercase}}{{httpMethod}}{{/lambda.uppercase}}',
      {{#isResponseFile}}
      responseType: ResponseType.bytes,
      {{/isResponseFile}}
      headers: <String, dynamic>{
        {{#httpUserAgent}}
        r'User-Agent': r'{{{.}}}',
        {{/httpUserAgent}}
        {{#headerParams}}
        {{^required}}{{^nullable}}if ({{{paramName}}} != null) {{/nullable}}{{/required}}r'{{baseName}}': {{paramName}},
        {{/headerParams}}
        ...?headers,
      },
      {{#hasQueryParams}}
      queryParameters: <String, dynamic>{
        {{#queryParams}}
        {{^required}}{{^nullable}}if ({{{paramName}}} != null) {{/nullable}}{{/required}}r'{{baseName}}': {{paramName}},
        {{/queryParams}}
      },
      {{/hasQueryParams}}
      extra: <String, dynamic>{
        'secure': <Map<String, String>>[{{^hasAuthMethods}}],{{/hasAuthMethods}}{{#hasAuthMethods}}
          {{#authMethods}}{
            'type': '{{type}}',
            'name': '{{name}}',{{#isApiKey}}
            'keyName': '{{keyParamName}}',
            'where': '{{#isKeyInQuery}}query{{/isKeyInQuery}}{{#isKeyInHeader}}header{{/isKeyInHeader}}',{{/isApiKey}}
          },{{/authMethods}}
        ],{{/hasAuthMethods}}
        ...?extra,
      },
      validateStatus: validateStatus,
      contentType: [{{^hasConsumes}}
        'application/json',{{/hasConsumes}}{{#hasConsumes}}{{#consumes}}
        '{{{mediaType}}}',{{/consumes}}{{/hasConsumes}}
      ].first,
      cancelToken: cancelToken,
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
    );

    dynamic _bodyData;
    {{#hasFormParams}}

    _bodyData = {{#isMultipart}}FormData.fromMap({{/isMultipart}}<String, dynamic>{
      {{#formParams}}
      {{^required}}{{^nullable}}if ({{{paramName}}} != null) {{/nullable}}{{/required}}r'{{{baseName}}}': {{#isFile}}MultipartFile.fromBytes({{{paramName}}}, filename: r'{{{baseName}}}'){{/isFile}}{{^isFile}}encodeFormParameter(_serializers, {{{paramName}}}, const FullType({{^isContainer}}{{{baseType}}}{{/isContainer}}{{#isContainer}}Built{{#isMap}}Map{{/isMap}}{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}, [{{#isMap}}FullType(String), {{/isMap}}FullType({{{baseType}}})]{{/isContainer}})){{/isFile}},
      {{/formParams}}
    }{{#isMultipart}}){{/isMultipart}};
    {{/hasFormParams}}
    {{#bodyParam}}

    {{#isPrimitiveType}}
    _bodyData = {{paramName}};
    {{/isPrimitiveType}}
    {{^isPrimitiveType}}
    {{#isContainer}}
    const _type = FullType(Built{{#isMap}}Map{{/isMap}}{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}, [{{#isMap}}FullType(String), {{/isMap}}FullType({{{baseType}}})]);
    _bodyData = _serializers.serialize({{paramName}}, specifiedType: _type);
    {{/isContainer}}
    {{^isContainer}}
    const _type = FullType({{{baseType}}});
    _bodyData = _serializers.serialize({{paramName}}, specifiedType: _type);
    {{/isContainer}}
    {{/isPrimitiveType}}
    {{/bodyParam}}

    final _response = await _dio.request<dynamic>(
      _request.path,
      data: _bodyData,
      options: _request,
    );
    {{#returnType}}

    {{#isResponseFile}}
    final {{{returnType}}} _responseData = _response.data as {{{returnType}}};
    {{/isResponseFile}}
    {{^isResponseFile}}
    {{#returnSimpleType}}
    {{#returnTypeIsPrimitive}}
    final {{{returnType}}} _responseData = _response.data as {{{returnType}}};
    {{/returnTypeIsPrimitive}}
    {{^returnTypeIsPrimitive}}
    const _responseType = FullType({{{returnType}}});
    final _responseData = _serializers.deserialize(
      _response.data,
      specifiedType: _responseType,
    ) as {{{returnType}}};
    {{/returnTypeIsPrimitive}}
    {{/returnSimpleType}}
    {{^returnSimpleType}}
    const _responseType = FullType(Built{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}{{#isMap}}Map{{/isMap}}, [{{#isMap}}FullType(String), {{/isMap}}FullType({{{returnBaseType}}})]);
    final {{{returnType}}} _responseData = _serializers.deserialize(
      _response.data,
      specifiedType: _responseType,
    ) as {{{returnType}}};
    {{/returnSimpleType}}
    {{/isResponseFile}}

    return Response<{{{returnType}}}>(
      data: _responseData,
      headers: _response.headers,
      isRedirect: _response.isRedirect,
      request: _response.request,
      redirects: _response.redirects,
      statusCode: _response.statusCode,
      statusMessage: _response.statusMessage,
      extra: _response.extra,
    );{{/returnType}}{{^returnType}}
    return _response;{{/returnType}}
  }

  {{/operation}}
}
{{/operations}}

*_api.dart

// ignore_for_file: unused_import

import 'dart:async';
import 'package:dio/dio.dart';
import 'package:built_value/serializer.dart';


import '{import&#x3D;lib.model.Body, classname&#x3D;Body}';
import '{import&#x3D;lib.model.Body1, classname&#x3D;Body1}';
import '{import&#x3D;lib.model.Body10, classname&#x3D;Body10}';
import '{import&#x3D;lib.model.Body11, classname&#x3D;Body11}';
import '{import&#x3D;lib.model.Body12, classname&#x3D;Body12}';
import '{import&#x3D;lib.model.Body13, classname&#x3D;Body13}';
import '{import&#x3D;lib.model.Body15, classname&#x3D;Body15}';
import '{import&#x3D;lib.model.Body2, classname&#x3D;Body2}';
import '{import&#x3D;lib.model.Body3, classname&#x3D;Body3}';
import '{import&#x3D;lib.model.Body4, classname&#x3D;Body4}';
import '{import&#x3D;lib.model.Body5, classname&#x3D;Body5}';
import '{import&#x3D;lib.model.Body6, classname&#x3D;Body6}';
import '{import&#x3D;lib.model.Body7, classname&#x3D;Body7}';
import '{import&#x3D;lib.model.Body8, classname&#x3D;Body8}';
import '{import&#x3D;lib.model.Body9, classname&#x3D;Body9}';
import '{import&#x3D;lib.model.InlineResponse200, classname&#x3D;InlineResponse200}';
import '{import&#x3D;lib.model.InlineResponse2001, classname&#x3D;InlineResponse2001}';
import '{import&#x3D;lib.model.InlineResponse20010, classname&#x3D;InlineResponse20010}';
import '{import&#x3D;lib.model.InlineResponse20011, classname&#x3D;InlineResponse20011}';
import '{import&#x3D;lib.model.InlineResponse20012, classname&#x3D;InlineResponse20012}';
import '{import&#x3D;lib.model.InlineResponse20013, classname&#x3D;InlineResponse20013}';
import '{import&#x3D;lib.model.InlineResponse20015, classname&#x3D;InlineResponse20015}';
import '{import&#x3D;lib.model.InlineResponse2002, classname&#x3D;InlineResponse2002}';
import '{import&#x3D;lib.model.InlineResponse2003, classname&#x3D;InlineResponse2003}';
import '{import&#x3D;lib.model.InlineResponse2004, classname&#x3D;InlineResponse2004}';
import '{import&#x3D;lib.model.InlineResponse2005, classname&#x3D;InlineResponse2005}';
import '{import&#x3D;lib.model.InlineResponse2006, classname&#x3D;InlineResponse2006}';
import '{import&#x3D;lib.model.InlineResponse2007, classname&#x3D;InlineResponse2007}';
import '{import&#x3D;lib.model.InlineResponse2008, classname&#x3D;InlineResponse2008}';
import '{import&#x3D;lib.model.InlineResponse2009, classname&#x3D;InlineResponse2009}';
import '{import&#x3D;lib.model.InlineResponse503, classname&#x3D;InlineResponse503}';

class AuthenticationApi {

  final Dio _dio;

  final Serializers _serializers;

config.yaml

generatorName: dart-dio
inputSpec: spec.yaml
outputFolder: .
templateDir: .templates/dart-dio
pubName: openapi
pubLibrary: openapi
useEnumExtension: true
serializationLibrary: built_value
additionalProperties:
  clientName: openApi
  serializableModel: "true"
  dateLibrary: core
  # # dateLibrary: timeMachine
  hideGenerationTimestamp: "true"
  useBuiltValue: "true"
typeMappings:
  Array: BuiltList
  array: BuiltList
  List: BuiltList
  set: BuiltSet
  map: BuiltMap
  file: Uint8List
  binary: Uint8List
  object: JsonObject
  AnyType: JsonObject
  Type: RecordType

generator version is 5.1.0

.Could you have a look? or help me correct it?

1reaction
kuhnroyalcommented, Apr 13, 2021

Whatever works for you. You can also always use docker with the cli-latest tag: https://hub.docker.com/r/openapitools/openapi-generator

Read more comments on GitHub >

github_iconTop Results From Across the Web

[BUG][dart][dart-dio] "--api-name-suffix" and "--model ... - GitHub
Have you validated the input using an OpenAPI validator (example)?; What's the version of OpenAPI Generator used? Have you search for related ...
Read more >
symfony make:entity crash on new project - Stack Overflow
This project is very new and there is very few code at the moment; It's the first entity I try to create in...
Read more >
flutter/flutter - Gitter
I'm setting up a timer within a stateless widget, can I just pass the BuildContext used in the Widget build(BuildContext context) method and ......
Read more >
9 - How to solve this error "Class \Drupal\simple_sitemap ...
I cannot login to the interface so I ran /core/rebuild.php but it doesn't solve it. When I ran drush cr on the command...
Read more >
Generate CRUD Class from Stubs: Livewire example - YouTube
Let's review a Livewire CRUD simple generator from an open-source repository.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found