Skip to content

Commit

Permalink
Fix generic argument factories support (#643)
Browse files Browse the repository at this point in the history
* Don't shorten "annotation"

* Support generic argument factories irrespective of `@JsonSerializable` annotations
  • Loading branch information
TekExplorer authored Dec 6, 2023
1 parent 0e64527 commit a32574e
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 22 deletions.
16 changes: 11 additions & 5 deletions generator/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 8.0.3

- fix [#627](https://github.com/trevorwang/retrofit.dart/issues/627) where generic argument constructors on any class not directly marked with `@JsonSerializable(genericArgumentFactories: true)`

- fix some typos in this changelog.

## 8.0.2

- fix #630 Null check operator used on a null value
Expand Down Expand Up @@ -123,7 +129,7 @@

## 2.0.0-beta1

- Nullsafety support
- Null safety support

## 1.4.1

Expand All @@ -135,7 +141,7 @@

## 1.3.8

- Send list params duplicative in multipart
- Send list params duplication in multipart

## 1.3.7

Expand Down Expand Up @@ -190,7 +196,7 @@

## 1.2.0

- Add `HttpReposne` to handle the original response
- Add `HttpResponse` to handle the original response

## 1.1.0

Expand Down Expand Up @@ -253,11 +259,11 @@ Added bean class support for `@Body()` annotation.

Here's the example.

```
```dart
Future<String> createUser(@Body() User user);
```

```
```dart
class User {
Map<String, dynamic> toJson() => {};
}
Expand Down
63 changes: 47 additions & 16 deletions generator/lib/src/generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import 'package:built_collection/built_collection.dart';
import 'package:code_builder/code_builder.dart';
import 'package:dart_style/dart_style.dart';
import 'package:dio/dio.dart';
import 'package:protobuf/protobuf.dart';
import 'package:retrofit/retrofit.dart' as retrofit;
import 'package:source_gen/source_gen.dart';
import 'package:tuple/tuple.dart';
import 'package:protobuf/protobuf.dart';

const _analyzerIgnores =
'// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers';
Expand Down Expand Up @@ -93,20 +93,20 @@ class RetrofitGenerator extends GeneratorForAnnotation<retrofit.RestApi> {
parser: parser ?? retrofit.Parser.JsonSerializable,
);
final baseUrl = clientAnnotation.baseUrl;
final annotClassConsts = element.constructors
final annotateClassConsts = element.constructors
.where((c) => !c.isFactory && !c.isDefaultConstructor);
final classBuilder = Class((c) {
c
..name = className
..types.addAll(element.typeParameters.map((e) => refer(e.name)))
..fields.addAll([_buildDioFiled(), _buildBaseUrlFiled(baseUrl)])
..constructors.addAll(
annotClassConsts.map(
annotateClassConsts.map(
(e) => _generateConstructor(baseUrl, superClassConst: e),
),
)
..methods.addAll(_parseMethods(element));
if (annotClassConsts.isEmpty) {
if (annotateClassConsts.isEmpty) {
c.constructors.add(_generateConstructor(baseUrl));
c.implements.add(refer(_generateTypeParameterizedName(element)));
} else {
Expand Down Expand Up @@ -205,8 +205,8 @@ class RetrofitGenerator extends GeneratorForAnnotation<retrofit.RestApi> {
...element.methods,
...element.mixins.expand((i) => i.methods)
].where((m) {
final methodAnnot = _getMethodAnnotation(m);
return methodAnnot != null &&
final methodAnnotation = _getMethodAnnotation(m);
return methodAnnotation != null &&
m.isAbstract &&
(m.returnType.isDartAsyncFuture || m.returnType.isDartAsyncStream);
}).map((m) => _generateMethod(m)!);
Expand All @@ -232,19 +232,19 @@ class RetrofitGenerator extends GeneratorForAnnotation<retrofit.RestApi> {

ConstantReader? _getMethodAnnotation(MethodElement method) {
for (final type in _methodsAnnotations) {
final annot = _getMethodAnnotationByType(method, type);
if (annot != null) {
return annot;
final annotation = _getMethodAnnotationByType(method, type);
if (annotation != null) {
return annotation;
}
}
return null;
}

ConstantReader? _getMethodAnnotationByType(MethodElement method, Type type) {
final annot =
final annotation =
_typeChecker(type).firstAnnotationOf(method, throwOnUnresolved: false);
if (annot != null) {
return ConstantReader(annot);
if (annotation != null) {
return ConstantReader(annotation);
}
return null;
}
Expand Down Expand Up @@ -286,14 +286,14 @@ class RetrofitGenerator extends GeneratorForAnnotation<retrofit.RestApi> {
MethodElement m,
Type type,
) {
final annot = <ParameterElement, ConstantReader>{};
final annotation = <ParameterElement, ConstantReader>{};
for (final p in m.parameters) {
final a = _typeChecker(type).firstAnnotationOf(p);
if (a != null) {
annot[p] = ConstantReader(a);
annotation[p] = ConstantReader(a);
}
}
return annot;
return annotation;
}

Tuple2<ParameterElement, ConstantReader>? _getAnnotation(
Expand Down Expand Up @@ -980,7 +980,38 @@ You should create a new class to encapsulate the response.
} catch (_) {}
}

return genericArgumentFactories;
return genericArgumentFactories ||
hasGenericArgumentFactoriesCompatibleSignature(dartType);
}

/// Checks for a compatible fromJson signature for generic argument factories
// TODO: But does the code work with multiple generic types?
bool hasGenericArgumentFactoriesCompatibleSignature(DartType? dartType) {
if (dartType == null) return false;
final element = dartType.element;
if (element is! InterfaceElement) return false;

final typeParameters = element.typeParameters;
if (typeParameters.isEmpty) return false;

final constructors = element.constructors;
if (constructors.isEmpty) return false;
final fromJson = constructors
.firstWhereOrNull((constructor) => constructor.name == 'fromJson');

if (fromJson == null || fromJson.parameters.length == 1) return false;

final fromJsonArguments = fromJson.parameters;

if (typeParameters.length != (fromJsonArguments.length - 1)) {
// TODO: better error. theoretically this should never be hit
// "invalid fromJson"?
// throw Exception(
// 'Not the right amount of arguments: \n$typeParameters\n$fromJsonArguments');
// throw Exception('Invalid fromJson found');
return false; // or error? we shouldn't get here at all, theoretically
}
return true;
}

String _getInnerJsonSerializableMapperFn(DartType dartType) {
Expand Down
2 changes: 1 addition & 1 deletion generator/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ topics:
- build-runner
- codegen
- api
version: 8.0.1
version: 8.0.3
environment:
sdk: '>=2.19.0 <4.0.0'

Expand Down

0 comments on commit a32574e

Please sign in to comment.