[dart] type improvements (#8111)

* [dart] Configure and use import mapping

This prevents models from being generated which would clash with exisiting dart types, e.g. List.

* [dart] Fix decimal format not supported

* [dart-dio] Remove redundant modelToIgnore & ignore dart:core import

* modelToIgnore is now handled via importMappings the same way other generators do this
* choose not to import dart:core as this is available by default

* [dart-dio] EnumClass is a reserved word in built_value

* Review changes

* Fix regenerate docs
This commit is contained in:
Peter Leibiger
2020-12-08 05:00:12 +01:00
committed by GitHub
parent 99d83712a8
commit 7fae4ab411
27 changed files with 121 additions and 237 deletions

View File

@@ -33,8 +33,19 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|BuiltList|package:built_collection/built_collection.dart|
|BuiltMap|package:built_collection/built_collection.dart|
|BuiltSet|package:built_collection/built_collection.dart|
|DateTime|dart:core|
|JsonObject|package:built_value/json_object.dart|
|List|dart:core|
|Map|dart:core|
|Object|dart:core|
|Set|dart:core|
|String|dart:core|
|Uint8List|dart:typed_data|
|bool|dart:core|
|double|dart:core|
|dynamic|dart:core|
|int|dart:core|
|num|dart:core|
## INSTANTIATION TYPES

View File

@@ -30,6 +30,17 @@ These options may be applied as additional-properties (cli) or configOptions (pl
| Type/Alias | Imports |
| ---------- | ------- |
|DateTime|dart:core|
|List|dart:core|
|Map|dart:core|
|Object|dart:core|
|Set|dart:core|
|String|dart:core|
|bool|dart:core|
|double|dart:core|
|dynamic|dart:core|
|int|dart:core|
|num|dart:core|
## INSTANTIATION TYPES

View File

@@ -28,6 +28,17 @@ These options may be applied as additional-properties (cli) or configOptions (pl
| Type/Alias | Imports |
| ---------- | ------- |
|DateTime|dart:core|
|List|dart:core|
|Map|dart:core|
|Object|dart:core|
|Set|dart:core|
|String|dart:core|
|bool|dart:core|
|double|dart:core|
|dynamic|dart:core|
|int|dart:core|
|num|dart:core|
## INSTANTIATION TYPES

View File

@@ -36,7 +36,6 @@ import com.google.common.collect.Sets;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.CodegenConfig;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.CodegenModel;
import org.openapitools.codegen.CodegenProperty;
@@ -56,7 +55,7 @@ import org.slf4j.LoggerFactory;
import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.Schema;
public class DartClientCodegen extends DefaultCodegen implements CodegenConfig {
public class DartClientCodegen extends DefaultCodegen {
private static final Logger LOGGER = LoggerFactory.getLogger(DartClientCodegen.class);
public static final String PUB_LIBRARY = "pubLibrary";
@@ -161,8 +160,7 @@ public class DartClientCodegen extends DefaultCodegen implements CodegenConfig {
typeMapping.put("number", "num");
typeMapping.put("float", "double");
typeMapping.put("double", "double");
typeMapping.put("object", "Object");
typeMapping.put("AnyType", "Object");
typeMapping.put("decimal", "double");
typeMapping.put("integer", "int");
typeMapping.put("Date", "DateTime");
typeMapping.put("date", "DateTime");
@@ -171,6 +169,24 @@ public class DartClientCodegen extends DefaultCodegen implements CodegenConfig {
typeMapping.put("UUID", "String");
typeMapping.put("URI", "String");
typeMapping.put("ByteArray", "String");
typeMapping.put("object", "Object");
typeMapping.put("AnyType", "Object");
// These are needed as they prevent models from being generated
// which would clash with existing types, e.g. List
// Importing dart:core doesn't hurt but a subclass may choose to skip
// dart:core imports.
importMapping.put("dynamic", "dart:core");
importMapping.put("Object", "dart:core");
importMapping.put("String", "dart:core");
importMapping.put("bool", "dart:core");
importMapping.put("num", "dart:core");
importMapping.put("int", "dart:core");
importMapping.put("double", "dart:core");
importMapping.put("List", "dart:core");
importMapping.put("Map", "dart:core");
importMapping.put("Set", "dart:core");
importMapping.put("DateTime", "dart:core");
cliOptions.add(new CliOption(PUB_LIBRARY, "Library name in generated code"));
cliOptions.add(new CliOption(PUB_NAME, "Name in generated pubspec"));

View File

@@ -16,8 +16,7 @@
package org.openapitools.codegen.languages;
import java.util.HashMap;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.CodegenConstants;
@@ -32,11 +31,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.*;
import io.swagger.v3.oas.models.media.Schema;
@@ -51,19 +46,10 @@ public class DartDioClientCodegen extends DartClientCodegen {
private static final String IS_FORMAT_JSON = "jsonFormat";
private static final String CLIENT_NAME = "clientName";
private static final Set<String> modelToIgnore = new HashSet<>();
static {
modelToIgnore.add("datetime");
modelToIgnore.add("map");
modelToIgnore.add("object");
modelToIgnore.add("list");
modelToIgnore.add("file");
modelToIgnore.add("uint8list");
}
private boolean nullableFields = true;
private String dateLibrary = "core";
private static final Set<String> reservedBuiltValueWords = Sets.newHashSet("EnumClass");
public DartDioClientCodegen() {
super();
@@ -116,6 +102,11 @@ public class DartDioClientCodegen extends DartClientCodegen {
return "Generates a Dart Dio client library.";
}
@Override
protected boolean isReservedWord(String word) {
return super.isReservedWord(word) || reservedBuiltValueWords.contains(word);
}
@Override
public String toDefaultValue(Schema schema) {
if (ModelUtils.isMapSchema(schema)) {
@@ -270,12 +261,13 @@ public class DartDioClientCodegen extends DartClientCodegen {
Set<String> modelImports = new HashSet<>();
CodegenModel cm = (CodegenModel) mo.get("model");
for (String modelImport : cm.imports) {
if (importMapping.containsKey(modelImport)) {
modelImports.add(importMapping.get(modelImport));
} else {
if (!modelToIgnore.contains(modelImport.toLowerCase(Locale.ROOT))) {
modelImports.add("package:" + pubName + "/model/" + underscore(modelImport) + ".dart");
if (importMapping().containsKey(modelImport)) {
final String value = importMapping().get(modelImport);
if (!Objects.equals(value, "dart:core")) {
modelImports.add(value);
}
} else {
modelImports.add("package:" + pubName + "/model/" + underscore(modelImport) + ".dart");
}
}
@@ -362,10 +354,13 @@ public class DartDioClientCodegen extends DartClientCodegen {
Set<String> imports = new HashSet<>();
for (String item : op.imports) {
if (!modelToIgnore.contains(item.toLowerCase(Locale.ROOT))) {
if (importMapping().containsKey(item)) {
final String value = importMapping().get(item);
if (!Objects.equals(value, "dart:core")) {
fullImports.add(value);
}
} else {
imports.add(underscore(item));
} else if (item.equalsIgnoreCase("Uint8List")) {
fullImports.add("dart:typed_data");
}
}
modelImports.addAll(imports);

View File

@@ -37,6 +37,8 @@ public class DartModelTest {
.addProperties("name", new StringSchema())
.addProperties("createdAt", new DateTimeSchema())
.addProperties("defaultItem", new IntegerSchema()._default(1))
.addProperties("number", new NumberSchema())
.addProperties("decimal", new StringSchema().format("number"))
.addRequiredItem("id")
.addRequiredItem("name");
final DefaultCodegen codegen = new DartClientCodegen();
@@ -47,9 +49,7 @@ public class DartModelTest {
Assert.assertEquals(cm.name, "sample");
Assert.assertEquals(cm.classname, "Sample");
Assert.assertEquals(cm.description, "a sample model");
Assert.assertEquals(cm.vars.size(), 4);
// {{imports}} is not used in template
//Assert.assertEquals(cm.imports.size(), 1);
Assert.assertEquals(cm.vars.size(), 6);
final CodegenProperty property1 = cm.vars.get(0);
Assert.assertEquals(property1.baseName, "id");
@@ -88,6 +88,16 @@ public class DartModelTest {
Assert.assertEquals(property4.baseType, "int");
Assert.assertFalse(property4.required);
Assert.assertFalse(property4.isContainer);
final CodegenProperty property5 = cm.vars.get(4);
Assert.assertEquals(property5.baseName, "number");
Assert.assertEquals(property5.dataType, "num");
Assert.assertEquals(property5.baseType, "num");
final CodegenProperty property6 = cm.vars.get(5);
Assert.assertEquals(property6.baseName, "decimal");
Assert.assertEquals(property6.dataType, "double");
Assert.assertEquals(property6.baseType, "double");
}
@Test(description = "convert a model with list property")

View File

@@ -18,7 +18,6 @@ doc/DefaultApi.md
doc/Dog.md
doc/DogAllOf.md
doc/EnumArrays.md
doc/EnumClass.md
doc/EnumTest.md
doc/FakeApi.md
doc/FakeClassnameTags123Api.md
@@ -35,10 +34,10 @@ doc/InlineObject3.md
doc/InlineObject4.md
doc/InlineObject5.md
doc/InlineResponseDefault.md
doc/List.md
doc/MapTest.md
doc/MixedPropertiesAndAdditionalPropertiesClass.md
doc/Model200Response.md
doc/ModelEnumClass.md
doc/ModelReturn.md
doc/Name.md
doc/NullableClass.md
@@ -85,7 +84,6 @@ lib/model/client.dart
lib/model/dog.dart
lib/model/dog_all_of.dart
lib/model/enum_arrays.dart
lib/model/enum_class.dart
lib/model/enum_test.dart
lib/model/file.dart
lib/model/file_schema_test_class.dart
@@ -100,10 +98,10 @@ lib/model/inline_object3.dart
lib/model/inline_object4.dart
lib/model/inline_object5.dart
lib/model/inline_response_default.dart
lib/model/list.dart
lib/model/map_test.dart
lib/model/mixed_properties_and_additional_properties_class.dart
lib/model/model200_response.dart
lib/model/model_enum_class.dart
lib/model/model_return.dart
lib/model/name.dart
lib/model/nullable_class.dart

View File

@@ -116,7 +116,6 @@ Class | Method | HTTP request | Description
- [Dog](doc//Dog.md)
- [DogAllOf](doc//DogAllOf.md)
- [EnumArrays](doc//EnumArrays.md)
- [EnumClass](doc//EnumClass.md)
- [EnumTest](doc//EnumTest.md)
- [File](doc//File.md)
- [FileSchemaTestClass](doc//FileSchemaTestClass.md)
@@ -131,10 +130,10 @@ Class | Method | HTTP request | Description
- [InlineObject4](doc//InlineObject4.md)
- [InlineObject5](doc//InlineObject5.md)
- [InlineResponseDefault](doc//InlineResponseDefault.md)
- [List](doc//List.md)
- [MapTest](doc//MapTest.md)
- [MixedPropertiesAndAdditionalPropertiesClass](doc//MixedPropertiesAndAdditionalPropertiesClass.md)
- [Model200Response](doc//Model200Response.md)
- [ModelEnumClass](doc//ModelEnumClass.md)
- [ModelReturn](doc//ModelReturn.md)
- [Name](doc//Name.md)
- [NullableClass](doc//NullableClass.md)

View File

@@ -14,7 +14,7 @@ Name | Type | Description | Notes
**number** | **num** | | [default to null]
**float** | **double** | | [optional] [default to null]
**double** | **double** | | [optional] [default to null]
**decimal** | [**Decimal**](Decimal.md) | | [optional] [default to null]
**decimal** | **double** | | [optional] [default to null]
**string** | **String** | | [optional] [default to null]
**byte** | **String** | | [default to null]
**binary** | [**Uint8List**](Uint8List.md) | | [optional] [default to null]

View File

@@ -1,15 +0,0 @@
# openapi.model.List
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**n123list** | **String** | | [optional] [default to null]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -1,4 +1,4 @@
# openapi.model.EnumClass
# openapi.model.ModelEnumClass
## Load the model package
```dart

View File

@@ -1,5 +1,4 @@
import 'dart:typed_data';
import 'package:openapi/model/decimal.dart';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
@@ -34,7 +33,7 @@ abstract class FormatTest implements Built<FormatTest, FormatTestBuilder> {
@nullable
@BuiltValueField(wireName: r'decimal')
Decimal get decimal;
double get decimal;
@nullable
@BuiltValueField(wireName: r'string')

View File

@@ -1,19 +0,0 @@
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
part 'list.g.dart';
abstract class List implements Built<List, ListBuilder> {
@nullable
@BuiltValueField(wireName: r'123-list')
String get n123list;
// Boilerplate code needed to wire-up generated code
List._();
factory List([updates(ListBuilder b)]) = _$List;
static Serializer<List> get serializer => _$listSerializer;
}

View File

@@ -2,23 +2,23 @@ import 'package:built_collection/built_collection.dart';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
part 'enum_class.g.dart';
part 'model_enum_class.g.dart';
class EnumClass extends EnumClass {
class ModelEnumClass extends EnumClass {
@BuiltValueEnumConst(wireName: '_abc')
static const EnumClass abc = _$abc;
static const ModelEnumClass abc = _$abc;
@BuiltValueEnumConst(wireName: '-efg')
static const EnumClass efg = _$efg;
static const ModelEnumClass efg = _$efg;
@BuiltValueEnumConst(wireName: '(xyz)')
static const EnumClass (xyz) = _$(xyz);
static const ModelEnumClass (xyz) = _$(xyz);
static Serializer<EnumClass> get serializer => _$enumClassSerializer;
static Serializer<ModelEnumClass> get serializer => _$enumClassSerializer;
const EnumClass._(String name): super(name);
const ModelEnumClass._(String name): super(name);
static BuiltSet<EnumClass> get values => _$values;
static EnumClass valueOf(String name) => _$valueOf(name);
static BuiltSet<ModelEnumClass> get values => _$values;
static ModelEnumClass valueOf(String name) => _$valueOf(name);
}
/// Optionally, enum_class can generate a mixin to go with your enum for use
@@ -27,5 +27,5 @@ class EnumClass extends EnumClass {
/// corresponding Angular template.
///
/// Trigger mixin generation by writing a line like this one next to your enum.
abstract class EnumClassMixin = Object with _$EnumClassMixin;
abstract class ModelEnumClassMixin = Object with _$ModelEnumClassMixin;

View File

@@ -21,7 +21,6 @@ import 'package:openapi/model/client.dart';
import 'package:openapi/model/dog.dart';
import 'package:openapi/model/dog_all_of.dart';
import 'package:openapi/model/enum_arrays.dart';
import 'package:openapi/model/enum_class.dart';
import 'package:openapi/model/enum_test.dart';
import 'package:openapi/model/file.dart';
import 'package:openapi/model/file_schema_test_class.dart';
@@ -36,10 +35,10 @@ import 'package:openapi/model/inline_object3.dart';
import 'package:openapi/model/inline_object4.dart';
import 'package:openapi/model/inline_object5.dart';
import 'package:openapi/model/inline_response_default.dart';
import 'package:openapi/model/list.dart';
import 'package:openapi/model/map_test.dart';
import 'package:openapi/model/mixed_properties_and_additional_properties_class.dart';
import 'package:openapi/model/model200_response.dart';
import 'package:openapi/model/model_enum_class.dart';
import 'package:openapi/model/model_return.dart';
import 'package:openapi/model/name.dart';
import 'package:openapi/model/nullable_class.dart';
@@ -75,7 +74,6 @@ Client,
Dog,
DogAllOf,
EnumArrays,
EnumClass,
EnumTest,
File,
FileSchemaTestClass,
@@ -90,10 +88,10 @@ InlineObject3,
InlineObject4,
InlineObject5,
InlineResponseDefault,
List,
MapTest,
MixedPropertiesAndAdditionalPropertiesClass,
Model200Response,
ModelEnumClass,
ModelReturn,
Name,
NullableClass,
@@ -160,9 +158,6 @@ const FullType(BuiltList, const [const FullType(DogAllOf)]),
const FullType(BuiltList, const [const FullType(EnumArrays)]),
() => new ListBuilder<EnumArrays>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(EnumClass)]),
() => new ListBuilder<EnumClass>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(EnumTest)]),
() => new ListBuilder<EnumTest>())
..addBuilderFactory(
@@ -205,9 +200,6 @@ const FullType(BuiltList, const [const FullType(InlineObject5)]),
const FullType(BuiltList, const [const FullType(InlineResponseDefault)]),
() => new ListBuilder<InlineResponseDefault>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(List)]),
() => new ListBuilder<List>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(MapTest)]),
() => new ListBuilder<MapTest>())
..addBuilderFactory(
@@ -217,6 +209,9 @@ const FullType(BuiltList, const [const FullType(MixedPropertiesAndAdditionalProp
const FullType(BuiltList, const [const FullType(Model200Response)]),
() => new ListBuilder<Model200Response>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(ModelEnumClass)]),
() => new ListBuilder<ModelEnumClass>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(ModelReturn)]),
() => new ListBuilder<ModelReturn>())
..addBuilderFactory(

View File

@@ -1,11 +0,0 @@
import 'package:openapi/model/enum_class.dart';
import 'package:test/test.dart';
// tests for EnumClass
void main() {
group(EnumClass, () {
});
}

View File

@@ -1,17 +0,0 @@
import 'package:openapi/model/list.dart';
import 'package:test/test.dart';
// tests for List
void main() {
final instance = List();
group(List, () {
// String n123list (default value: null)
test('to test the property `n123list`', () async {
// TODO
});
});
}

View File

@@ -0,0 +1,11 @@
import 'package:openapi/model/model_enum_class.dart';
import 'package:test/test.dart';
// tests for ModelEnumClass
void main() {
group(ModelEnumClass, () {
});
}

View File

@@ -35,7 +35,6 @@ doc/InlineObject3.md
doc/InlineObject4.md
doc/InlineObject5.md
doc/InlineResponseDefault.md
doc/List.md
doc/MapTest.md
doc/MixedPropertiesAndAdditionalPropertiesClass.md
doc/Model200Response.md
@@ -104,7 +103,6 @@ lib/model/inline_object3.dart
lib/model/inline_object4.dart
lib/model/inline_object5.dart
lib/model/inline_response_default.dart
lib/model/list.dart
lib/model/map_test.dart
lib/model/mixed_properties_and_additional_properties_class.dart
lib/model/model200_response.dart

View File

@@ -131,7 +131,6 @@ Class | Method | HTTP request | Description
- [InlineObject4](doc//InlineObject4.md)
- [InlineObject5](doc//InlineObject5.md)
- [InlineResponseDefault](doc//InlineResponseDefault.md)
- [List](doc//List.md)
- [MapTest](doc//MapTest.md)
- [MixedPropertiesAndAdditionalPropertiesClass](doc//MixedPropertiesAndAdditionalPropertiesClass.md)
- [Model200Response](doc//Model200Response.md)

View File

@@ -14,7 +14,7 @@ Name | Type | Description | Notes
**number** | **num** | |
**float** | **double** | | [optional]
**double** | **double** | | [optional]
**decimal** | [**Decimal**](Decimal.md) | | [optional]
**decimal** | **double** | | [optional]
**string** | **String** | | [optional]
**byte** | **String** | |
**binary** | [**MultipartFile**](File.md) | | [optional]

View File

@@ -1,15 +0,0 @@
# openapi.model.List
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**n123list** | **String** | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -64,7 +64,6 @@ part 'model/inline_object3.dart';
part 'model/inline_object4.dart';
part 'model/inline_object5.dart';
part 'model/inline_response_default.dart';
part 'model/list.dart';
part 'model/map_test.dart';
part 'model/mixed_properties_and_additional_properties_class.dart';
part 'model/model200_response.dart';

View File

@@ -224,8 +224,6 @@ class ApiClient {
return InlineObject5.fromJson(value);
case 'InlineResponseDefault':
return InlineResponseDefault.fromJson(value);
case 'List':
return List.fromJson(value);
case 'MapTest':
return MapTest.fromJson(value);
case 'MixedPropertiesAndAdditionalPropertiesClass':

View File

@@ -59,7 +59,7 @@ class FormatTest {
double double;
Decimal decimal;
double decimal;
String string;
@@ -195,7 +195,7 @@ class FormatTest {
json['number'].toDouble(),
float: json['float'],
double: json['double'],
decimal: Decimal.fromJson(json['decimal']),
decimal: json['decimal'],
string: json['string'],
byte: json['byte'],
binary: null, // No support for decoding binary content from JSON

View File

@@ -1,72 +0,0 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.0
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class List {
/// Returns a new [List] instance.
List({
this.n123list,
});
String n123list;
@override
bool operator ==(Object other) => identical(this, other) || other is List &&
other.n123list == n123list;
@override
int get hashCode =>
(n123list == null ? 0 : n123list.hashCode);
@override
String toString() => 'List[n123list=$n123list]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
if (n123list != null) {
json['123-list'] = n123list;
}
return json;
}
/// Returns a new [List] instance and imports its values from
/// [json] if it's non-null, null if [json] is null.
static List fromJson(Map<String, dynamic> json) => json == null
? null
: List(
n123list: json['123-list'],
);
static List<List> listFromJson(List<dynamic> json, {bool emptyIsNull, bool growable,}) =>
json == null || json.isEmpty
? true == emptyIsNull ? null : <List>[]
: json.map((v) => List.fromJson(v)).toList(growable: true == growable);
static Map<String, List> mapFromJson(Map<String, dynamic> json) {
final map = <String, List>{};
if (json != null && json.isNotEmpty) {
json.forEach((String key, dynamic v) => map[key] = List.fromJson(v));
}
return map;
}
// maps a json object with a list of List-objects as value to a dart map
static Map<String, List<List>> mapListFromJson(Map<String, dynamic> json, {bool emptyIsNull, bool growable,}) {
final map = <String, List<List>>{};
if (json != null && json.isNotEmpty) {
json.forEach((String key, dynamic v) {
map[key] = List.listFromJson(v, emptyIsNull: emptyIsNull, growable: growable);
});
}
return map;
}
}

View File

@@ -1,17 +0,0 @@
import 'package:openapi/api.dart';
import 'package:test/test.dart';
// tests for List
void main() {
final instance = List();
group('test List', () {
// String n123list
test('to test the property `n123list`', () async {
// TODO
});
});
}