in packages/pigeon/lib/java_generator.dart [413:653]
void generateJava(JavaOptions options, Root root, StringSink sink) {
final Set<String> rootClassNameSet =
root.classes.map((Class x) => x.name).toSet();
final Set<String> rootEnumNameSet =
root.enums.map((Enum x) => x.name).toSet();
final Indent indent = Indent(sink);
void writeHeader() {
if (options.copyrightHeader != null) {
addLines(indent, options.copyrightHeader!, linePrefix: '// ');
}
indent.writeln('// $generatedCodeWarning');
indent.writeln('// $seeAlsoWarning');
}
void writeImports() {
indent.writeln('import android.util.Log;');
indent.writeln('import androidx.annotation.NonNull;');
indent.writeln('import androidx.annotation.Nullable;');
indent.writeln('import io.flutter.plugin.common.BasicMessageChannel;');
indent.writeln('import io.flutter.plugin.common.BinaryMessenger;');
indent.writeln('import io.flutter.plugin.common.MessageCodec;');
indent.writeln('import io.flutter.plugin.common.StandardMessageCodec;');
indent.writeln('import java.io.ByteArrayOutputStream;');
indent.writeln('import java.nio.ByteBuffer;');
indent.writeln('import java.util.Arrays;');
indent.writeln('import java.util.ArrayList;');
indent.writeln('import java.util.List;');
indent.writeln('import java.util.Map;');
indent.writeln('import java.util.HashMap;');
}
void writeEnum(Enum anEnum) {
indent.write('public enum ${anEnum.name} ');
indent.scoped('{', '}', () {
int index = 0;
for (final String member in anEnum.members) {
indent.writeln(
'$member($index)${index == anEnum.members.length - 1 ? ';' : ','}');
index++;
}
indent.writeln('');
// We use explicit indexing here as use of the ordinal() method is
// discouraged. The toMap and fromMap API matches class API to allow
// the same code to work with enums and classes, but this
// can also be done directly in the host and flutter APIs.
indent.writeln('private int index;');
indent.write('private ${anEnum.name}(final int index) ');
indent.scoped('{', '}', () {
indent.writeln('this.index = index;');
});
});
}
void writeDataClass(Class klass) {
void writeField(NamedType field) {
final HostDatatype hostDatatype = getHostDatatype(field, root.classes,
root.enums, (NamedType x) => _javaTypeForBuiltinDartType(x.type));
final String nullability =
field.type.isNullable ? '@Nullable' : '@NonNull';
indent.writeln(
'private $nullability ${hostDatatype.datatype} ${field.name};');
indent.writeln(
'public $nullability ${hostDatatype.datatype} ${_makeGetter(field)}() { return ${field.name}; }');
indent.writeScoped(
'public void ${_makeSetter(field)}($nullability ${hostDatatype.datatype} setterArg) {',
'}', () {
if (!field.type.isNullable) {
indent.writeScoped('if (setterArg == null) {', '}', () {
indent.writeln(
'throw new IllegalStateException("Nonnull field \\"${field.name}\\" is null.");');
});
}
indent.writeln('this.${field.name} = setterArg;');
});
}
void writeToMap() {
indent.write('@NonNull Map<String, Object> toMap() ');
indent.scoped('{', '}', () {
indent.writeln('Map<String, Object> toMapResult = new HashMap<>();');
for (final NamedType field in klass.fields) {
final HostDatatype hostDatatype = getHostDatatype(field, root.classes,
root.enums, (NamedType x) => _javaTypeForBuiltinDartType(x.type));
String toWriteValue = '';
final String fieldName = field.name;
if (!hostDatatype.isBuiltin &&
rootClassNameSet.contains(field.type.baseName)) {
toWriteValue = '($fieldName == null) ? null : $fieldName.toMap()';
} else if (!hostDatatype.isBuiltin &&
rootEnumNameSet.contains(field.type.baseName)) {
toWriteValue = '$fieldName == null ? null : $fieldName.index';
} else {
toWriteValue = field.name;
}
indent.writeln('toMapResult.put("${field.name}", $toWriteValue);');
}
indent.writeln('return toMapResult;');
});
}
void writeFromMap() {
indent.write(
'static @NonNull ${klass.name} fromMap(@NonNull Map<String, Object> map) ');
indent.scoped('{', '}', () {
const String result = 'pigeonResult';
indent.writeln('${klass.name} $result = new ${klass.name}();');
for (final NamedType field in klass.fields) {
final String fieldVariable = field.name;
final String setter = _makeSetter(field);
indent.writeln('Object $fieldVariable = map.get("${field.name}");');
if (rootEnumNameSet.contains(field.type.baseName)) {
indent.writeln(
'$result.$setter($fieldVariable == null ? null : ${field.type.baseName}.values()[(int)$fieldVariable]);');
} else {
indent.writeln(
'$result.$setter(${_castObject(field, root.classes, root.enums, fieldVariable)});');
}
}
indent.writeln('return $result;');
});
}
void writeBuilder() {
indent.write('public static class Builder ');
indent.scoped('{', '}', () {
for (final NamedType field in klass.fields) {
final HostDatatype hostDatatype = getHostDatatype(field, root.classes,
root.enums, (NamedType x) => _javaTypeForBuiltinDartType(x.type));
final String nullability =
field.type.isNullable ? '@Nullable' : '@NonNull';
indent.writeln(
'private @Nullable ${hostDatatype.datatype} ${field.name};');
indent.writeScoped(
'public @NonNull Builder ${_makeSetter(field)}($nullability ${hostDatatype.datatype} setterArg) {',
'}', () {
indent.writeln('this.${field.name} = setterArg;');
indent.writeln('return this;');
});
}
indent.write('public @NonNull ${klass.name} build() ');
indent.scoped('{', '}', () {
const String returnVal = 'pigeonReturn';
indent.writeln('${klass.name} $returnVal = new ${klass.name}();');
for (final NamedType field in klass.fields) {
indent.writeln('$returnVal.${_makeSetter(field)}(${field.name});');
}
indent.writeln('return $returnVal;');
});
});
}
indent.writeln(
'/** Generated class from Pigeon that represents data sent in messages. */');
indent.write('public static class ${klass.name} ');
indent.scoped('{', '}', () {
for (final NamedType field in klass.fields) {
writeField(field);
indent.addln('');
}
if (klass.fields
.map((NamedType e) => !e.type.isNullable)
.any((bool e) => e)) {
indent.writeln(
'/** Constructor is private to enforce null safety; use Builder. */');
indent.writeln('private ${klass.name}() {}');
}
writeBuilder();
writeToMap();
writeFromMap();
});
}
void writeResultInterface() {
indent.write('public interface Result<T> ');
indent.scoped('{', '}', () {
indent.writeln('void success(T result);');
indent.writeln('void error(Throwable error);');
});
}
void writeApi(Api api) {
if (api.location == ApiLocation.host) {
_writeHostApi(indent, api);
} else if (api.location == ApiLocation.flutter) {
_writeFlutterApi(indent, api);
}
}
void writeWrapError() {
indent.format('''
private static Map<String, Object> wrapError(Throwable exception) {
\tMap<String, Object> errorMap = new HashMap<>();
\terrorMap.put("${Keys.errorMessage}", exception.toString());
\terrorMap.put("${Keys.errorCode}", exception.getClass().getSimpleName());
\terrorMap.put("${Keys.errorDetails}", "Cause: " + exception.getCause() + ", Stacktrace: " + Log.getStackTraceString(exception));
\treturn errorMap;
}''');
}
writeHeader();
indent.addln('');
if (options.package != null) {
indent.writeln('package ${options.package};');
}
indent.addln('');
writeImports();
indent.addln('');
indent.writeln('/** Generated class from Pigeon. */');
indent.writeln(
'@SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression"})');
indent.write('public class ${options.className!} ');
indent.scoped('{', '}', () {
for (final Enum anEnum in root.enums) {
indent.writeln('');
writeEnum(anEnum);
}
for (final Class klass in root.classes) {
indent.addln('');
writeDataClass(klass);
}
if (root.apis.any((Api api) =>
api.location == ApiLocation.host &&
api.methods.any((Method it) => it.isAsynchronous))) {
indent.addln('');
writeResultInterface();
}
for (final Api api in root.apis) {
_writeCodec(indent, api, root);
indent.addln('');
writeApi(api);
}
writeWrapError();
});
}