Skip to content

Commit e6be554

Browse files
[Dart-Dio-Next]#9082 Add json_serializable serialization option (#9980)
* PoC json_serializable in dart-dio-next * Move build.yaml template into json_serializable dir * Undo implicit-dynamic change * Fix automatic formatting * Treat non-required fields as nullable * Make class properties final * Fix error introduced by merging in master * Fix map creation when deserializing * Exclude built files from analysis * Add new dio import props * Fix broken merge * Fix configuration of nullable properties * Only add api_util import if using built value * Add config param to set properties as final * Fix syntax error due to merge * Update to simplified dio configuration * Add missing api constructor template * Fix import for multipart files * Fix inclusion of library deserialize template * Update docs * Remove trailing newline from class * Fix whitespace in generated templates * FIx built value generation problem caused by merge conflicts * Escape dollar signs in strings * Handle enums * Config for json_serializable sample * Generate sample for json_serializable * Revert "Escape dollar signs in strings" This reverts commit 6e2a3ae. * Use raw strings when dealing with enum values * Add json_serializable Maven module ind fix number based enums * regenerate all tests * Update docs and fix wrong maven module * add a beta hint to json_serializable option * Update minimum dart sdk with json serializable * Use dart 2.14 when testing Dart samples * Update codegen to remove analysis errors in output Co-authored-by: Peter Leibiger <kuhnroyal@gmail.com>
1 parent e0d8d0f commit e6be554

211 files changed

Lines changed: 13180 additions & 25 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/samples-dart.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
key: ${{ runner.os }}-${{ github.job }}-${{ env.cache-name }}-${{ hashFiles('samples/**/pubspec.yaml') }}
4141
- uses: dart-lang/setup-dart@v1
4242
with:
43-
sdk: 2.13.0
43+
sdk: 2.14.0
4444
- name: Run tests
4545
uses: ./.github/actions/run-samples
4646
with:
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
generatorName: dart-dio-next
2+
outputDir: samples/openapi3/client/petstore/dart-dio-next/petstore_client_lib_fake-json_serializable
3+
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore-with-fake-endpoints-models-for-testing.yaml
4+
templateDir: modules/openapi-generator/src/main/resources/dart/libraries/dio
5+
typeMappings:
6+
Client: "ModelClient"
7+
File: "ModelFile"
8+
EnumClass: "ModelEnumClass"
9+
additionalProperties:
10+
hideGenerationTimestamp: "true"
11+
enumUnknownDefaultCase: "true"
12+
serializationLibrary: "json_serializable"

