Skip to content

Commit

Permalink
Improve error message when @JsonSerializable is used with generics (#715
Browse files Browse the repository at this point in the history
)

Follow-up on #714

Also drop use of `InvalidGenerationSourceError.todo`

See dart-lang/source_gen#480
  • Loading branch information
kevmoo authored Sep 10, 2020
1 parent 295b264 commit 9f6c8b9
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 30 deletions.
29 changes: 23 additions & 6 deletions json_serializable/lib/src/helper_core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,33 @@ InvalidGenerationSourceError createInvalidGenerationError(
UnsupportedTypeError e,
) {
var message = 'Could not generate `$targetMember` code for `${field.name}`';
if (field.type != e.type) {
String todo;

if (e.type is TypeParameterType) {
message = '$message because of type `${e.type.getDisplayString()}` '
'(type parameter)';

todo = r'''
To support type paramaters (generic types) you can:
1) Use `JsonConverter`
https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonConverter-class.html
2) Use `JsonKey` fields `fromJson` and `toJson`
https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonKey/fromJson.html
https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonKey/toJson.html
3) Set `JsonSerializable.genericArgumentFactories` to `true`
https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonSerializable/genericArgumentFactories.html''';
} else if (field.type != e.type) {
message = '$message because of type `${typeToCode(e.type)}`';
}
message = '$message.\n${e.reason}';

final messageItems = [
'$message.',
e.reason,
if (todo != null) todo,
];

return InvalidGenerationSourceError(
message,
todo: 'Make sure all of the types are serializable.',
messageItems.join('\n'),
element: field,
);
}
Expand Down Expand Up @@ -126,8 +145,6 @@ String typeToCode(DartType type) {
final typeArgumentsCode = typeArguments.map(typeToCode).join(', ');
return '${type.element.name}<$typeArgumentsCode>';
}
} else if (type is TypeParameterType) {
return '${type.getDisplayString()} (type parameter)';
}
throw UnimplementedError('(${type.runtimeType}) $type');
}
14 changes: 7 additions & 7 deletions json_serializable/lib/src/json_serializable_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,10 @@ class JsonSerializableGenerator
BuildStep buildStep,
) {
if (element is! ClassElement) {
final name = element.name;
throw InvalidGenerationSourceError('Generator cannot target `$name`.',
todo: 'Remove the JsonSerializable annotation from `$name`.',
element: element);
throw InvalidGenerationSourceError(
'`@JsonSerializable` can only be used on classes.',
element: element,
);
}

final classElement = element as ClassElement;
Expand Down Expand Up @@ -186,9 +186,9 @@ class _GeneratorHelper extends HelperCore with EncodeHelper, DecodeHelper {
final jsonKey = nameAccess(fe);
if (!set.add(jsonKey)) {
throw InvalidGenerationSourceError(
'More than one field has the JSON key `$jsonKey`.',
todo: 'Check the `JsonKey` annotations on fields.',
element: fe);
'More than one field has the JSON key for name "$jsonKey".',
element: fe,
);
}
return set;
},
Expand Down
12 changes: 4 additions & 8 deletions json_serializable/test/src/_json_serializable_test_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,11 @@ part 'to_from_json_test_input.dart';

part 'unknown_enum_value_test_input.dart';

@ShouldThrow('Generator cannot target `theAnswer`.',
todo: 'Remove the JsonSerializable annotation from `theAnswer`.')
@ShouldThrow('`@JsonSerializable` can only be used on classes.')
@JsonSerializable()
const theAnswer = 42;

@ShouldThrow('Generator cannot target `annotatedMethod`.',
todo: 'Remove the JsonSerializable annotation from `annotatedMethod`.')
@ShouldThrow('`@JsonSerializable` can only be used on classes.')
@JsonSerializable()
Object annotatedMethod() => null;

Expand Down Expand Up @@ -271,8 +269,7 @@ class NoCtorClass {
}

@ShouldThrow(
'More than one field has the JSON key `str`.',
todo: 'Check the `JsonKey` annotations on fields.',
'More than one field has the JSON key for name "str".',
element: 'str',
)
@JsonSerializable(createFactory: false)
Expand All @@ -284,8 +281,7 @@ class KeyDupesField {
}

@ShouldThrow(
'More than one field has the JSON key `a`.',
todo: 'Check the `JsonKey` annotations on fields.',
'More than one field has the JSON key for name "a".',
element: 'str',
)
@JsonSerializable(createFactory: false)
Expand Down
6 changes: 0 additions & 6 deletions json_serializable/test/src/core_subclass_type_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ part of '_json_serializable_test_input.dart';
r'''
Could not generate `fromJson` code for `mapView`.
None of the provided `TypeHelper` instances support the defined type.''',
todo: 'Make sure all of the types are serializable.',
element: 'mapView',
)
@JsonSerializable(createToJson: false)
Expand All @@ -16,7 +15,6 @@ class UnsupportedMapField {
r'''
Could not generate `fromJson` code for `listView`.
None of the provided `TypeHelper` instances support the defined type.''',
todo: 'Make sure all of the types are serializable.',
element: 'listView',
)
@JsonSerializable(createToJson: false)
Expand All @@ -28,7 +26,6 @@ class UnsupportedListField {
r'''
Could not generate `fromJson` code for `customSet`.
None of the provided `TypeHelper` instances support the defined type.''',
todo: 'Make sure all of the types are serializable.',
element: 'customSet',
)
@JsonSerializable(createToJson: false)
Expand All @@ -42,7 +39,6 @@ abstract class _CustomSet implements Set {}
r'''
Could not generate `fromJson` code for `customDuration`.
None of the provided `TypeHelper` instances support the defined type.''',
todo: 'Make sure all of the types are serializable.',
element: 'customDuration',
)
@JsonSerializable(createToJson: false)
Expand All @@ -56,7 +52,6 @@ abstract class _CustomDuration implements Duration {}
r'''
Could not generate `fromJson` code for `customUri`.
None of the provided `TypeHelper` instances support the defined type.''',
todo: 'Make sure all of the types are serializable.',
element: 'customUri',
)
@JsonSerializable(createToJson: false)
Expand All @@ -70,7 +65,6 @@ abstract class _CustomUri implements Uri {}
r'''
Could not generate `fromJson` code for `customDateTime`.
None of the provided `TypeHelper` instances support the defined type.''',
todo: 'Make sure all of the types are serializable.',
element: 'customDateTime',
)
@JsonSerializable(createToJson: false)
Expand Down
15 changes: 12 additions & 3 deletions json_serializable/test/src/generic_test_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,18 @@
part of '_json_serializable_test_input.dart';

@ShouldThrow(
'Could not generate `fromJson` code for `result` because of type '
'`TResult (type parameter)`.\n'
'None of the provided `TypeHelper` instances support the defined type.',
r'''
Could not generate `fromJson` code for `result` because of type `TResult` (type parameter).
None of the provided `TypeHelper` instances support the defined type.
To support type paramaters (generic types) you can:
1) Use `JsonConverter`
https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonConverter-class.html
2) Use `JsonKey` fields `fromJson` and `toJson`
https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonKey/fromJson.html
https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonKey/toJson.html
3) Set `JsonSerializable.genericArgumentFactories` to `true`
https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonSerializable/genericArgumentFactories.html''',
element: 'result',
)
@JsonSerializable()
class Issue713<TResult> {
Expand Down

0 comments on commit 9f6c8b9

Please sign in to comment.