Skip to content
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
5a74262
standardize kotlin/java host api error wrapping
xegrox Feb 21, 2023
a2d74b1
changelog
xegrox Feb 21, 2023
97c02cb
tests
xegrox Feb 21, 2023
4ff920e
format
xegrox Feb 21, 2023
1575209
format
xegrox Feb 21, 2023
7a4d396
update test
xegrox Feb 22, 2023
e79fa0d
standardize for swift too
xegrox Feb 22, 2023
b4aca30
Merge branch 'main' into main
xegrox Feb 22, 2023
cdace1c
format
xegrox Feb 22, 2023
dc9c3e0
changelog
xegrox Feb 22, 2023
4294185
standardize for cpp
xegrox Feb 22, 2023
b28fec5
error class for kotlin + tests
xegrox Feb 24, 2023
59bde90
error class for java + tests
xegrox Feb 24, 2023
cf93865
update tests for other platforms
xegrox Feb 24, 2023
6371f12
fix missing try catch java
xegrox Feb 24, 2023
c9a30bb
Merge branch 'main' of https://github.com/flutter/packages
xegrox Feb 24, 2023
8ca9ee5
update version and changelog
xegrox Feb 24, 2023
50acb7a
format
xegrox Feb 24, 2023
84ea8a1
apply review changes
xegrox Feb 25, 2023
73f26df
one error class per file for kotlin
xegrox Feb 25, 2023
cf3d222
update changelog
xegrox Feb 25, 2023
8feaa2c
update changelog
xegrox Feb 25, 2023
7ee1845
Merge branch 'main' into main
xegrox Feb 25, 2023
5d1b57d
rename default error class to `FlutterError`
xegrox Feb 27, 2023
c898a63
format
xegrox Feb 27, 2023
eb154ac
update tests
xegrox Feb 27, 2023
43bfaaf
format
xegrox Feb 27, 2023
d9858ee
review changes
xegrox Mar 12, 2023
1d59674
Merge branch 'main' of https://github.com/flutter/packages
xegrox Mar 12, 2023
742dba0
fix warnings
xegrox Mar 12, 2023
52fe56b
update changelog
xegrox Mar 12, 2023
d50751d
fix cpp
xegrox Mar 12, 2023
7c57e7e
fix cpp
xegrox Mar 12, 2023
ee5d84a
review changes
xegrox Mar 15, 2023
698a29d
Merge branch 'main' into main
xegrox Mar 15, 2023
23e6659
Fix "Objective-C"
stuartmorgan-g Mar 15, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion packages/pigeon/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
## 9.0.2

* [java] Adds a `GeneratedApi.FlutterError` exception for passing custom error parameters (code, message, details).
* [kotlin] Adds a `FlutterError` exception for passing custom error parameters (code, message, details).
* [kotlin] Adds a `errorClassName` option in `KotlinOptions` for custom error class names.
* [java] Removes legacy try catch in async apis.
* Adds `FlutterError` handling integration tests for all platforms.

## 9.0.1

* Updates links for the merge of flutter/plugins into flutter/packages.

## 9.0.0

* **Breaking Change** Updates `DartOptions` to be immutable and adds const to the constructor.
* **Breaking Change** Updates `DartOptions` to be immutable and
adds const to the constructor.
* [java] Reverts `final` changes to Flutter Api classes.

## 8.0.0
Expand Down
2 changes: 1 addition & 1 deletion packages/pigeon/lib/generator_tools.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import 'ast.dart';
/// The current version of pigeon.
///
/// This must match the version in pubspec.yaml.
const String pigeonVersion = '9.0.1';
const String pigeonVersion = '9.0.2';

