Skip to content

Commit

Permalink
[dart] Fix api client deserialization for json_serializable (#8882)
Browse files Browse the repository at this point in the history
* Fix api-client deserialization for json_serializable

* Use raw string for url path

* Use Set/List.of

* Use returnTypeIsPrimitive in template

* Regenerate all templates

* Fix casting map to Iterable of things

* Add json_serializable to maven modules

* Run build_runner before pub run test

* Return future of type for strong linter mode
  • Loading branch information
agilob authored Mar 11, 2021
1 parent f7a6b7f commit b782cff
Show file tree
Hide file tree
Showing 31 changed files with 433 additions and 453 deletions.
46 changes: 36 additions & 10 deletions modules/openapi-generator/src/main/resources/dart2/api.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class {{{classname}}} {
{{/allParams}}

{{/hasParams}}
final path = '{{{path}}}'{{#pathParams}}
final path = r'{{{path}}}'{{#pathParams}}
.replaceAll('{' + '{{{baseName}}}' + '}', {{{paramName}}}.toString()){{/pathParams}};

Object postBody{{#bodyParam}} = {{{paramName}}}{{/bodyParam}};
Expand Down Expand Up @@ -185,21 +185,47 @@ class {{{classname}}} {
// 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 != null && response.statusCode != HttpStatus.noContent) {
{{#isArray}}
{{#native_serialization}}
{{#isArray}}
return (apiClient.deserialize(_decodeBodyBytes(response), '{{{returnType}}}') as List)
.cast<{{{returnBaseType}}}>()
.{{#uniqueItems}}toSet(){{/uniqueItems}}{{^uniqueItems}}toList(growable: false){{/uniqueItems}};
{{/isArray}}
{{^isArray}}
{{#isMap}}
{{/isArray}}
{{^isArray}}
{{#isMap}}
return {{{returnType}}}.from(apiClient.deserialize(_decodeBodyBytes(response), '{{{returnType}}}'));
{{/isMap}}
{{^isMap}}
{{/isMap}}
{{^isMap}}
return apiClient.deserialize(_decodeBodyBytes(response), '{{{returnType}}}') as {{{returnType}}};
{{/isMap}}
{{/isArray}}
{{/isMap}}{{/isArray}}{{/native_serialization}}{{#json_serializable}}
{{#isArray}}
{{#uniqueItems}}
return (json.decode(response.body) as List)
.map((i) => {{{returnBaseType}}}.fromJson(i))
.toSet();
{{/uniqueItems}}
{{^uniqueItems}}
return (json.decode(response.body) as List)
.map((i) => {{{returnBaseType}}}.fromJson(i))
.toList();
{{/uniqueItems}}
{{/isArray}}
{{^isArray}}
{{#isMap}}
return {{{returnType}}}.from(json.decode(response.body));
{{/isMap}}
{{^isMap}}
{{#returnTypeIsPrimitive}}
return response.body as {{{returnBaseType}}};
{{/returnTypeIsPrimitive}}
{{^returnTypeIsPrimitive}}
return {{{returnType}}}.fromJson(json.decode(response.body));
{{/returnTypeIsPrimitive}}
{{/isMap}}
{{/isArray}}
{{/json_serializable}}
}
return null;
return Future<{{{returnType}}}>.value(null);
{{/returnType}}
}
{{/operation}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,6 @@ class ApiClient {
Map<String, Authentication> get authentications =>
Map.unmodifiable(_authentications);

dynamic deserialize(String json, String targetType, {bool growable}) {
// Remove all spaces. Necessary for reg expressions as well.
targetType = targetType.replaceAll(' ', '');
return targetType == 'String'
? json
: _deserialize(jsonDecode(json), targetType, growable: true == growable);
}

String serialize(Object obj) => obj == null ? '' : json.encode(obj);

T getAuthentication<T extends Authentication>(String name) {
final authentication = _authentications[name];
return authentication is T ? authentication : null;
Expand Down Expand Up @@ -159,6 +148,7 @@ class ApiClient {
throw ApiException(HttpStatus.badRequest, 'Invalid HTTP operation: $method $path',);
}

{{#native_serialization}}
dynamic _deserialize(dynamic value, String targetType, {bool growable}) {
try {
switch (targetType) {
Expand Down Expand Up @@ -216,6 +206,18 @@ class ApiClient {
throw ApiException(HttpStatus.internalServerError, 'Could not find a suitable class for deserialization',);
}

dynamic deserialize(String json, String targetType, {bool growable}) {
// Remove all spaces. Necessary for reg expressions as well.
targetType = targetType.replaceAll(' ', '');
return targetType == 'String'
? json
: _deserialize(jsonDecode(json), targetType, growable: true == growable);
}
{{/native_serialization}}

String serialize(Object obj) => obj == null ? '' : json.encode(obj);

/// Update query and header parameters based on authentication settings.
/// @param authNames The authentications to apply
void _updateParamsForAuth(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@ String parameterToString(dynamic value) {
{{#model}}
{{#isEnum}}
if (value is {{{classname}}}) {
{{#native_serialization}} return {{{classname}}}TypeTransformer().encode(value).toString();{{/native_serialization}}
{{#json_serializable}} return _${{{classname}}}EnumMap[value];{{/json_serializable}}
{{#native_serialization}} return {{{classname}}}TypeTransformer().encode(value).toString();{{/native_serialization}}{{#json_serializable}} return value.toString();{{/json_serializable}}
}
{{/isEnum}}
{{/model}}
Expand Down
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1353,6 +1353,7 @@
<module>samples/client/petstore/dart2/petstore</module>
<module>samples/openapi3/client/petstore/dart2/petstore_client_lib</module>
<module>samples/openapi3/client/petstore/dart2/petstore</module>
<module>samples/openapi3/client/petstore/dart2/petstore_json_serializable_client_lib_fake</module>
<module>samples/client/petstore/dart-dio/petstore_client_lib</module>
<module>samples/openapi3/client/petstore/dart-dio/petstore_client_lib</module>
<module>samples/openapi3/client/petstore/dart-dio/petstore_client_lib_fake</module>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class PetApi {
throw ApiException(HttpStatus.badRequest, 'Missing required param: body');
}

final path = '/pet';
final path = r'/pet';

Object postBody = body;

Expand Down Expand Up @@ -94,7 +94,7 @@ class PetApi {
throw ApiException(HttpStatus.badRequest, 'Missing required param: petId');
}

final path = '/pet/{petId}'
final path = r'/pet/{petId}'
.replaceAll('{' + 'petId' + '}', petId.toString());

Object postBody;
Expand Down Expand Up @@ -166,7 +166,7 @@ class PetApi {
throw ApiException(HttpStatus.badRequest, 'Missing required param: status');
}

final path = '/pet/findByStatus';
final path = r'/pet/findByStatus';

Object postBody;

Expand Down Expand Up @@ -225,7 +225,7 @@ class PetApi {
.cast<Pet>()
.toList(growable: false);
}
return null;
return Future<List<Pet>>.value(null);
}

/// Finds Pets by tags
Expand All @@ -244,7 +244,7 @@ class PetApi {
throw ApiException(HttpStatus.badRequest, 'Missing required param: tags');
}

final path = '/pet/findByTags';
final path = r'/pet/findByTags';

Object postBody;

Expand Down Expand Up @@ -303,7 +303,7 @@ class PetApi {
.cast<Pet>()
.toList(growable: false);
}
return null;
return Future<List<Pet>>.value(null);
}

/// Find pet by ID
Expand All @@ -322,7 +322,7 @@ class PetApi {
throw ApiException(HttpStatus.badRequest, 'Missing required param: petId');
}

final path = '/pet/{petId}'
final path = r'/pet/{petId}'
.replaceAll('{' + 'petId' + '}', petId.toString());

Object postBody;
Expand Down Expand Up @@ -377,8 +377,8 @@ class PetApi {
// FormatException when trying to decode an empty string.
if (response.body != null && response.statusCode != HttpStatus.noContent) {
return apiClient.deserialize(_decodeBodyBytes(response), 'Pet') as Pet;
}
return null;
}
return Future<Pet>.value(null);
}

/// Update an existing pet
Expand All @@ -395,7 +395,7 @@ class PetApi {
throw ApiException(HttpStatus.badRequest, 'Missing required param: body');
}

final path = '/pet';
final path = r'/pet';

Object postBody = body;

Expand Down Expand Up @@ -464,7 +464,7 @@ class PetApi {
throw ApiException(HttpStatus.badRequest, 'Missing required param: petId');
}

final path = '/pet/{petId}'
final path = r'/pet/{petId}'
.replaceAll('{' + 'petId' + '}', petId.toString());

Object postBody;
Expand Down Expand Up @@ -554,7 +554,7 @@ class PetApi {
throw ApiException(HttpStatus.badRequest, 'Missing required param: petId');
}

final path = '/pet/{petId}/uploadImage'
final path = r'/pet/{petId}/uploadImage'
.replaceAll('{' + 'petId' + '}', petId.toString());

Object postBody;
Expand Down Expand Up @@ -625,7 +625,7 @@ class PetApi {
// FormatException when trying to decode an empty string.
if (response.body != null && response.statusCode != HttpStatus.noContent) {
return apiClient.deserialize(_decodeBodyBytes(response), 'ApiResponse') as ApiResponse;
}
return null;
}
return Future<ApiResponse>.value(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class StoreApi {
throw ApiException(HttpStatus.badRequest, 'Missing required param: orderId');
}

final path = '/store/order/{orderId}'
final path = r'/store/order/{orderId}'
.replaceAll('{' + 'orderId' + '}', orderId.toString());

Object postBody;
Expand Down Expand Up @@ -89,7 +89,7 @@ class StoreApi {
///
/// Note: This method returns the HTTP [Response].
Future<Response> getInventoryWithHttpInfo() async {
final path = '/store/inventory';
final path = r'/store/inventory';

Object postBody;

Expand Down Expand Up @@ -139,7 +139,7 @@ class StoreApi {
if (response.body != null && response.statusCode != HttpStatus.noContent) {
return Map<String, int>.from(apiClient.deserialize(_decodeBodyBytes(response), 'Map<String, int>'));
}
return null;
return Future<Map<String, int>>.value(null);
}

/// Find purchase order by ID
Expand All @@ -158,7 +158,7 @@ class StoreApi {
throw ApiException(HttpStatus.badRequest, 'Missing required param: orderId');
}

final path = '/store/order/{orderId}'
final path = r'/store/order/{orderId}'
.replaceAll('{' + 'orderId' + '}', orderId.toString());

Object postBody;
Expand Down Expand Up @@ -213,8 +213,8 @@ class StoreApi {
// FormatException when trying to decode an empty string.
if (response.body != null && response.statusCode != HttpStatus.noContent) {
return apiClient.deserialize(_decodeBodyBytes(response), 'Order') as Order;
}
return null;
}
return Future<Order>.value(null);
}

/// Place an order for a pet
Expand All @@ -231,7 +231,7 @@ class StoreApi {
throw ApiException(HttpStatus.badRequest, 'Missing required param: body');
}

final path = '/store/order';
final path = r'/store/order';

Object postBody = body;

Expand Down Expand Up @@ -283,7 +283,7 @@ class StoreApi {
// FormatException when trying to decode an empty string.
if (response.body != null && response.statusCode != HttpStatus.noContent) {
return apiClient.deserialize(_decodeBodyBytes(response), 'Order') as Order;
}
return null;
}
return Future<Order>.value(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class UserApi {
throw ApiException(HttpStatus.badRequest, 'Missing required param: body');
}

final path = '/user';
final path = r'/user';

Object postBody = body;

Expand Down Expand Up @@ -96,7 +96,7 @@ class UserApi {
throw ApiException(HttpStatus.badRequest, 'Missing required param: body');
}

final path = '/user/createWithArray';
final path = r'/user/createWithArray';

Object postBody = body;

Expand Down Expand Up @@ -159,7 +159,7 @@ class UserApi {
throw ApiException(HttpStatus.badRequest, 'Missing required param: body');
}

final path = '/user/createWithList';
final path = r'/user/createWithList';

Object postBody = body;

Expand Down Expand Up @@ -224,7 +224,7 @@ class UserApi {
throw ApiException(HttpStatus.badRequest, 'Missing required param: username');
}

final path = '/user/{username}'
final path = r'/user/{username}'
.replaceAll('{' + 'username' + '}', username.toString());

Object postBody;
Expand Down Expand Up @@ -290,7 +290,7 @@ class UserApi {
throw ApiException(HttpStatus.badRequest, 'Missing required param: username');
}

final path = '/user/{username}'
final path = r'/user/{username}'
.replaceAll('{' + 'username' + '}', username.toString());

Object postBody;
Expand Down Expand Up @@ -343,8 +343,8 @@ class UserApi {
// FormatException when trying to decode an empty string.
if (response.body != null && response.statusCode != HttpStatus.noContent) {
return apiClient.deserialize(_decodeBodyBytes(response), 'User') as User;
}
return null;
}
return Future<User>.value(null);
}

/// Logs user into the system
Expand All @@ -367,7 +367,7 @@ class UserApi {
throw ApiException(HttpStatus.badRequest, 'Missing required param: password');
}

final path = '/user/login';
final path = r'/user/login';

Object postBody;

Expand Down Expand Up @@ -425,15 +425,15 @@ class UserApi {
// FormatException when trying to decode an empty string.
if (response.body != null && response.statusCode != HttpStatus.noContent) {
return apiClient.deserialize(_decodeBodyBytes(response), 'String') as String;
}
return null;
}
return Future<String>.value(null);
}

/// Logs out current logged in user session
///
/// Note: This method returns the HTTP [Response].
Future<Response> logoutUserWithHttpInfo() async {
final path = '/user/logout';
final path = r'/user/logout';

Object postBody;

Expand Down Expand Up @@ -499,7 +499,7 @@ class UserApi {
throw ApiException(HttpStatus.badRequest, 'Missing required param: body');
}

final path = '/user/{username}'
final path = r'/user/{username}'
.replaceAll('{' + 'username' + '}', username.toString());

Object postBody = body;
Expand Down
Loading

0 comments on commit b782cff

Please sign in to comment.