docs/generators/dart-dio-next.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
2323
|disallowAdditionalPropertiesIfNotPresent|If false, the 'additionalProperties' implementation (set to true by default) is compliant with the OAS and JSON schema specifications. If true (default), keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.|<dl><dt>**false**</dt><dd>The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications.</dd><dt>**true**</dt><dd>Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.</dd></dl>|true|
2424
|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
2525
|enumUnknownDefaultCase|If the server adds new enum cases, that are unknown by an old spec/client, the client will fail to parse the network response.With this option enabled, each enum will have a new case, 'unknown_default_open_api', so that when the server sends an enum case that is not known by the client/spec, they can safely fallback to this case.|<dl><dt>**false**</dt><dd>No changes to the enum's are made, this is the default option.</dd><dt>**true**</dt><dd>With this option enabled, each enum will have a new case, 'unknown_default_open_api', so that when the enum case sent by the server is not known by the client/spec, can safely be decoded to this case.</dd></dl>|false|
26+
|finalProperties|Whether properties are marked as final when using Json Serializable for serialization| |true|
2627
|legacyDiscriminatorBehavior|Set to false for generators with better support for discriminators. (Python, Java, Go, PowerShell, C#have this enabled by default).|<dl><dt>**true**</dt><dd>The mapping in the discriminator includes descendent schemas that allOf inherit from self and the discriminator mapping schemas in the OAS document.</dd><dt>**false**</dt><dd>The mapping in the discriminator includes any descendent schemas that allOf inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values, and the discriminator mapping schemas in the OAS document AND Codegen validates that oneOf and anyOf schemas contain the required discriminator and throws an error if the discriminator is missing.</dd></dl>|true|
2728
|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|
2829
|pubAuthor|Author name in generated pubspec| |Author|
@@ -32,7 +33,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
3233
|pubLibrary|Library name in generated code| |openapi.api|
3334
|pubName|Name in generated pubspec| |openapi|
3435
|pubVersion|Version in generated pubspec| |1.0.0|
35-
|serializationLibrary|Specify serialization library|<dl><dt>**built_value**</dt><dd>[DEFAULT] built_value</dd></dl>|built_value|
36+
|serializationLibrary|Specify serialization library|<dl><dt>**built_value**</dt><dd>[DEFAULT] built_value</dd><dt>**json_serializable**</dt><dd>[BETA] json_serializable</dd></dl>|built_value|
3637
|sortModelPropertiesByRequiredFlag|Sort model properties to place required parameters before optional parameters.| |true|
3738
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
3839
|sourceFolder|source folder for generated code| |src|

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/DartDioNextClientCodegen.java

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,13 @@ public class DartDioNextClientCodegen extends AbstractDartCodegen {
5656
public static final String DATE_LIBRARY_DEFAULT = DATE_LIBRARY_CORE;
5757

5858
public static final String SERIALIZATION_LIBRARY_BUILT_VALUE = "built_value";
59+
public static final String SERIALIZATION_LIBRARY_JSON_SERIALIZABLE = "json_serializable";
5960
public static final String SERIALIZATION_LIBRARY_DEFAULT = SERIALIZATION_LIBRARY_BUILT_VALUE;
6061

6162
private static final String DIO_IMPORT = "package:dio/dio.dart";
63+
public static final String FINAL_PROPERTIES = "finalProperties";
64+
public static final String FINAL_PROPERTIES_DEFAULT_VALUE = "true";
65+
6266
private static final String CLIENT_NAME = "clientName";
6367

6468
private String dateLibrary;
@@ -85,11 +89,17 @@ public DartDioNextClientCodegen() {
8589
this.setTemplateDir(embeddedTemplateDir);
8690

8791
supportedLibraries.put(SERIALIZATION_LIBRARY_BUILT_VALUE, "[DEFAULT] built_value");
92+
supportedLibraries.put(SERIALIZATION_LIBRARY_JSON_SERIALIZABLE, "[BETA] json_serializable");
8893
final CliOption serializationLibrary = CliOption.newString(CodegenConstants.SERIALIZATION_LIBRARY, "Specify serialization library");
8994
serializationLibrary.setEnum(supportedLibraries);
9095
serializationLibrary.setDefault(SERIALIZATION_LIBRARY_DEFAULT);
9196
cliOptions.add(serializationLibrary);
9297

98+
final CliOption finalProperties = CliOption.newBoolean(FINAL_PROPERTIES, "Whether properties are marked as final when using Json Serializable for serialization");
99+
finalProperties.setDefault("true");
100+
cliOptions.add(finalProperties);
101+
102+
// Date Library Option
93103
final CliOption dateOption = CliOption.newString(DATE_LIBRARY, "Specify Date library");
94104
dateOption.setDefault(DATE_LIBRARY_DEFAULT);
95105

@@ -147,6 +157,14 @@ public void processOpts() {
147157
}
148158
setDateLibrary(additionalProperties.get(DATE_LIBRARY).toString());
149159

160+
if (!additionalProperties.containsKey(FINAL_PROPERTIES)) {
161+
additionalProperties.put(FINAL_PROPERTIES, Boolean.parseBoolean(FINAL_PROPERTIES_DEFAULT_VALUE));
162+
LOGGER.debug("finalProperties not set, using default {}", FINAL_PROPERTIES_DEFAULT_VALUE);
163+
}
164+
else {
165+
additionalProperties.put(FINAL_PROPERTIES, Boolean.parseBoolean(additionalProperties.get(FINAL_PROPERTIES).toString()));
166+
}
167+
150168
if (!additionalProperties.containsKey(CLIENT_NAME)) {
151169
final String name = org.openapitools.codegen.utils.StringUtils.camelize(pubName);
152170
additionalProperties.put(CLIENT_NAME, name);
@@ -177,6 +195,10 @@ public void processOpts() {
177195

178196
private void configureSerializationLibrary(String srcFolder) {
179197
switch (library) {
198+
case SERIALIZATION_LIBRARY_JSON_SERIALIZABLE:
199+
additionalProperties.put("useJsonSerializable", "true");
200+
configureSerializationLibraryJsonSerializable(srcFolder);
201+
break;
180202
default:
181203
case SERIALIZATION_LIBRARY_BUILT_VALUE:
182204
additionalProperties.put("useBuiltValue", "true");
@@ -229,6 +251,18 @@ private void configureSerializationLibraryBuiltValue(String srcFolder) {
229251
imports.put("MultipartFile", DIO_IMPORT);
230252
}
231253

254+
private void configureSerializationLibraryJsonSerializable(String srcFolder) {
255+
supportingFiles.add(new SupportingFile("serialization/json_serializable/build.yaml.mustache", "" /* main project dir */, "build.yaml"));
256+
supportingFiles.add(new SupportingFile("serialization/json_serializable/deserialize.mustache", srcFolder,
257+
"deserialize.dart"));
258+
259+
// most of these are defined in AbstractDartCodegen, we are overriding
260+
// just the binary / file handling
261+
languageSpecificPrimitives.add("Object");
262+
imports.put("Uint8List", "dart:typed_data");
263+
imports.put("MultipartFile", DIO_IMPORT);
264+
}
265+
232266
private void configureDateLibrary(String srcFolder) {
233267
switch (dateLibrary) {
234268
case DATE_LIBRARY_TIME_MACHINE:
@@ -362,27 +396,30 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<Mo
362396
op.imports.remove("Uint8List");
363397
}
364398

365-
for (CodegenParameter param : op.allParams) {
366-
// Generate serializer factories for all container type parameters.
367-
// But skip binary and file parameters, JSON serializers don't make sense there.
368-
if (param.isContainer && !(param.isBinary || param.isFile )) {
369-
addBuiltValueSerializer(new BuiltValueSerializer(
370-
param.isArray,
371-
param.uniqueItems,
372-
param.isMap,
373-
param.items.isNullable,
374-
param.baseType
375-
));
399+
resultImports.addAll(rewriteImports(op.imports, false));
400+
401+
if (SERIALIZATION_LIBRARY_BUILT_VALUE.equals(library)) {
402+
403+
for (CodegenParameter param : op.allParams) {
404+
// Generate serializer factories for all container type parameters.
405+
// But skip binary and file parameters, JSON serializers don't make sense there.
406+
if (param.isContainer && !(param.isBinary || param.isFile )) {
407+
addBuiltValueSerializer(new BuiltValueSerializer(
408+
param.isArray,
409+
param.uniqueItems,
410+
param.isMap,
411+
param.items.isNullable,
412+
param.baseType
413+
));
414+
}
376415
}
377416
}
378417

379418
resultImports.addAll(rewriteImports(op.imports, false));
380-
if (op.getHasFormParams() || op.getHasQueryParams()) {
419+
if (SERIALIZATION_LIBRARY_BUILT_VALUE.equals(library) && (op.getHasFormParams() || op.getHasQueryParams())) {
381420
resultImports.add("package:" + pubName + "/" + sourceFolder + "/api_util.dart");
382421
}
383422

384-
// Generate serializer factories for response types.
385-
// But skip binary and file response, JSON serializers don't make sense there.
386423
if (op.returnContainer != null && !(op.isResponseBinary || op.isResponseFile)) {
387424
addBuiltValueSerializer(new BuiltValueSerializer(
388425
Objects.equals("array", op.returnContainer) || Objects.equals("set", op.returnContainer),
@@ -393,7 +430,6 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<Mo
393430
));
394431
}
395432
}
396-
397433
// for some reason "import" structure is changed ..
398434
objs.put("imports", resultImports.stream().sorted().collect(Collectors.toList()));
399435

modules/openapi-generator/src/main/resources/dart/libraries/dio/analysis_options.mustache

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ analyzer:
66
implicit-dynamic: false
77
implicit-casts: false
88
exclude:
9-
- test/*.dart
9+
- test/*.dart{{#useJsonSerializable}}
10+
- lib/src/model/*.g.dart{{/useJsonSerializable}}

modules/openapi-generator/src/main/resources/dart/libraries/dio/model_test.mustache

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ import 'package:{{pubName}}/{{pubName}}.dart';
77
void main() {
88
{{^isEnum}}
99
{{! Due to required vars without default value we can not create a full instance here }}
10-
final instance = {{{classname}}}Builder();
11-
// TODO add properties to the builder and call build()
10+
{{#includeLibraryTemplate}}test_instance{{/includeLibraryTemplate}}
1211
{{/isEnum}}
1312

1413
group({{{classname}}}, () {

modules/openapi-generator/src/main/resources/dart/libraries/dio/pubspec.mustache

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,22 @@ description: {{pubDescription}}
44
homepage: {{pubHomepage}}
55

66
environment:
7+
{{#useBuiltValue}}
78
sdk: '>=2.12.0 <3.0.0'
9+
{{/useBuiltValue}}
10+
{{#useJsonSerializable}}
11+
sdk: '>=2.14.0 <3.0.0'
12+
{{/useJsonSerializable}}
813
914
dependencies:
1015
dio: '>=4.0.0 <5.0.0'
1116
{{#useBuiltValue}}
1217
built_value: '>=8.1.0 <9.0.0'
1318
built_collection: '>=5.1.0 <6.0.0'
1419
{{/useBuiltValue}}
20+
{{#useJsonSerializable}}
21+
json_annotation: '^4.4.0'
22+
{{/useJsonSerializable}}
1523
{{#useDateLibTimeMachine}}
1624
time_machine: ^0.9.16
1725
{{/useDateLibTimeMachine}}
@@ -21,4 +29,8 @@ dev_dependencies:
2129
built_value_generator: '>=8.1.0 <9.0.0'
2230
build_runner: any
2331
{{/useBuiltValue}}
32+
{{#useJsonSerializable}}
33+
build_runner: any
34+
json_serializable: '^6.1.5'
35+
{{/useJsonSerializable}}
2436
test: ^1.16.0
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
final instance = {{{classname}}}Builder();
2+
// TODO add properties to the builder and call build()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
const {{classname}}(this._dio);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
_responseData = deserialize<{{{returnType}}}, {{{returnBaseType}}}>(_response.data!, '{{{returnType}}}', growable: true);

0 commit comments

Comments
 (0)