writeFlutterApi method

  1. @override
void writeFlutterApi(
  1. JavaOptions generatorOptions,
  2. Root root,
  3. Indent indent,
  4. AstFlutterApi api, {
  5. required String dartPackageName,
})
override

Writes the code for a flutter Api, api. Example: public static final class Foo { public Foo(BinaryMessenger argBinaryMessenger) {...} public interface Result

Implementation

@override
void writeFlutterApi(
  JavaOptions generatorOptions,
  Root root,
  Indent indent,
  AstFlutterApi api, {
  required String dartPackageName,
}) {
  /// Returns an argument name that can be used in a context where it is possible to collide
  /// and append `.index` to enums.
  String getEnumSafeArgumentExpression(int count, NamedType argument) {
    if (argument.type.isEnum) {
      return argument.type.isNullable
          ? '${_getArgumentName(count, argument)}Arg == null ? null : ${_getArgumentName(count, argument)}Arg.index'
          : '${_getArgumentName(count, argument)}Arg.index';
    }
    return '${_getArgumentName(count, argument)}Arg';
  }

  if (getCodecClasses(api, root).isNotEmpty) {
    _writeCodec(indent, api, root);
  }
  const List<String> generatedMessages = <String>[
    ' Generated class from Pigeon that represents Flutter messages that can be called from Java.'
  ];
  addDocumentationComments(indent, api.documentationComments, _docCommentSpec,
      generatorComments: generatedMessages);

  indent.write('public static class ${api.name} ');
  indent.addScoped('{', '}', () {
    indent.writeln('private final @NonNull BinaryMessenger binaryMessenger;');
    indent.writeln('private final String messageChannelSuffix;');
    indent.newln();
    indent.write(
        'public ${api.name}(@NonNull BinaryMessenger argBinaryMessenger) ');
    indent.addScoped('{', '}', () {
      indent.writeln('this(argBinaryMessenger, "");');
    });
    indent.write(
        'public ${api.name}(@NonNull BinaryMessenger argBinaryMessenger, @NonNull String messageChannelSuffix) ');
    indent.addScoped('{', '}', () {
      indent.writeln('this.binaryMessenger = argBinaryMessenger;');
      indent.writeln(
          'this.messageChannelSuffix = messageChannelSuffix.isEmpty() ? "" : "." + messageChannelSuffix;');
    });
    indent.newln();
    indent.writeln('/** Public interface for sending reply. */ ');
    final String codecName = _getCodecName(api);
    indent.writeln('/** The codec used by ${api.name}. */');
    indent.write('static @NonNull MessageCodec<Object> getCodec() ');
    indent.addScoped('{', '}', () {
      indent.write('return ');
      if (getCodecClasses(api, root).isNotEmpty) {
        indent.addln('$codecName.INSTANCE;');
      } else {
        indent.addln('new $_standardMessageCodec();');
      }
    });

    for (final Method func in api.methods) {
      final String resultType = _getResultType(func.returnType);
      final String returnType = func.returnType.isVoid
          ? 'Void'
          : _javaTypeForDartType(func.returnType);
      String sendArgument;
      addDocumentationComments(
          indent, func.documentationComments, _docCommentSpec);
      if (func.parameters.isEmpty) {
        indent
            .write('public void ${func.name}(@NonNull $resultType result) ');
        sendArgument = 'null';
      } else {
        final Iterable<String> argTypes = func.parameters
            .map((NamedType e) => _nullsafeJavaTypeForDartType(e.type));
        final Iterable<String> argNames =
            indexMap(func.parameters, _getSafeArgumentName);
        final Iterable<String> enumSafeArgNames =
            indexMap(func.parameters, getEnumSafeArgumentExpression);
        if (func.parameters.length == 1) {
          sendArgument =
              'new ArrayList<Object>(Collections.singletonList(${enumSafeArgNames.first}))';
        } else {
          sendArgument =
              'new ArrayList<Object>(Arrays.asList(${enumSafeArgNames.join(', ')}))';
        }
        final String argsSignature =
            map2(argTypes, argNames, (String x, String y) => '$x $y')
                .join(', ');
        indent.write(
            'public void ${func.name}($argsSignature, @NonNull $resultType result) ');
      }
      indent.addScoped('{', '}', () {
        const String channel = 'channel';
        indent.writeln(
            'final String channelName = "${makeChannelName(api, func, dartPackageName)}" + messageChannelSuffix;');
        indent.writeln('BasicMessageChannel<Object> $channel =');
        indent.nest(2, () {
          indent.writeln('new BasicMessageChannel<>(');
          indent.nest(2, () {
            indent.writeln('binaryMessenger, channelName, getCodec());');
          });
        });
        indent.writeln('$channel.send(');
        indent.nest(2, () {
          indent.writeln('$sendArgument,');
          indent.write('channelReply -> ');
          indent.addScoped('{', '});', () {
            indent.writeScoped('if (channelReply instanceof List) {', '} ',
                () {
              indent.writeln(
                  'List<Object> listReply = (List<Object>) channelReply;');
              indent.writeScoped('if (listReply.size() > 1) {', '} ', () {
                indent.writeln(
                    'result.error(new FlutterError((String) listReply.get(0), (String) listReply.get(1), (String) listReply.get(2)));');
              }, addTrailingNewline: false);
              if (!func.returnType.isNullable && !func.returnType.isVoid) {
                indent.addScoped('else if (listReply.get(0) == null) {', '} ',
                    () {
                  indent.writeln(
                      'result.error(new FlutterError("null-error", "Flutter api returned null value for non-null return value.", ""));');
                }, addTrailingNewline: false);
              }
              indent.addScoped('else {', '}', () {
                if (func.returnType.isVoid) {
                  indent.writeln('result.success();');
                } else {
                  const String output = 'output';
                  final String outputExpression;
                  indent.writeln('@SuppressWarnings("ConstantConditions")');
                  if (func.returnType.baseName == 'int') {
                    outputExpression =
                        'listReply.get(0) == null ? null : ((Number) listReply.get(0)).longValue();';
                  } else if (func.returnType.isEnum) {
                    if (func.returnType.isNullable) {
                      outputExpression =
                          'listReply.get(0) == null ? null : $returnType.values()[(int) listReply.get(0)];';
                    } else {
                      outputExpression =
                          '$returnType.values()[(int) listReply.get(0)];';
                    }
                  } else {
                    outputExpression =
                        '${_cast('listReply.get(0)', javaType: returnType)};';
                  }
                  indent.writeln('$returnType $output = $outputExpression');
                  indent.writeln('result.success($output);');
                }
              });
            }, addTrailingNewline: false);
            indent.addScoped(' else {', '} ', () {
              indent.writeln(
                  'result.error(createConnectionError(channelName));');
            });
          });
        });
      });
    }
  });
}