From f33ff15d05e5565cc75382d578e33a18ebd0f2b6 Mon Sep 17 00:00:00 2001 From: 0xNF Date: Sun, 18 Sep 2022 13:36:56 +0900 Subject: [PATCH 1/3] [Dart] Add Uint8List support to Dart generator (#12161) * Adds Uint8List as a valid return type for type: string format: binary definitions * Adds support for using bodyBytes instead of body for deserializing response data --- .../src/main/resources/dart2/api.mustache | 9 ++++----- .../src/main/resources/dart2/api_client.mustache | 16 +++++++++++----- .../src/main/resources/dart2/api_helper.mustache | 11 ++++------- .../src/main/resources/dart2/apilib.mustache | 1 + 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/dart2/api.mustache b/modules/openapi-generator/src/main/resources/dart2/api.mustache index e40ebac39408..84150d4a42bf 100644 --- a/modules/openapi-generator/src/main/resources/dart2/api.mustache +++ b/modules/openapi-generator/src/main/resources/dart2/api.mustache @@ -164,7 +164,7 @@ class {{{classname}}} { Future<{{#returnType}}{{{.}}}?{{/returnType}}{{^returnType}}void{{/returnType}}> {{{nickname}}}({{#allParams}}{{#required}}{{{dataType}}} {{{paramName}}},{{^-last}} {{/-last}}{{/required}}{{/allParams}}{{#hasOptionalParams}}{ {{#allParams}}{{^required}}{{{dataType}}}? {{{paramName}}},{{^-last}} {{/-last}}{{/required}}{{/allParams}} }{{/hasOptionalParams}}) async { final response = await {{{nickname}}}WithHttpInfo({{#allParams}}{{#required}}{{{paramName}}},{{^-last}} {{/-last}}{{/required}}{{/allParams}}{{#hasOptionalParams}} {{#allParams}}{{^required}}{{{paramName}}}: {{{paramName}}},{{^-last}} {{/-last}}{{/required}}{{/allParams}} {{/hasOptionalParams}}); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } {{#returnType}} // When a remote server returns no body with a status of 204, we shall not decode it. @@ -173,17 +173,16 @@ class {{{classname}}} { if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { {{#native_serialization}} {{#isArray}} - final responseBody = await _decodeBodyBytes(response); - return (await apiClient.deserializeAsync(responseBody, '{{{returnType}}}') as List) + return (await apiClient.deserializeAsync(response.bodyBytes, '{{{returnType}}}') as List) .cast<{{{returnBaseType}}}>() .{{#uniqueItems}}toSet(){{/uniqueItems}}{{^uniqueItems}}toList(){{/uniqueItems}}; {{/isArray}} {{^isArray}} {{#isMap}} - return {{{returnType}}}.from(await apiClient.deserializeAsync(await _decodeBodyBytes(response), '{{{returnType}}}'),); + return {{{returnType}}}.from(await apiClient.deserializeAsync(response.bodyBytes, '{{{returnType}}}'),); {{/isMap}} {{^isMap}} - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), '{{{returnType}}}',) as {{{returnType}}}; + return await apiClient.deserializeAsync(response.bodyBytes, '{{{returnType}}}',) as {{{returnType}}}; {{/isMap}}{{/isArray}}{{/native_serialization}} } return null; diff --git a/modules/openapi-generator/src/main/resources/dart2/api_client.mustache b/modules/openapi-generator/src/main/resources/dart2/api_client.mustache index b340a9745757..36e79e115723 100644 --- a/modules/openapi-generator/src/main/resources/dart2/api_client.mustache +++ b/modules/openapi-generator/src/main/resources/dart2/api_client.mustache @@ -134,19 +134,25 @@ class ApiClient { } {{#native_serialization}} - Future deserializeAsync(String json, String targetType, {bool growable = false,}) async => + Future deserializeAsync(Uint8List responseBytes, String targetType, {bool growable = false,}) async => // ignore: deprecated_member_use_from_same_package - deserialize(json, targetType, growable: growable); + deserialize(responseBytes, targetType, growable: growable); @Deprecated('Scheduled for removal in OpenAPI Generator 6.x. Use deserializeAsync() instead.') - dynamic deserialize(String json, String targetType, {bool growable = false,}) { + dynamic deserialize(Uint8List responseBytes, String targetType, {bool growable = false,}) { // Remove all spaces. Necessary for regular expressions as well. targetType = targetType.replaceAll(' ', ''); // ignore: parameter_assignments + // if the expected target type is a byte-array, then just return the response bytes as-is + if (targetType == 'Uint8List') { + return responseBytes; + } + + final decodedString = const Utf8Decoder().convert(responseBytes); // If the expected target type is String, nothing to do... return targetType == 'String' - ? json - : _deserialize(jsonDecode(json), targetType, growable: growable); + ? decodedString + : _deserialize(jsonDecode(decodedString), targetType, growable: growable); } {{/native_serialization}} diff --git a/modules/openapi-generator/src/main/resources/dart2/api_helper.mustache b/modules/openapi-generator/src/main/resources/dart2/api_helper.mustache index ec98b7d1d741..cdd71c188d71 100644 --- a/modules/openapi-generator/src/main/resources/dart2/api_helper.mustache +++ b/modules/openapi-generator/src/main/resources/dart2/api_helper.mustache @@ -57,13 +57,10 @@ String parameterToString(dynamic value) { return value.toString(); } -/// Returns the decoded body as UTF-8 if the given headers indicate an 'application/json' -/// content type. Otherwise, returns the decoded body as decoded by dart:http package. -Future _decodeBodyBytes(Response response) async { - final contentType = response.headers['content-type']; - return contentType != null && contentType.toLowerCase().startsWith('application/json') - ? response.bodyBytes.isEmpty ? '' : utf8.decode(response.bodyBytes) - : response.body; +/// Decodes the response body for error reporting purposes. +/// Decodes as UTF-8 but allows for malformed bytes to avoid crashing. +String decodeError(Uint8List responseBytes) { + return const Utf8Decoder(allowMalformed: true).convert(responseBytes); } /// Returns a valid [T] value found at the specified Map [key], null otherwise. diff --git a/modules/openapi-generator/src/main/resources/dart2/apilib.mustache b/modules/openapi-generator/src/main/resources/dart2/apilib.mustache index 2fcebda4ea46..0968cc259aca 100644 --- a/modules/openapi-generator/src/main/resources/dart2/apilib.mustache +++ b/modules/openapi-generator/src/main/resources/dart2/apilib.mustache @@ -4,6 +4,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'dart:typed_data'; import 'package:http/http.dart'; import 'package:intl/intl.dart'; From d5ed19fccb47be0547ccb0e60df664d64e98689e Mon Sep 17 00:00:00 2001 From: 0xNF Date: Mon, 19 Sep 2022 11:19:39 +0900 Subject: [PATCH 2/3] [Dart] Update samples --- .../dart2/petstore_client_lib/lib/api.dart | 1 + .../petstore_client_lib/lib/api/pet_api.dart | 30 ++++++------ .../lib/api/store_api.dart | 14 +++--- .../petstore_client_lib/lib/api/user_api.dart | 20 ++++---- .../petstore_client_lib/lib/api_client.dart | 16 +++++-- .../petstore_client_lib/lib/api_helper.dart | 11 ++--- .../petstore_client_lib_fake/lib/api.dart | 1 + .../lib/api/another_fake_api.dart | 4 +- .../lib/api/default_api.dart | 4 +- .../lib/api/fake_api.dart | 48 +++++++++---------- .../lib/api/fake_classname_tags123_api.dart | 4 +- .../lib/api/pet_api.dart | 30 ++++++------ .../lib/api/store_api.dart | 14 +++--- .../lib/api/user_api.dart | 20 ++++---- .../lib/api_client.dart | 16 +++++-- .../lib/api_helper.dart | 11 ++--- 16 files changed, 124 insertions(+), 120 deletions(-) diff --git a/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api.dart b/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api.dart index 742bcfa11543..95dd24562778 100644 --- a/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api.dart +++ b/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api.dart @@ -13,6 +13,7 @@ library openapi.api; import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'dart:typed_data'; import 'package:http/http.dart'; import 'package:intl/intl.dart'; diff --git a/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api/pet_api.dart b/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api/pet_api.dart index d0354de38dbb..17a0d4a467d7 100644 --- a/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api/pet_api.dart +++ b/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api/pet_api.dart @@ -62,13 +62,13 @@ class PetApi { Future addPet(Pet pet,) async { final response = await addPetWithHttpInfo(pet,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'Pet',) as Pet; + return await apiClient.deserializeAsync(response.bodyBytes, 'Pet',) as Pet; } return null; @@ -129,7 +129,7 @@ class PetApi { Future deletePet(int petId, { String? apiKey, }) async { final response = await deletePetWithHttpInfo(petId, apiKey: apiKey, ); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -181,14 +181,13 @@ class PetApi { Future?> findPetsByStatus(List status,) async { final response = await findPetsByStatusWithHttpInfo(status,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - final responseBody = await _decodeBodyBytes(response); - return (await apiClient.deserializeAsync(responseBody, 'List') as List) + return (await apiClient.deserializeAsync(response.bodyBytes, 'List') as List) .cast() .toList(); @@ -244,14 +243,13 @@ class PetApi { Future?> findPetsByTags(List tags,) async { final response = await findPetsByTagsWithHttpInfo(tags,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - final responseBody = await _decodeBodyBytes(response); - return (await apiClient.deserializeAsync(responseBody, 'List') as List) + return (await apiClient.deserializeAsync(response.bodyBytes, 'List') as List) .cast() .toList(); @@ -306,13 +304,13 @@ class PetApi { Future getPetById(int petId,) async { final response = await getPetByIdWithHttpInfo(petId,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'Pet',) as Pet; + return await apiClient.deserializeAsync(response.bodyBytes, 'Pet',) as Pet; } return null; @@ -364,13 +362,13 @@ class PetApi { Future updatePet(Pet pet,) async { final response = await updatePetWithHttpInfo(pet,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'Pet',) as Pet; + return await apiClient.deserializeAsync(response.bodyBytes, 'Pet',) as Pet; } return null; @@ -441,7 +439,7 @@ class PetApi { Future updatePetWithForm(int petId, { String? name, String? status, }) async { final response = await updatePetWithFormWithHttpInfo(petId, name: name, status: status, ); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -518,13 +516,13 @@ class PetApi { Future uploadFile(int petId, { String? additionalMetadata, MultipartFile? file, }) async { final response = await uploadFileWithHttpInfo(petId, additionalMetadata: additionalMetadata, file: file, ); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'ApiResponse',) as ApiResponse; + return await apiClient.deserializeAsync(response.bodyBytes, 'ApiResponse',) as ApiResponse; } return null; diff --git a/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api/store_api.dart b/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api/store_api.dart index db1ac1f010bf..dee9aeb46984 100644 --- a/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api/store_api.dart +++ b/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api/store_api.dart @@ -63,7 +63,7 @@ class StoreApi { Future deleteOrder(String orderId,) async { final response = await deleteOrderWithHttpInfo(orderId,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -103,13 +103,13 @@ class StoreApi { Future?> getInventory() async { final response = await getInventoryWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return Map.from(await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'Map'),); + return Map.from(await apiClient.deserializeAsync(response.bodyBytes, 'Map'),); } return null; @@ -162,13 +162,13 @@ class StoreApi { Future getOrderById(int orderId,) async { final response = await getOrderByIdWithHttpInfo(orderId,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'Order',) as Order; + return await apiClient.deserializeAsync(response.bodyBytes, 'Order',) as Order; } return null; @@ -220,13 +220,13 @@ class StoreApi { Future placeOrder(Order order,) async { final response = await placeOrderWithHttpInfo(order,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'Order',) as Order; + return await apiClient.deserializeAsync(response.bodyBytes, 'Order',) as Order; } return null; diff --git a/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api/user_api.dart b/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api/user_api.dart index a44252a6130b..f3574b90284b 100644 --- a/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api/user_api.dart +++ b/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api/user_api.dart @@ -62,7 +62,7 @@ class UserApi { Future createUser(User user,) async { final response = await createUserWithHttpInfo(user,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -112,7 +112,7 @@ class UserApi { Future createUsersWithArrayInput(List user,) async { final response = await createUsersWithArrayInputWithHttpInfo(user,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -162,7 +162,7 @@ class UserApi { Future createUsersWithListInput(List user,) async { final response = await createUsersWithListInputWithHttpInfo(user,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -213,7 +213,7 @@ class UserApi { Future deleteUser(String username,) async { final response = await deleteUserWithHttpInfo(username,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -264,13 +264,13 @@ class UserApi { Future getUserByName(String username,) async { final response = await getUserByNameWithHttpInfo(username,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'User',) as User; + return await apiClient.deserializeAsync(response.bodyBytes, 'User',) as User; } return null; @@ -331,13 +331,13 @@ class UserApi { Future loginUser(String username, String password,) async { final response = await loginUserWithHttpInfo(username, password,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'String',) as String; + return await apiClient.deserializeAsync(response.bodyBytes, 'String',) as String; } return null; @@ -379,7 +379,7 @@ class UserApi { Future logoutUser() async { final response = await logoutUserWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -436,7 +436,7 @@ class UserApi { Future updateUser(String username, User user,) async { final response = await updateUserWithHttpInfo(username, user,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } } diff --git a/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api_client.dart b/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api_client.dart index 00b9e81f7ea9..4befd0e775cb 100644 --- a/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api_client.dart +++ b/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api_client.dart @@ -143,19 +143,25 @@ class ApiClient { ); } - Future deserializeAsync(String json, String targetType, {bool growable = false,}) async => + Future deserializeAsync(Uint8List responseBytes, String targetType, {bool growable = false,}) async => // ignore: deprecated_member_use_from_same_package - deserialize(json, targetType, growable: growable); + deserialize(responseBytes, targetType, growable: growable); @Deprecated('Scheduled for removal in OpenAPI Generator 6.x. Use deserializeAsync() instead.') - dynamic deserialize(String json, String targetType, {bool growable = false,}) { + dynamic deserialize(Uint8List responseBytes, String targetType, {bool growable = false,}) { // Remove all spaces. Necessary for regular expressions as well. targetType = targetType.replaceAll(' ', ''); // ignore: parameter_assignments + // if the expected target type is a byte-array, then just return the response bytes as-is + if (targetType == 'Uint8List') { + return responseBytes; + } + + final decodedString = const Utf8Decoder().convert(responseBytes); // If the expected target type is String, nothing to do... return targetType == 'String' - ? json - : _deserialize(jsonDecode(json), targetType, growable: growable); + ? decodedString + : _deserialize(jsonDecode(decodedString), targetType, growable: growable); } // ignore: deprecated_member_use_from_same_package diff --git a/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api_helper.dart b/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api_helper.dart index d6adb1798250..2819fac529b6 100644 --- a/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api_helper.dart +++ b/samples/openapi3/client/petstore/dart2/petstore_client_lib/lib/api_helper.dart @@ -58,13 +58,10 @@ String parameterToString(dynamic value) { return value.toString(); } -/// Returns the decoded body as UTF-8 if the given headers indicate an 'application/json' -/// content type. Otherwise, returns the decoded body as decoded by dart:http package. -Future _decodeBodyBytes(Response response) async { - final contentType = response.headers['content-type']; - return contentType != null && contentType.toLowerCase().startsWith('application/json') - ? response.bodyBytes.isEmpty ? '' : utf8.decode(response.bodyBytes) - : response.body; +/// Decodes the response body for error reporting purposes. +/// Decodes as UTF-8 but allows for malformed bytes to avoid crashing. +String decodeError(Uint8List responseBytes) { + return const Utf8Decoder(allowMalformed: true).convert(responseBytes); } /// Returns a valid [T] value found at the specified Map [key], null otherwise. diff --git a/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api.dart b/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api.dart index e624212cc80d..332f2d53de68 100644 --- a/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api.dart +++ b/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api.dart @@ -13,6 +13,7 @@ library openapi.api; import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'dart:typed_data'; import 'package:http/http.dart'; import 'package:intl/intl.dart'; diff --git a/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/another_fake_api.dart b/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/another_fake_api.dart index 689eafbd8ed7..a8e54ab137cb 100644 --- a/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/another_fake_api.dart +++ b/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/another_fake_api.dart @@ -62,13 +62,13 @@ class AnotherFakeApi { Future call123testSpecialTags(ModelClient modelClient,) async { final response = await call123testSpecialTagsWithHttpInfo(modelClient,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'ModelClient',) as ModelClient; + return await apiClient.deserializeAsync(response.bodyBytes, 'ModelClient',) as ModelClient; } return null; diff --git a/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/default_api.dart b/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/default_api.dart index c62615343015..5d3ad31a07cf 100644 --- a/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/default_api.dart +++ b/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/default_api.dart @@ -45,13 +45,13 @@ class DefaultApi { Future fooGet() async { final response = await fooGetWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'FooGetDefaultResponse',) as FooGetDefaultResponse; + return await apiClient.deserializeAsync(response.bodyBytes, 'FooGetDefaultResponse',) as FooGetDefaultResponse; } return null; diff --git a/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/fake_api.dart b/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/fake_api.dart index 6cfbfb4e6c93..521f69e65202 100644 --- a/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/fake_api.dart +++ b/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/fake_api.dart @@ -48,13 +48,13 @@ class FakeApi { Future fakeHealthGet() async { final response = await fakeHealthGetWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'HealthCheckResult',) as HealthCheckResult; + return await apiClient.deserializeAsync(response.bodyBytes, 'HealthCheckResult',) as HealthCheckResult; } return null; @@ -122,7 +122,7 @@ class FakeApi { Future fakeHttpSignatureTest(Pet pet, { String? query1, String? header1, }) async { final response = await fakeHttpSignatureTestWithHttpInfo(pet, query1: query1, header1: header1, ); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -168,13 +168,13 @@ class FakeApi { Future fakeOuterBooleanSerialize({ bool? body, }) async { final response = await fakeOuterBooleanSerializeWithHttpInfo( body: body, ); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'bool',) as bool; + return await apiClient.deserializeAsync(response.bodyBytes, 'bool',) as bool; } return null; @@ -222,13 +222,13 @@ class FakeApi { Future fakeOuterCompositeSerialize({ OuterComposite? outerComposite, }) async { final response = await fakeOuterCompositeSerializeWithHttpInfo( outerComposite: outerComposite, ); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'OuterComposite',) as OuterComposite; + return await apiClient.deserializeAsync(response.bodyBytes, 'OuterComposite',) as OuterComposite; } return null; @@ -276,13 +276,13 @@ class FakeApi { Future fakeOuterNumberSerialize({ num? body, }) async { final response = await fakeOuterNumberSerializeWithHttpInfo( body: body, ); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'num',) as num; + return await apiClient.deserializeAsync(response.bodyBytes, 'num',) as num; } return null; @@ -330,13 +330,13 @@ class FakeApi { Future fakeOuterStringSerialize({ String? body, }) async { final response = await fakeOuterStringSerializeWithHttpInfo( body: body, ); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'String',) as String; + return await apiClient.deserializeAsync(response.bodyBytes, 'String',) as String; } return null; @@ -384,13 +384,13 @@ class FakeApi { Future fakePropertyEnumIntegerSerialize(OuterObjectWithEnumProperty outerObjectWithEnumProperty,) async { final response = await fakePropertyEnumIntegerSerializeWithHttpInfo(outerObjectWithEnumProperty,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'OuterObjectWithEnumProperty',) as OuterObjectWithEnumProperty; + return await apiClient.deserializeAsync(response.bodyBytes, 'OuterObjectWithEnumProperty',) as OuterObjectWithEnumProperty; } return null; @@ -438,7 +438,7 @@ class FakeApi { Future testBodyWithBinary(MultipartFile body,) async { final response = await testBodyWithBinaryWithHttpInfo(body,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -482,7 +482,7 @@ class FakeApi { Future testBodyWithFileSchema(FileSchemaTestClass fileSchemaTestClass,) async { final response = await testBodyWithFileSchemaWithHttpInfo(fileSchemaTestClass,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -527,7 +527,7 @@ class FakeApi { Future testBodyWithQueryParams(String query, User user,) async { final response = await testBodyWithQueryParamsWithHttpInfo(query, user,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -577,13 +577,13 @@ class FakeApi { Future testClientModel(ModelClient modelClient,) async { final response = await testClientModelWithHttpInfo(modelClient,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'ModelClient',) as ModelClient; + return await apiClient.deserializeAsync(response.bodyBytes, 'ModelClient',) as ModelClient; } return null; @@ -752,7 +752,7 @@ class FakeApi { Future testEndpointParameters(num number, double double_, String patternWithoutDelimiter, String byte, { int? integer, int? int32, int? int64, double? float, String? string, MultipartFile? binary, DateTime? date, DateTime? dateTime, String? password, String? callback, }) async { final response = await testEndpointParametersWithHttpInfo(number, double_, patternWithoutDelimiter, byte, integer: integer, int32: int32, int64: int64, float: float, string: string, binary: binary, date: date, dateTime: dateTime, password: password, callback: callback, ); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -877,7 +877,7 @@ class FakeApi { Future testEnumParameters({ List? enumHeaderStringArray, String? enumHeaderString, List? enumQueryStringArray, String? enumQueryString, int? enumQueryInteger, double? enumQueryDouble, List? enumQueryModelArray, List? enumFormStringArray, String? enumFormString, }) async { final response = await testEnumParametersWithHttpInfo( enumHeaderStringArray: enumHeaderStringArray, enumHeaderString: enumHeaderString, enumQueryStringArray: enumQueryStringArray, enumQueryString: enumQueryString, enumQueryInteger: enumQueryInteger, enumQueryDouble: enumQueryDouble, enumQueryModelArray: enumQueryModelArray, enumFormStringArray: enumFormStringArray, enumFormString: enumFormString, ); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -971,7 +971,7 @@ class FakeApi { Future testGroupParameters(int requiredStringGroup, bool requiredBooleanGroup, int requiredInt64Group, { int? stringGroup, bool? booleanGroup, int? int64Group, }) async { final response = await testGroupParametersWithHttpInfo(requiredStringGroup, requiredBooleanGroup, requiredInt64Group, stringGroup: stringGroup, booleanGroup: booleanGroup, int64Group: int64Group, ); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -1021,7 +1021,7 @@ class FakeApi { Future testInlineAdditionalProperties(Map requestBody,) async { final response = await testInlineAdditionalPropertiesWithHttpInfo(requestBody,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -1083,7 +1083,7 @@ class FakeApi { Future testJsonFormData(String param, String param2,) async { final response = await testJsonFormDataWithHttpInfo(param, param2,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -1161,7 +1161,7 @@ class FakeApi { Future testQueryParameterCollectionFormat(List pipe, List ioutil, List http, List url, List context, String allowEmpty, { Map? language, }) async { final response = await testQueryParameterCollectionFormatWithHttpInfo(pipe, ioutil, http, url, context, allowEmpty, language: language, ); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } } diff --git a/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/fake_classname_tags123_api.dart b/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/fake_classname_tags123_api.dart index 2782357efb9b..8135156a1853 100644 --- a/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/fake_classname_tags123_api.dart +++ b/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/fake_classname_tags123_api.dart @@ -62,13 +62,13 @@ class FakeClassnameTags123Api { Future testClassname(ModelClient modelClient,) async { final response = await testClassnameWithHttpInfo(modelClient,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'ModelClient',) as ModelClient; + return await apiClient.deserializeAsync(response.bodyBytes, 'ModelClient',) as ModelClient; } return null; diff --git a/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/pet_api.dart b/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/pet_api.dart index 371afa625cfc..1e169a484d00 100644 --- a/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/pet_api.dart +++ b/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/pet_api.dart @@ -62,7 +62,7 @@ class PetApi { Future addPet(Pet pet,) async { final response = await addPetWithHttpInfo(pet,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -121,7 +121,7 @@ class PetApi { Future deletePet(int petId, { String? apiKey, }) async { final response = await deletePetWithHttpInfo(petId, apiKey: apiKey, ); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -173,14 +173,13 @@ class PetApi { Future?> findPetsByStatus(List status,) async { final response = await findPetsByStatusWithHttpInfo(status,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - final responseBody = await _decodeBodyBytes(response); - return (await apiClient.deserializeAsync(responseBody, 'List') as List) + return (await apiClient.deserializeAsync(response.bodyBytes, 'List') as List) .cast() .toList(); @@ -236,14 +235,13 @@ class PetApi { Future?> findPetsByTags(Set tags,) async { final response = await findPetsByTagsWithHttpInfo(tags,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - final responseBody = await _decodeBodyBytes(response); - return (await apiClient.deserializeAsync(responseBody, 'Set') as List) + return (await apiClient.deserializeAsync(response.bodyBytes, 'Set') as List) .cast() .toSet(); @@ -298,13 +296,13 @@ class PetApi { Future getPetById(int petId,) async { final response = await getPetByIdWithHttpInfo(petId,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'Pet',) as Pet; + return await apiClient.deserializeAsync(response.bodyBytes, 'Pet',) as Pet; } return null; @@ -356,7 +354,7 @@ class PetApi { Future updatePet(Pet pet,) async { final response = await updatePetWithHttpInfo(pet,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -425,7 +423,7 @@ class PetApi { Future updatePetWithForm(int petId, { String? name, String? status, }) async { final response = await updatePetWithFormWithHttpInfo(petId, name: name, status: status, ); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -502,13 +500,13 @@ class PetApi { Future uploadFile(int petId, { String? additionalMetadata, MultipartFile? file, }) async { final response = await uploadFileWithHttpInfo(petId, additionalMetadata: additionalMetadata, file: file, ); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'ApiResponse',) as ApiResponse; + return await apiClient.deserializeAsync(response.bodyBytes, 'ApiResponse',) as ApiResponse; } return null; @@ -587,13 +585,13 @@ class PetApi { Future uploadFileWithRequiredFile(int petId, MultipartFile requiredFile, { String? additionalMetadata, }) async { final response = await uploadFileWithRequiredFileWithHttpInfo(petId, requiredFile, additionalMetadata: additionalMetadata, ); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'ApiResponse',) as ApiResponse; + return await apiClient.deserializeAsync(response.bodyBytes, 'ApiResponse',) as ApiResponse; } return null; diff --git a/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/store_api.dart b/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/store_api.dart index 68c1c9fdccb9..4223cab00135 100644 --- a/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/store_api.dart +++ b/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/store_api.dart @@ -63,7 +63,7 @@ class StoreApi { Future deleteOrder(String orderId,) async { final response = await deleteOrderWithHttpInfo(orderId,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -103,13 +103,13 @@ class StoreApi { Future?> getInventory() async { final response = await getInventoryWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return Map.from(await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'Map'),); + return Map.from(await apiClient.deserializeAsync(response.bodyBytes, 'Map'),); } return null; @@ -162,13 +162,13 @@ class StoreApi { Future getOrderById(int orderId,) async { final response = await getOrderByIdWithHttpInfo(orderId,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'Order',) as Order; + return await apiClient.deserializeAsync(response.bodyBytes, 'Order',) as Order; } return null; @@ -220,13 +220,13 @@ class StoreApi { Future placeOrder(Order order,) async { final response = await placeOrderWithHttpInfo(order,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'Order',) as Order; + return await apiClient.deserializeAsync(response.bodyBytes, 'Order',) as Order; } return null; diff --git a/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/user_api.dart b/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/user_api.dart index a44252a6130b..f3574b90284b 100644 --- a/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/user_api.dart +++ b/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api/user_api.dart @@ -62,7 +62,7 @@ class UserApi { Future createUser(User user,) async { final response = await createUserWithHttpInfo(user,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -112,7 +112,7 @@ class UserApi { Future createUsersWithArrayInput(List user,) async { final response = await createUsersWithArrayInputWithHttpInfo(user,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -162,7 +162,7 @@ class UserApi { Future createUsersWithListInput(List user,) async { final response = await createUsersWithListInputWithHttpInfo(user,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -213,7 +213,7 @@ class UserApi { Future deleteUser(String username,) async { final response = await deleteUserWithHttpInfo(username,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -264,13 +264,13 @@ class UserApi { Future getUserByName(String username,) async { final response = await getUserByNameWithHttpInfo(username,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'User',) as User; + return await apiClient.deserializeAsync(response.bodyBytes, 'User',) as User; } return null; @@ -331,13 +331,13 @@ class UserApi { Future loginUser(String username, String password,) async { final response = await loginUserWithHttpInfo(username, password,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } // When a remote server returns no body with a status of 204, we shall not decode it. // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // FormatException when trying to decode an empty string. if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'String',) as String; + return await apiClient.deserializeAsync(response.bodyBytes, 'String',) as String; } return null; @@ -379,7 +379,7 @@ class UserApi { Future logoutUser() async { final response = await logoutUserWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } @@ -436,7 +436,7 @@ class UserApi { Future updateUser(String username, User user,) async { final response = await updateUserWithHttpInfo(username, user,); if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + throw ApiException(response.statusCode, decodeError(await response.bodyBytes)); } } } diff --git a/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api_client.dart b/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api_client.dart index 22839ae04f0b..834d2f4d850a 100644 --- a/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api_client.dart +++ b/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api_client.dart @@ -143,19 +143,25 @@ class ApiClient { ); } - Future deserializeAsync(String json, String targetType, {bool growable = false,}) async => + Future deserializeAsync(Uint8List responseBytes, String targetType, {bool growable = false,}) async => // ignore: deprecated_member_use_from_same_package - deserialize(json, targetType, growable: growable); + deserialize(responseBytes, targetType, growable: growable); @Deprecated('Scheduled for removal in OpenAPI Generator 6.x. Use deserializeAsync() instead.') - dynamic deserialize(String json, String targetType, {bool growable = false,}) { + dynamic deserialize(Uint8List responseBytes, String targetType, {bool growable = false,}) { // Remove all spaces. Necessary for regular expressions as well. targetType = targetType.replaceAll(' ', ''); // ignore: parameter_assignments + // if the expected target type is a byte-array, then just return the response bytes as-is + if (targetType == 'Uint8List') { + return responseBytes; + } + + final decodedString = const Utf8Decoder().convert(responseBytes); // If the expected target type is String, nothing to do... return targetType == 'String' - ? json - : _deserialize(jsonDecode(json), targetType, growable: growable); + ? decodedString + : _deserialize(jsonDecode(decodedString), targetType, growable: growable); } // ignore: deprecated_member_use_from_same_package diff --git a/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api_helper.dart b/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api_helper.dart index 4a29277289d8..45eb19409d27 100644 --- a/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api_helper.dart +++ b/samples/openapi3/client/petstore/dart2/petstore_client_lib_fake/lib/api_helper.dart @@ -76,13 +76,10 @@ String parameterToString(dynamic value) { return value.toString(); } -/// Returns the decoded body as UTF-8 if the given headers indicate an 'application/json' -/// content type. Otherwise, returns the decoded body as decoded by dart:http package. -Future _decodeBodyBytes(Response response) async { - final contentType = response.headers['content-type']; - return contentType != null && contentType.toLowerCase().startsWith('application/json') - ? response.bodyBytes.isEmpty ? '' : utf8.decode(response.bodyBytes) - : response.body; +/// Decodes the response body for error reporting purposes. +/// Decodes as UTF-8 but allows for malformed bytes to avoid crashing. +String decodeError(Uint8List responseBytes) { + return const Utf8Decoder(allowMalformed: true).convert(responseBytes); } /// Returns a valid [T] value found at the specified Map [key], null otherwise. From 235d4fd3d86a9ec4cc4fd9580467d4ed05ec994c Mon Sep 17 00:00:00 2001 From: 0xNF Date: Tue, 20 Sep 2022 09:43:59 +0900 Subject: [PATCH 3/3] [Dart] Re-added in missing Uint8 list imports in DartCodegen --- .../languages/AbstractDartCodegen.java | 184 ++++++++++++------ 1 file changed, 120 insertions(+), 64 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 5559d7f3ebe2..f3cb2ba67a46 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 @@ -1,16 +1,41 @@ package org.openapitools.codegen.languages; -import com.google.common.collect.Sets; -import io.swagger.v3.oas.models.Operation; -import io.swagger.v3.oas.models.media.ArraySchema; -import io.swagger.v3.oas.models.media.ComposedSchema; -import io.swagger.v3.oas.models.media.Schema; -import io.swagger.v3.oas.models.media.StringSchema; -import io.swagger.v3.oas.models.servers.Server; +import static org.openapitools.codegen.utils.StringUtils.camelize; +import static org.openapitools.codegen.utils.StringUtils.escape; +import static org.openapitools.codegen.utils.StringUtils.underscore; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; -import org.openapitools.codegen.*; -import org.openapitools.codegen.meta.features.*; +import org.openapitools.codegen.CodegenConstants; +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenOperation; +import org.openapitools.codegen.CodegenParameter; +import org.openapitools.codegen.CodegenProperty; +import org.openapitools.codegen.CodegenResponse; +import org.openapitools.codegen.CodegenType; +import org.openapitools.codegen.DefaultCodegen; +import org.openapitools.codegen.GeneratorLanguage; +import org.openapitools.codegen.meta.features.ClientModificationFeature; +import org.openapitools.codegen.meta.features.DocumentationFeature; +import org.openapitools.codegen.meta.features.GlobalFeature; +import org.openapitools.codegen.meta.features.ParameterFeature; +import org.openapitools.codegen.meta.features.SchemaSupportFeature; +import org.openapitools.codegen.meta.features.SecurityFeature; +import org.openapitools.codegen.meta.features.WireFormatFeature; import org.openapitools.codegen.model.ModelMap; import org.openapitools.codegen.model.ModelsMap; import org.openapitools.codegen.model.OperationMap; @@ -19,16 +44,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import com.google.common.collect.Sets; -import static org.openapitools.codegen.utils.StringUtils.*; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.ComposedSchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.media.StringSchema; +import io.swagger.v3.oas.models.servers.Server; public abstract class AbstractDartCodegen extends DefaultCodegen { @@ -72,29 +95,22 @@ public AbstractDartCodegen() { SecurityFeature.OAuth2_Implicit, SecurityFeature.BasicAuth, SecurityFeature.BearerToken, - SecurityFeature.ApiKey - )) + SecurityFeature.ApiKey)) .excludeGlobalFeatures( GlobalFeature.XMLStructureDefinitions, GlobalFeature.Callbacks, GlobalFeature.LinkObjects, - GlobalFeature.ParameterStyling - ) + GlobalFeature.ParameterStyling) .excludeSchemaSupportFeatures( SchemaSupportFeature.Polymorphism, SchemaSupportFeature.Union, - SchemaSupportFeature.Composite - ) + SchemaSupportFeature.Composite) .includeParameterFeatures( - ParameterFeature.Cookie - ) + ParameterFeature.Cookie) .includeClientModificationFeatures( - ClientModificationFeature.BasePath - ) + ClientModificationFeature.BasePath) .excludeWireFormatFeatures( - WireFormatFeature.XML - ) - ); + WireFormatFeature.XML)); outputFolder = "generated-code/dart"; modelTemplateFiles.put("model.mustache", ".dart"); @@ -126,8 +142,7 @@ public AbstractDartCodegen() { "bool", "int", "num", - "double" - ); + "double"); typeMapping = new HashMap<>(); typeMapping.put("Array", "List"); @@ -149,11 +164,11 @@ public AbstractDartCodegen() { typeMapping.put("Date", "DateTime"); typeMapping.put("date", "DateTime"); typeMapping.put("DateTime", "DateTime"); - typeMapping.put("file", "MultipartFile"); - typeMapping.put("binary", "MultipartFile"); + typeMapping.put("file", "Uint8List"); + typeMapping.put("binary", "Uint8List"); typeMapping.put("UUID", "String"); typeMapping.put("URI", "String"); - typeMapping.put("ByteArray", "String"); + typeMapping.put("ByteArray", "Uint8List"); typeMapping.put("object", "Object"); typeMapping.put("AnyType", "Object"); @@ -168,8 +183,7 @@ public AbstractDartCodegen() { "Set", "Map", "DateTime", - "Object" - ); + "Object"); imports.put("String", "dart:core"); imports.put("bool", "dart:core"); @@ -181,6 +195,7 @@ public AbstractDartCodegen() { imports.put("Map", "dart:core"); imports.put("DateTime", "dart:core"); imports.put("Object", "dart:core"); + imports.put("Uint8List", "dart:typed_data"); imports.put("MultipartFile", "package:http/http.dart"); addOption(PUB_LIBRARY, "Library name in generated code", pubLibrary); @@ -190,7 +205,8 @@ public AbstractDartCodegen() { addOption(PUB_AUTHOR, "Author name in generated pubspec", pubAuthor); addOption(PUB_AUTHOR_EMAIL, "Email address of the author in generated pubspec", pubAuthorEmail); addOption(PUB_HOMEPAGE, "Homepage in generated pubspec", pubHomepage); - addOption(USE_ENUM_EXTENSION, "Allow the 'x-enum-values' extension for enums", String.valueOf(useEnumExtension)); + addOption(USE_ENUM_EXTENSION, "Allow the 'x-enum-values' extension for enums", + String.valueOf(useEnumExtension)); addOption(CodegenConstants.SOURCE_FOLDER, CodegenConstants.SOURCE_FOLDER_DESC, sourceFolder); } @@ -221,56 +237,58 @@ public void processOpts() { additionalProperties.put(CodegenConstants.API_PACKAGE, apiPackage); if (StringUtils.isEmpty(System.getenv("DART_POST_PROCESS_FILE"))) { - LOGGER.info("Environment variable DART_POST_PROCESS_FILE not defined so the Dart code may not be properly formatted. To define it, try `export DART_POST_PROCESS_FILE=\"/usr/local/bin/dartfmt -w\"` (Linux/Mac)"); - LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI)."); + LOGGER.info( + "Environment variable DART_POST_PROCESS_FILE not defined so the Dart code may not be properly formatted. To define it, try `export DART_POST_PROCESS_FILE=\"/usr/local/bin/dartfmt -w\"` (Linux/Mac)"); + LOGGER.info( + "NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI)."); } if (additionalProperties.containsKey(PUB_NAME)) { this.setPubName((String) additionalProperties.get(PUB_NAME)); } else { - //not set, use to be passed to template + // not set, use to be passed to template additionalProperties.put(PUB_NAME, pubName); } if (additionalProperties.containsKey(PUB_LIBRARY)) { this.setPubLibrary((String) additionalProperties.get(PUB_LIBRARY)); } else { - //not set, use to be passed to template + // not set, use to be passed to template additionalProperties.put(PUB_LIBRARY, pubLibrary); } if (additionalProperties.containsKey(PUB_VERSION)) { this.setPubVersion((String) additionalProperties.get(PUB_VERSION)); } else { - //not set, use to be passed to template + // not set, use to be passed to template additionalProperties.put(PUB_VERSION, pubVersion); } if (additionalProperties.containsKey(PUB_DESCRIPTION)) { this.setPubDescription((String) additionalProperties.get(PUB_DESCRIPTION)); } else { - //not set, use to be passed to template + // not set, use to be passed to template additionalProperties.put(PUB_DESCRIPTION, pubDescription); } if (additionalProperties.containsKey(PUB_AUTHOR)) { this.setPubAuthor((String) additionalProperties.get(PUB_AUTHOR)); } else { - //not set, use to be passed to template + // not set, use to be passed to template additionalProperties.put(PUB_AUTHOR, pubAuthor); } if (additionalProperties.containsKey(PUB_AUTHOR_EMAIL)) { this.setPubAuthorEmail((String) additionalProperties.get(PUB_AUTHOR_EMAIL)); } else { - //not set, use to be passed to template + // not set, use to be passed to template additionalProperties.put(PUB_AUTHOR_EMAIL, pubAuthorEmail); } if (additionalProperties.containsKey(PUB_HOMEPAGE)) { this.setPubHomepage((String) additionalProperties.get(PUB_HOMEPAGE)); } else { - //not set, use to be passed to template + // not set, use to be passed to template additionalProperties.put(PUB_HOMEPAGE, pubHomepage); } @@ -309,7 +327,8 @@ protected boolean isReservedWord(String word) { // * a keyword // * a word that has been mapped in the reservedWordsMappings // * a default included type or a type include through some library - return super.isReservedWord(word) || reservedWordsMappings().containsKey(word) || defaultIncludes().contains(word); + return super.isReservedWord(word) || reservedWordsMappings().containsKey(word) + || defaultIncludes().contains(word); } @Override @@ -322,12 +341,14 @@ public String escapeReservedWord(String name) { @Override public String apiFileFolder() { - return (outputFolder + File.separator + libPath + sourceFolder + File.separator + apiPackage()).replace('/', File.separatorChar); + return (outputFolder + File.separator + libPath + sourceFolder + File.separator + apiPackage()).replace('/', + File.separatorChar); } @Override public String modelFileFolder() { - return (outputFolder + File.separator + libPath + sourceFolder + File.separator + modelPackage()).replace('/', File.separatorChar); + return (outputFolder + File.separator + libPath + sourceFolder + File.separator + modelPackage()).replace('/', + File.separatorChar); } @Override @@ -433,7 +454,8 @@ public String toModelName(final String name) { // model name starts with number if (camelizedName.matches("^\\d.*")) { final String modelName = "Model" + camelizedName; // e.g. 200Response => Model200Response (after camelize) - LOGGER.warn("{} (model name starts with number) cannot be used as model name. Renamed to {}", name, modelName); + LOGGER.warn("{} (model name starts with number) cannot be used as model name. Renamed to {}", name, + modelName); return modelName; } @@ -496,11 +518,13 @@ public String getTypeDeclaration(Schema p) { return getSchemaType(target) + "<" + getTypeDeclaration(items) + ">"; } if (ModelUtils.isMapSchema(target)) { - // Note: ModelUtils.isMapSchema(p) returns true when p is a composed schema that also defines + // Note: ModelUtils.isMapSchema(p) returns true when p is a composed schema that + // also defines // additionalproperties: true Schema inner = getAdditionalProperties(target); if (inner == null) { - LOGGER.error("`{}` (map property) does not have a proper inner type defined. Default to type:string", p.getName()); + LOGGER.error("`{}` (map property) does not have a proper inner type defined. Default to type:string", + p.getName()); inner = new StringSchema().description("TODO default missing map inner type to string"); p.setAdditionalProperties(inner); } @@ -530,17 +554,22 @@ public ModelsMap postProcessModels(ModelsMap objs) { public void postProcessModelProperty(CodegenModel model, CodegenProperty property) { super.postProcessModelProperty(model, property); if (!model.isEnum && property.isEnum && property.getComposedSchemas() == null) { - // These are inner enums, enums which do not exist as models, just as properties. + // These are inner enums, enums which do not exist as models, just as + // properties. // 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 + // 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. - // Also taking into account potential collection types e.g. List -> List + // Here the datatypeWithEnum template variable gets updated to match that + // scheme. + // Also taking into account potential collection types e.g. List + // -> List final String enumName = model.classname + property.enumName; if (property.items != null) { // inner items e.g. enums in collections, only works for one level // but same is the case for DefaultCodegen - property.setDatatypeWithEnum(property.datatypeWithEnum.replace(property.items.datatypeWithEnum, enumName)); + property.setDatatypeWithEnum( + property.datatypeWithEnum.replace(property.items.datatypeWithEnum, enumName)); property.items.setDatatypeWithEnum(enumName); property.items.setEnumName(enumName); } else { @@ -586,8 +615,10 @@ public CodegenProperty fromProperty(String name, Schema p, boolean required) { 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. - // Add all container type imports here, by default 'dart:core' imports are skipped + // 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 require specific container type imports. if (r.containerType != null && typeMapping().containsKey(r.containerType)) { final String value = typeMapping().get(r.containerType); @@ -618,6 +649,27 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List ops = operations.getOperation(); for (CodegenOperation op : ops) { + + for (CodegenParameter param : op.allParams) { + if (((op.isMultipart && param.isFormParam) || param.isBodyParam) + && (param.isBinary || param.isFile)) { + param.dataType = param.dataType.replace("Uint8List", "MultipartFile"); + param.baseType = param.baseType.replace("Uint8List", "MultipartFile"); + op.imports.add("MultipartFile"); + } + } + // The MultipartFile handling above changes the type of some parameters from + // `UInt8List`, the default for files, to `MultipartFile`. + // + // The following block removes the required import for Uint8List if it is no + // longer in use. + if (op.allParams.stream().noneMatch(param -> param.dataType.equals("Uint8List")) + && op.responses.stream().filter(response -> response.dataType != null) + .noneMatch(response -> response.dataType.equals("Uint8List"))) { + // Remove unused imports after processing + op.imports.remove("Uint8List"); + } + if (op.hasConsumes) { if (!op.formParams.isEmpty() || op.isMultipart) { // DefaultCodegen only sets this if the first consumes mediaType @@ -630,7 +682,9 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List> prioritizeContentTypes(List> enumVars, Map vendorExtensions, String dataType) { + protected void updateEnumVarsWithExtensions(List> enumVars, + Map vendorExtensions, String dataType) { if (vendorExtensions != null && useEnumExtension && vendorExtensions.containsKey("x-enum-values")) { // Use the x-enum-values extension for this enum // Existing enumVars added by the default handling need to be removed first @@ -733,7 +788,8 @@ public String toOperationId(String operationId) { // operationId starts with a number if (operationId.matches("^\\d.*")) { String newOperationId = camelize("call_" + operationId, true); - LOGGER.warn("{} (starting with a number) cannot be used as method name. Renamed to {}", operationId, newOperationId); + LOGGER.warn("{} (starting with a number) cannot be used as method name. Renamed to {}", operationId, + newOperationId); operationId = newOperationId; }