/// Read all the content from [stdin] to a String.
String readStdin() {
Expand Down
168 changes: 100 additions & 68 deletions packages/pigeon/lib/java_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -606,46 +606,50 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
: _javaTypeForDartType(method.returnType);
indent.writeln(
'ArrayList<Object> wrapped = new ArrayList<Object>();');
indent.write('try ');
indent.addScoped('{', '}', () {
final List<String> methodArgument = <String>[];
if (method.arguments.isNotEmpty) {
final List<String> methodArgument = <String>[];
if (method.arguments.isNotEmpty) {
indent.writeln(
'ArrayList<Object> args = (ArrayList<Object>) message;');
indent.write('if (args == null) ');
indent.addScoped('{', '}', () {
indent.writeln(
'ArrayList<Object> args = (ArrayList<Object>) message;');
indent.writeln('assert args != null;');
enumerate(method.arguments, (int index, NamedType arg) {
// The StandardMessageCodec can give us [Integer, Long] for
// a Dart 'int'. To keep things simple we just use 64bit
// longs in Pigeon with Java.
final bool isInt = arg.type.baseName == 'int';
final String argType =
isInt ? 'Number' : _javaTypeForDartType(arg.type);
final String argName = _getSafeArgumentName(index, arg);
final String argExpression = isInt
? '($argName == null) ? null : $argName.longValue()'
: argName;
String accessor = 'args.get($index)';
if (isEnum(root, arg.type)) {
accessor = _intToEnum(accessor, arg.type.baseName);
} else if (argType != 'Object') {
accessor = '($argType) $accessor';
}
indent.writeln('$argType $argName = $accessor;');
if (!arg.type.isNullable) {
indent.write('if ($argName == null) ');
indent.addScoped('{', '}', () {
indent.writeln(
'throw new NullPointerException("$argName unexpectedly null.");');
});
}
methodArgument.add(argExpression);
});
}
if (method.isAsynchronous) {
final String resultValue =
method.returnType.isVoid ? 'null' : 'result';
const String resultName = 'resultCallback';
indent.format('''
'reply.reply(wrapError(new IllegalArgumentException("Arguments expected but none received.")));');
indent.writeln('return;');
});
enumerate(method.arguments, (int index, NamedType arg) {
// The StandardMessageCodec can give us [Integer, Long] for
// a Dart 'int'. To keep things simple we just use 64bit
// longs in Pigeon with Java.
final bool isInt = arg.type.baseName == 'int';
final String argType =
isInt ? 'Number' : _javaTypeForDartType(arg.type);
final String argName = _getSafeArgumentName(index, arg);
final String argExpression = isInt
? '($argName == null) ? null : $argName.longValue()'
: argName;
String accessor = 'args.get($index)';
if (isEnum(root, arg.type)) {
accessor = _intToEnum(accessor, arg.type.baseName);
} else if (argType != 'Object') {
accessor = '($argType) $accessor';
}
indent.writeln('$argType $argName = $accessor;');
if (!arg.type.isNullable) {
indent.write('if ($argName == null) ');
indent.addScoped('{', '}', () {
indent.writeln(
'reply.reply(wrapError(new NullPointerException("aStringArg unexpectedly null.")));');
indent.writeln('return;');
});
}
methodArgument.add(argExpression);
});
}
if (method.isAsynchronous) {
final String resultValue =
method.returnType.isVoid ? 'null' : 'result';
const String resultName = 'resultCallback';
indent.format('''
Result<$returnType> $resultName =
\t\tnew Result<$returnType>() {
\t\t\tpublic void success($returnType result) {
Expand All @@ -659,31 +663,33 @@ Result<$returnType> $resultName =
\t\t\t}
\t\t};
''');
methodArgument.add(resultName);
}
final String call =
'api.${method.name}(${methodArgument.join(', ')})';
if (method.isAsynchronous) {
indent.writeln('$call;');
} else if (method.returnType.isVoid) {
indent.writeln('$call;');
indent.writeln('wrapped.add(0, null);');
} else {
indent.writeln('$returnType output = $call;');
indent.writeln('wrapped.add(0, output);');
}
}, addTrailingNewline: false);
indent.add(' catch (Error | RuntimeException exception) ');
indent.addScoped('{', '}', () {
indent.writeln(
'ArrayList<Object> wrappedError = wrapError(exception);');
if (method.isAsynchronous) {
indent.writeln('reply.reply(wrappedError);');
} else {
indent.writeln('wrapped = wrappedError;');
}
});
if (!method.isAsynchronous) {
methodArgument.add(resultName);
}
final String call =
'api.${method.name}(${methodArgument.join(', ')})';
if (method.isAsynchronous) {
indent.writeln('$call;');
} else {
indent.write('try ');
indent.addScoped('{', '}', () {
if (method.returnType.isVoid) {
indent.writeln('$call;');
indent.writeln('wrapped.add(0, null);');
} else {
indent.writeln('$returnType output = $call;');
indent.writeln('wrapped.add(0, output);');
}
});
indent.add(' catch (Throwable exception) ');
indent.addScoped('{', '}', () {
indent.writeln(
'ArrayList<Object> wrappedError = wrapError(exception);');
if (method.isAsynchronous) {
indent.writeln('reply.reply(wrappedError);');
} else {
indent.writeln('wrapped = wrappedError;');
}
});
indent.writeln('reply.reply(wrapped);');
}
});
Expand Down Expand Up @@ -765,22 +771,48 @@ Result<$returnType> $resultName =
});
}

void _writeErrorClass(Indent indent) {
indent.write('public static class FlutterError extends RuntimeException ');
indent.addScoped('{', '}', () {
indent.writeln('public final String code;');
indent.writeln('public final String message;');
indent.writeln('public final Object details;');
indent.newln();
indent.writeln(
'public FlutterError(@NonNull String code, @Nullable String message, @Nullable Object details) ');
indent.writeScoped('{', '}', () {
indent.writeln('super(message);');
indent.writeln('this.code = code;');
indent.writeln('this.message = message;');
indent.writeln('this.details = details;');
});
});
}

void _writeWrapError(Indent indent) {
indent.format('''
@NonNull
private static ArrayList<Object> wrapError(@NonNull Throwable exception) {
\tArrayList<Object> errorList = new ArrayList<Object>(3);
\terrorList.add(exception.toString());
\terrorList.add(exception.getClass().getSimpleName());
\terrorList.add(
\t\t"Cause: " + exception.getCause() + ", Stacktrace: " + Log.getStackTraceString(exception));
\tif (exception instanceof FlutterError) {
\t\tFlutterError error = (FlutterError) exception;
\t\terrorList.add(error.code);
\t\terrorList.add(error.message);
\t\terrorList.add(error.details);
\t} else {
\t\terrorList.add(exception.toString());
\t\terrorList.add(exception.getClass().getSimpleName());
\t\terrorList.add(
\t\t\t"Cause: " + exception.getCause() + ", Stacktrace: " + Log.getStackTraceString(exception));
\t}
\treturn errorList;
}''');
}

@override
void writeGeneralUtilities(
JavaOptions generatorOptions, Root root, Indent indent) {
_writeErrorClass(indent);
_writeWrapError(indent);
}

Expand Down
56 changes: 42 additions & 14 deletions packages/pigeon/lib/kotlin_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,25 @@ const DocumentCommentSpecification _docCommentSpec =
/// Options that control how Kotlin code will be generated.
class KotlinOptions {
/// Creates a [KotlinOptions] object
const KotlinOptions({
this.package,
this.copyrightHeader,
});
const KotlinOptions(
{this.package, this.copyrightHeader, this.errorClassName});

/// The package where the generated class will live.
final String? package;

/// A copyright header that will get prepended to generated code.
final Iterable<String>? copyrightHeader;

/// The name of the error class used for passing custom error parameters.
final String? errorClassName;

/// Creates a [KotlinOptions] from a Map representation where:
/// `x = KotlinOptions.fromMap(x.toMap())`.
static KotlinOptions fromMap(Map<String, Object> map) {
return KotlinOptions(
package: map['package'] as String?,
copyrightHeader: map['copyrightHeader'] as Iterable<String>?,
errorClassName: map['errorClassName'] as String?,
);
}

Expand All @@ -54,6 +56,7 @@ class KotlinOptions {
final Map<String, Object> result = <String, Object>{
if (package != null) 'package': package!,
if (copyrightHeader != null) 'copyrightHeader': copyrightHeader!,
if (errorClassName != null) 'errorClassName': errorClassName!,
};
return result;
}
Expand Down Expand Up @@ -404,6 +407,7 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
/// fun setUp(binaryMessenger: BinaryMessenger, api: Api) {...}
/// }
/// }
///
@override
void writeHostApi(
KotlinOptions generatorOptions,
Expand Down Expand Up @@ -552,7 +556,7 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
indent.writeln('wrapped = listOf<Any?>($call)');
}
}, addTrailingNewline: false);
indent.add(' catch (exception: Error) ');
indent.add(' catch (exception: Throwable) ');
indent.addScoped('{', '}', () {
indent.writeln('wrapped = wrapError(exception)');
});
Expand Down Expand Up @@ -625,25 +629,49 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
});
}

void _writeWrapError(Indent indent) {
void _writeWrapError(KotlinOptions generatorOptions, Indent indent) {
indent.newln();
indent.write('private fun wrapError(exception: Throwable): List<Any> ');
indent.write('private fun wrapError(exception: Throwable): List<Any?> ');
indent.addScoped('{', '}', () {
indent.write('return ');
indent.addScoped('listOf<Any>(', ')', () {
indent.writeln('exception.javaClass.simpleName,');
indent.writeln('exception.toString(),');
indent.writeln(
'"Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception)');
indent.write(
'if (exception is ${generatorOptions.errorClassName ?? "FlutterError"}) ');
indent.addScoped('{', '}', () {
indent.write('return ');
indent.addScoped('listOf(', ')', () {
indent.writeln('exception.code,');
indent.writeln('exception.message,');
indent.writeln('exception.details');
});
}, addTrailingNewline: false);
indent.addScoped(' else {', '}', () {
indent.write('return ');
indent.addScoped('listOf(', ')', () {
indent.writeln('exception.javaClass.simpleName,');
indent.writeln('exception.toString(),');
indent.writeln(
'"Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception)');
});
});
});
}

void _writeErrorClass(KotlinOptions generatorOptions, Indent indent) {
indent.newln();
indent.write('class ${generatorOptions.errorClassName ?? "FlutterError"} ');
indent.addScoped('(', ')', () {
indent.writeln('val code: String,');
indent.writeln('override val message: String? = null,');
indent.writeln('val details: Any? = null');
}, addTrailingNewline: false);
indent.addln(' : Throwable()');
}

@override
void writeGeneralUtilities(
KotlinOptions generatorOptions, Root root, Indent indent) {
_writeWrapResult(indent);
_writeWrapError(indent);
_writeWrapError(generatorOptions, indent);
_writeErrorClass(generatorOptions, indent);
}
}

Expand Down
1 change: 1 addition & 0 deletions packages/pigeon/lib/pigeon_lib.dart
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,7 @@ class KotlinGeneratorAdapter implements GeneratorAdapter {
KotlinOptions kotlinOptions =
options.kotlinOptions ?? const KotlinOptions();
kotlinOptions = kotlinOptions.merge(KotlinOptions(
errorClassName: kotlinOptions.errorClassName ?? 'FlutterError',
copyrightHeader: options.copyrightHeader != null
? _lineReader(options.copyrightHeader!)
: null));
Expand Down
2 changes: 1 addition & 1 deletion packages/pigeon/mock_handler_tester/test/message.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v9.0.1), do not edit directly.
// Autogenerated from Pigeon (v9.0.2), do not edit directly.
// See also: https://pub.dev/packages/pigeon
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import

Expand Down
2 changes: 1 addition & 1 deletion packages/pigeon/mock_handler_tester/test/test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v9.0.1), do not edit directly.
// Autogenerated from Pigeon (v9.0.2), do not edit directly.
// See also: https://pub.dev/packages/pigeon
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import
// ignore_for_file: avoid_relative_lib_imports
Expand Down
Loading