From 62923052421df3aca31b6759b354c55931fd9d1a Mon Sep 17 00:00:00 2001 From: Peter Leibiger Date: Wed, 1 Dec 2021 16:07:46 +0100 Subject: [PATCH] [dart][dio][built_value] Fix missing serializer factory builders for additionalProperties Refactor the addition of custom serializer factories. --- .../languages/AbstractDartCodegen.java | 6 +- .../languages/DartDioNextClientCodegen.java | 110 +++++++++++++++--- .../built_value/serializers.mustache | 12 +- .../lib/src/serializers.dart | 20 ++-- .../lib/src/serializers.dart | 20 ++-- 5 files changed, 121 insertions(+), 47 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractDartCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractDartCodegen.java index 86af0181b3da..75e466165a55 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractDartCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractDartCodegen.java @@ -505,7 +505,7 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert super.postProcessModelProperty(model, property); if (!model.isEnum && property.isEnum) { // These are inner enums, enums which do not exist as models, just as properties. - // They are handled via the enum_inline template and and are generated in the + // They are handled via the enum_inline template and are generated in the // same file as the containing class. To prevent name clashes the inline enum classes // are prefix with the classname of the containing class in the template. // Here the datatypeWithEnum template variable gets updated to match that scheme. @@ -529,9 +529,9 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, List servers) { final CodegenOperation op = super.fromOperation(path, httpMethod, operation, servers); for (CodegenResponse r : op.responses) { - // By default only set types are automatically added to operation imports, not sure why. + // By default, only set types are automatically added to operation imports, not sure why. // Add all container type imports here, by default 'dart:core' imports are skipped - // but other sub classes may required specific container type imports. + // but other sub-classes may require specific container type imports. if (r.containerType != null && typeMapping().containsKey(r.containerType)) { final String value = typeMapping().get(r.containerType); if (needToImport(value)) { diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/DartDioNextClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/DartDioNextClientCodegen.java index 9acfe364003b..5f438eb6f8b3 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/DartDioNextClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/DartDioNextClientCodegen.java @@ -323,6 +323,21 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert // enums are generated with built_value and make use of BuiltSet model.imports.add("BuiltSet"); } + + if (property.isContainer) { + // Figure out if there are any container type additionalProperties + // that need a custom serializer builder factory added. + final CodegenProperty items = property.items; + if (items.getAdditionalProperties() != null) { + addBuiltValueSerializer(new BuiltValueSerializer( + items.isArray, + items.getUniqueItems(), + items.isMap, + items.items.isNullable, + items.getAdditionalProperties().dataType + )); + } + } } } @@ -332,7 +347,6 @@ public Map postProcessOperationsWithModels(Map o Map operations = (Map) objs.get("operations"); List operationList = (List) operations.get("operation"); - Set> serializers = new HashSet<>(); Set resultImports = new HashSet<>(); for (CodegenOperation op : operationList) { @@ -370,12 +384,13 @@ public Map postProcessOperationsWithModels(Map o // Generate serializer factories for all container type parameters. // But skip binary and file parameters, JSON serializers don't make sense there. if (param.isContainer && !(param.isBinary || param.isFile )) { - final Map serializer = new HashMap<>(); - serializer.put("isArray", param.isArray); - serializer.put("uniqueItems", param.uniqueItems); - serializer.put("isMap", param.isMap); - serializer.put("baseType", param.baseType); - serializers.add(serializer); + addBuiltValueSerializer(new BuiltValueSerializer( + param.isArray, + param.uniqueItems, + param.isMap, + param.items.isNullable, + param.baseType + )); } } @@ -387,17 +402,17 @@ public Map postProcessOperationsWithModels(Map o // Generate serializer factories for response types. // But skip binary and file response, JSON serializers don't make sense there. if (op.returnContainer != null && !(op.isResponseBinary || op.isResponseFile)) { - final Map serializer = new HashMap<>(); - serializer.put("isArray", Objects.equals("array", op.returnContainer) || Objects.equals("set", op.returnContainer)); - serializer.put("uniqueItems", op.uniqueItems); - serializer.put("isMap", Objects.equals("map", op.returnContainer)); - serializer.put("baseType", op.returnBaseType); - serializers.add(serializer); + addBuiltValueSerializer(new BuiltValueSerializer( + Objects.equals("array", op.returnContainer) || Objects.equals("set", op.returnContainer), + op.uniqueItems, + Objects.equals("map", op.returnContainer), + false, + op.returnBaseType + )); } } objs.put("imports", resultImports.stream().sorted().collect(Collectors.toList())); - objs.put("serializers", serializers); return objs; } @@ -410,6 +425,19 @@ private void addBuiltValueSerializerImport(String type) { }); } + /** + * Adds the serializer to the global list of custom built_value serializers. + * @param serializer + */ + private void addBuiltValueSerializer(BuiltValueSerializer serializer) { + System.out.println("######## Add serializer!"); + additionalProperties.compute("builtValueSerializers", (k, v) -> { + Set serializers = v == null ? Sets.newHashSet() : ((Set) v); + serializers.add(serializer); + return serializers; + }); + } + private Set rewriteImports(Set originalImports, boolean isModel) { Set resultImports = Sets.newHashSet(); for (String modelImport : originalImports) { @@ -428,4 +456,58 @@ private Set rewriteImports(Set originalImports, boolean isModel) } return resultImports; } + + static class BuiltValueSerializer { + + final boolean isArray; + + final boolean uniqueItems; + + final boolean isMap; + + final boolean isNullable; + + final String dataType; + + private BuiltValueSerializer(boolean isArray, boolean uniqueItems, boolean isMap, boolean isNullable, String dataType) { + this.isArray = isArray; + this.uniqueItems = uniqueItems; + this.isMap = isMap; + this.isNullable = isNullable; + this.dataType = dataType; + } + + public boolean isArray() { + return isArray; + } + + public boolean isUniqueItems() { + return uniqueItems; + } + + public boolean isMap() { + return isMap; + } + + public boolean isNullable() { + return isNullable; + } + + public String getDataType() { + return dataType; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + BuiltValueSerializer that = (BuiltValueSerializer) o; + return isArray == that.isArray && uniqueItems == that.uniqueItems && isMap == that.isMap && isNullable == that.isNullable && dataType.equals(that.dataType); + } + + @Override + public int hashCode() { + return Objects.hash(isArray, uniqueItems, isMap, isNullable, dataType); + } + } } diff --git a/modules/openapi-generator/src/main/resources/dart/libraries/dio/serialization/built_value/serializers.mustache b/modules/openapi-generator/src/main/resources/dart/libraries/dio/serialization/built_value/serializers.mustache index e1f3dbe1df5f..c558f153c890 100644 --- a/modules/openapi-generator/src/main/resources/dart/libraries/dio/serialization/built_value/serializers.mustache +++ b/modules/openapi-generator/src/main/resources/dart/libraries/dio/serialization/built_value/serializers.mustache @@ -19,17 +19,17 @@ part 'serializers.g.dart'; @SerializersFor([{{#models}}{{#model}} {{classname}},{{/model}}{{/models}} ]) -Serializers serializers = (_$serializers.toBuilder(){{#apiInfo}}{{#apis}}{{#serializers}} +Serializers serializers = (_$serializers.toBuilder(){{#builtValueSerializers}} ..addBuilderFactory( {{#isArray}} - const FullType(Built{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}, [FullType({{baseType}})]), - () => {{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}Builder<{{baseType}}>(), + const FullType(Built{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}, [FullType{{#isNullable}}.nullable{{/isNullable}}({{dataType}})]), + () => {{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}Builder<{{dataType}}>(), {{/isArray}} {{#isMap}} - const FullType(BuiltMap, [FullType(String), FullType({{baseType}})]), - () => MapBuilder(), + const FullType(BuiltMap, [FullType(String), FullType{{#isNullable}}.nullable{{/isNullable}}({{dataType}})]), + () => MapBuilder(), {{/isMap}} - ){{/serializers}}{{/apis}}{{/apiInfo}}{{#useDateLibTimeMachine}} + ){{/builtValueSerializers}}{{#useDateLibTimeMachine}} ..add(const OffsetDateSerializer()) ..add(const OffsetDateTimeSerializer()){{/useDateLibTimeMachine}}{{#useDateLibCore}} ..add(const DateSerializer()) diff --git a/samples/openapi3/client/petstore/dart-dio-next/dio_http_petstore_client_lib_fake/lib/src/serializers.dart b/samples/openapi3/client/petstore/dart-dio-next/dio_http_petstore_client_lib_fake/lib/src/serializers.dart index 1b807addf9e7..5ee82d7b5019 100644 --- a/samples/openapi3/client/petstore/dart-dio-next/dio_http_petstore_client_lib_fake/lib/src/serializers.dart +++ b/samples/openapi3/client/petstore/dart-dio-next/dio_http_petstore_client_lib_fake/lib/src/serializers.dart @@ -110,26 +110,22 @@ part 'serializers.g.dart'; User, ]) Serializers serializers = (_$serializers.toBuilder() - ..addBuilderFactory( - const FullType(BuiltList, [FullType(String)]), - () => ListBuilder(), - ) ..addBuilderFactory( const FullType(BuiltMap, [FullType(String), FullType(String)]), () => MapBuilder(), ) ..addBuilderFactory( - const FullType(BuiltList, [FullType(String)]), - () => ListBuilder(), - ) - ..addBuilderFactory( - const FullType(BuiltSet, [FullType(Pet)]), - () => SetBuilder(), + const FullType(BuiltList, [FullType(User)]), + () => ListBuilder(), ) ..addBuilderFactory( const FullType(BuiltSet, [FullType(String)]), () => SetBuilder(), ) + ..addBuilderFactory( + const FullType(BuiltSet, [FullType(Pet)]), + () => SetBuilder(), + ) ..addBuilderFactory( const FullType(BuiltList, [FullType(Pet)]), () => ListBuilder(), @@ -139,8 +135,8 @@ Serializers serializers = (_$serializers.toBuilder() () => MapBuilder(), ) ..addBuilderFactory( - const FullType(BuiltList, [FullType(User)]), - () => ListBuilder(), + const FullType(BuiltList, [FullType(String)]), + () => ListBuilder(), ) ..add(const DateSerializer()) ..add(Iso8601DateTimeSerializer())) diff --git a/samples/openapi3/client/petstore/dart-dio-next/petstore_client_lib_fake/lib/src/serializers.dart b/samples/openapi3/client/petstore/dart-dio-next/petstore_client_lib_fake/lib/src/serializers.dart index 1b807addf9e7..5ee82d7b5019 100644 --- a/samples/openapi3/client/petstore/dart-dio-next/petstore_client_lib_fake/lib/src/serializers.dart +++ b/samples/openapi3/client/petstore/dart-dio-next/petstore_client_lib_fake/lib/src/serializers.dart @@ -110,26 +110,22 @@ part 'serializers.g.dart'; User, ]) Serializers serializers = (_$serializers.toBuilder() - ..addBuilderFactory( - const FullType(BuiltList, [FullType(String)]), - () => ListBuilder(), - ) ..addBuilderFactory( const FullType(BuiltMap, [FullType(String), FullType(String)]), () => MapBuilder(), ) ..addBuilderFactory( - const FullType(BuiltList, [FullType(String)]), - () => ListBuilder(), - ) - ..addBuilderFactory( - const FullType(BuiltSet, [FullType(Pet)]), - () => SetBuilder(), + const FullType(BuiltList, [FullType(User)]), + () => ListBuilder(), ) ..addBuilderFactory( const FullType(BuiltSet, [FullType(String)]), () => SetBuilder(), ) + ..addBuilderFactory( + const FullType(BuiltSet, [FullType(Pet)]), + () => SetBuilder(), + ) ..addBuilderFactory( const FullType(BuiltList, [FullType(Pet)]), () => ListBuilder(), @@ -139,8 +135,8 @@ Serializers serializers = (_$serializers.toBuilder() () => MapBuilder(), ) ..addBuilderFactory( - const FullType(BuiltList, [FullType(User)]), - () => ListBuilder(), + const FullType(BuiltList, [FullType(String)]), + () => ListBuilder(), ) ..add(const DateSerializer()) ..add(Iso8601DateTimeSerializer()))