forked from flutter/packages
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Pigeon] Added java target for host functions. (flutter#96)
* [Pigeon] Added java target for host functions.
- Loading branch information
Showing
8 changed files
with
272 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
// Copyright 2020 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
import 'ast.dart'; | ||
import 'generator_tools.dart'; | ||
|
||
/// Options that control how Java code will be generated. | ||
class JavaOptions { | ||
/// The name of the class that will house all the generated classes. | ||
String className; | ||
|
||
/// The package where the generated class will live. | ||
String package; | ||
} | ||
|
||
void _writeHostApi(Indent indent, Api api) { | ||
assert(api.location == ApiLocation.host); | ||
indent.writeln( | ||
'/** Generated interface from Pigeon that represents a handler of messages from Flutter.*/'); | ||
indent.write('public interface ${api.name} '); | ||
indent.scoped('{', '}', () { | ||
for (Method method in api.methods) { | ||
indent.writeln( | ||
'${method.returnType} ${method.name}(${method.argType} arg);'); | ||
} | ||
indent.addln(''); | ||
indent.writeln( | ||
'/** Sets up an instance of `${api.name}` to handle messages through the `binaryMessenger` */'); | ||
indent.write( | ||
'public static void setup(BinaryMessenger binaryMessenger, ${api.name} api) '); | ||
indent.scoped('{', '}', () { | ||
for (Method method in api.methods) { | ||
final String channelName = makeChannelName(api, method); | ||
indent.write(''); | ||
indent.scoped('{', '}', () { | ||
indent.writeln('BasicMessageChannel<Object> channel ='); | ||
indent.inc(); | ||
indent.inc(); | ||
indent.writeln( | ||
'new BasicMessageChannel<Object>(binaryMessenger, "$channelName", new StandardMessageCodec());'); | ||
indent.dec(); | ||
indent.dec(); | ||
indent.write( | ||
'channel.setMessageHandler(new BasicMessageChannel.MessageHandler<Object>() '); | ||
indent.scoped('{', '});', () { | ||
indent.write( | ||
'public void onMessage(Object message, BasicMessageChannel.Reply<Object> reply) '); | ||
indent.scoped('{', '}', () { | ||
final String argType = method.argType; | ||
final String returnType = method.returnType; | ||
indent.writeln( | ||
'$argType input = $argType.fromMap((HashMap)message);'); | ||
indent.writeln('$returnType output = api.${method.name}(input);'); | ||
indent.writeln('reply.reply(output.toMap());'); | ||
}); | ||
}); | ||
}); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
// void _writeFlutterApi(Indent indent, Api api) { | ||
// assert(api.location == ApiLocation.flutter); | ||
// } | ||
|
||
String _makeGetter(Field field) { | ||
final String uppercased = | ||
field.name.substring(0, 1).toUpperCase() + field.name.substring(1); | ||
return 'get$uppercased'; | ||
} | ||
|
||
String _makeSetter(Field field) { | ||
final String uppercased = | ||
field.name.substring(0, 1).toUpperCase() + field.name.substring(1); | ||
return 'set$uppercased'; | ||
} | ||
|
||
/// Generates the ".java" file for the AST represented by [root] to [sink] with the | ||
/// provided [options]. | ||
void generateJava(JavaOptions options, Root root, StringSink sink) { | ||
final Indent indent = Indent(sink); | ||
indent.writeln('// Autogenerated from Pigeon, do not edit directly.'); | ||
indent.writeln('// See also: https://pub.dev/packages/pigeon'); | ||
indent.addln(''); | ||
if (options.package != null) { | ||
indent.writeln('package ${options.package};'); | ||
} | ||
indent.addln(''); | ||
|
||
indent.writeln('import java.util.HashMap;'); | ||
indent.addln(''); | ||
indent.writeln('import io.flutter.plugin.common.BasicMessageChannel;'); | ||
indent.writeln('import io.flutter.plugin.common.BinaryMessenger;'); | ||
indent.writeln('import io.flutter.plugin.common.StandardMessageCodec;'); | ||
|
||
indent.addln(''); | ||
assert(options.className != null); | ||
indent.writeln('/** Generated class from Pigeon. */'); | ||
indent.write('public class ${options.className} '); | ||
indent.scoped('{', '}', () { | ||
for (Class klass in root.classes) { | ||
indent.addln(''); | ||
indent.writeln( | ||
'/** Generated class from Pigeon that represents data sent in messages. */'); | ||
indent.write('public static class ${klass.name} '); | ||
indent.scoped('{', '}', () { | ||
for (Field field in klass.fields) { | ||
indent.writeln('private ${field.dataType} ${field.name};'); | ||
indent.writeln( | ||
'public ${field.dataType} ${_makeGetter(field)}() { return ${field.name}; }'); | ||
indent.writeln( | ||
'public void ${_makeSetter(field)}(${field.dataType} setterArg) { this.${field.name} = setterArg; }'); | ||
indent.addln(''); | ||
} | ||
indent.write('HashMap toMap() '); | ||
indent.scoped('{', '}', () { | ||
indent.writeln( | ||
'HashMap<String, Object> toMapResult = new HashMap<String, Object>();'); | ||
for (Field field in klass.fields) { | ||
indent.writeln('toMapResult.put("${field.name}", ${field.name});'); | ||
} | ||
indent.writeln('return toMapResult;'); | ||
}); | ||
indent.write('static ${klass.name} fromMap(HashMap map) '); | ||
indent.scoped('{', '}', () { | ||
indent.writeln('${klass.name} fromMapResult = new ${klass.name}();'); | ||
for (Field field in klass.fields) { | ||
indent.writeln( | ||
'fromMapResult.${field.name} = (${field.dataType})map.get("${field.name}");'); | ||
} | ||
indent.writeln('return fromMapResult;'); | ||
}); | ||
}); | ||
} | ||
|
||
for (Api api in root.apis) { | ||
indent.addln(''); | ||
if (api.location == ApiLocation.host) { | ||
_writeHostApi(indent, api); | ||
} else if (api.location == ApiLocation.flutter) { | ||
// _writeFlutterApi(indent, api); | ||
} | ||
} | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// Copyright 2020 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
import 'package:test/test.dart'; | ||
import 'package:pigeon/java_generator.dart'; | ||
import 'package:pigeon/ast.dart'; | ||
|
||
void main() { | ||
test('gen one class', () { | ||
final Class klass = Class() | ||
..name = 'Foobar' | ||
..fields = <Field>[ | ||
Field() | ||
..name = 'field1' | ||
..dataType = 'int' | ||
]; | ||
final Root root = Root() | ||
..apis = <Api>[] | ||
..classes = <Class>[klass]; | ||
final StringBuffer sink = StringBuffer(); | ||
final JavaOptions javaOptions = JavaOptions(); | ||
javaOptions.className = 'Messages'; | ||
generateJava(javaOptions, root, sink); | ||
final String code = sink.toString(); | ||
expect(code, contains('public class Messages')); | ||
expect(code, contains('public static class Foobar')); | ||
expect(code, contains('private int field1;')); | ||
}); | ||
|
||
test('package', () { | ||
final Class klass = Class() | ||
..name = 'Foobar' | ||
..fields = <Field>[ | ||
Field() | ||
..name = 'field1' | ||
..dataType = 'int' | ||
]; | ||
final Root root = Root() | ||
..apis = <Api>[] | ||
..classes = <Class>[klass]; | ||
final StringBuffer sink = StringBuffer(); | ||
final JavaOptions javaOptions = JavaOptions(); | ||
javaOptions.className = 'Messages'; | ||
javaOptions.package = 'com.google.foobar'; | ||
generateJava(javaOptions, root, sink); | ||
final String code = sink.toString(); | ||
expect(code, contains('package com.google.foobar;')); | ||
expect(code, contains('HashMap toMap()')); | ||
}); | ||
|
||
test('gen one host api', () { | ||
final Root root = Root(apis: <Api>[ | ||
Api(name: 'Api', location: ApiLocation.host, methods: <Method>[ | ||
Method(name: 'doSomething', argType: 'Input', returnType: 'Output') | ||
]) | ||
], classes: <Class>[ | ||
Class( | ||
name: 'Input', | ||
fields: <Field>[Field(name: 'input', dataType: 'String')]), | ||
Class( | ||
name: 'Output', | ||
fields: <Field>[Field(name: 'output', dataType: 'String')]) | ||
]); | ||
final StringBuffer sink = StringBuffer(); | ||
final JavaOptions javaOptions = JavaOptions(); | ||
javaOptions.className = 'Messages'; | ||
generateJava(javaOptions, root, sink); | ||
final String code = sink.toString(); | ||
expect(code, contains('public interface Api')); | ||
expect(code, matches('Output.*doSomething.*Input')); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters