GrpcGetDocLines(const string& comments) {
+ if (!comments.empty()) {
+ // TODO(kenton): Ideally we should parse the comment text as Markdown and
+ // write it back as HTML, but this requires a Markdown parser. For now
+ // we just use to get fixed-width text formatting.
+
+ // If the comment itself contains block comment start or end markers,
+ // HTML-escape them so that they don't accidentally close the doc comment.
+ string escapedComments = GrpcEscapeJavadoc(comments);
+
+ std::vector lines = GrpcSplit(escapedComments, "\n");
+ while (!lines.empty() && lines.back().empty()) {
+ lines.pop_back();
+ }
+ return lines;
+ }
+ return std::vector();
+}
+
+// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
+template
+static std::vector GrpcGetDocLinesForDescriptor(const DescriptorType* descriptor) {
+ return GrpcGetDocLines(GrpcGetCommentsForDescriptor(descriptor));
+}
+
+// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
+static void GrpcWriteDocCommentBody(Printer* printer,
+ const std::vector& lines,
+ bool surroundWithPreTag) {
+ if (!lines.empty()) {
+ if (surroundWithPreTag) {
+ printer->Print(" * \n");
+ }
+
+ for (size_t i = 0; i < lines.size(); i++) {
+ // Most lines should start with a space. Watch out for lines that start
+ // with a /, since putting that right after the leading asterisk will
+ // close the comment.
+ if (!lines[i].empty() && lines[i][0] == '/') {
+ printer->Print(" * $line$\n", "line", lines[i]);
+ } else {
+ printer->Print(" *$line$\n", "line", lines[i]);
+ }
+ }
+
+ if (surroundWithPreTag) {
+ printer->Print(" * \n");
+ }
+ }
+}
+
+// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
+static void GrpcWriteDocComment(Printer* printer, const string& comments) {
+ printer->Print("/**\n");
+ std::vector lines = GrpcGetDocLines(comments);
+ GrpcWriteDocCommentBody(printer, lines, false);
+ printer->Print(" */\n");
+}
+
+// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
+static void GrpcWriteServiceDocComment(Printer* printer,
+ const ServiceDescriptor* service) {
+ // Deviating from protobuf to avoid extraneous docs
+ // (see https://github.com/google/protobuf/issues/1406);
+ printer->Print("/**\n");
+ std::vector lines = GrpcGetDocLinesForDescriptor(service);
+ GrpcWriteDocCommentBody(printer, lines, true);
+ printer->Print(" */\n");
+}
+
+// TODO(nmittler): Remove once protobuf includes javadoc methods in distribution.
+void GrpcWriteMethodDocComment(Printer* printer,
+ const MethodDescriptor* method) {
+ // Deviating from protobuf to avoid extraneous docs
+ // (see https://github.com/google/protobuf/issues/1406);
+ printer->Print("/**\n");
+ std::vector lines = GrpcGetDocLinesForDescriptor(method);
+ GrpcWriteDocCommentBody(printer, lines, true);
+ printer->Print(" */\n");
+}
+
+enum StubType {
+ ASYNC_INTERFACE = 0,
+ BLOCKING_CLIENT_INTERFACE = 1,
+ FUTURE_CLIENT_INTERFACE = 2,
+ BLOCKING_SERVER_INTERFACE = 3,
+ ASYNC_CLIENT_IMPL = 4,
+ BLOCKING_CLIENT_IMPL = 5,
+ FUTURE_CLIENT_IMPL = 6,
+ ABSTRACT_CLASS = 7,
+};
+
+enum CallType {
+ ASYNC_CALL = 0,
+ BLOCKING_CALL = 1,
+ FUTURE_CALL = 2
+};
+
+static void PrintMarshallerStaticBlock(const ServiceDescriptor* service,
+ std::map* vars,
+ Printer* p) {
+ for (int i = 0; i < service->method_count(); ++i) {
+ const MethodDescriptor* method = service->method(i);
+ (*vars)["input_type"] = google::protobuf::compiler::java::ClassName(method->input_type());
+ (*vars)["output_type"] = google::protobuf::compiler::java::ClassName(method->output_type());
+ p->Print(
+ *vars,
+ "private static final AtomicBoolean registered = new AtomicBoolean();\n\n");
+
+ p->Print(
+ *vars,
+ "private static Class> init() {\n"
+ " Class> clazz = null;\n"
+ " try {\n"
+ " clazz = Class.forName(DemoServiceDubbo.class.getName());\n"
+ " if (registered.compareAndSet(false, true)) {\n"
+ " $ProtobufUtils$.marshaller(\n"
+ " $input_type$.getDefaultInstance());\n"
+ " $ProtobufUtils$.marshaller(\n"
+ " $output_type$.getDefaultInstance());\n"
+ " }\n"
+ " } catch (ClassNotFoundException e) {\n"
+ " // ignore \n"
+ " }\n"
+ " return clazz;\n"
+ "}\n\n");
+ }
+}
+
+static void PrintDubboInterface(
+ const ServiceDescriptor* service,
+ std::map* vars,
+ Printer* p, bool generate_nano) {
+ const string service_name = service->name();
+ (*vars)["service_name"] = service_name;
+ (*vars)["dubbo_interface"] = "I" + service_name;
+
+ p->Print(
+ "/**\n "
+ "* Code generated for Dubbo\n "
+ "*/\n"
+ );
+ p->Print(
+ *vars,
+ "public interface $dubbo_interface$ {\n\n"
+ " static Class> clazz = init();\n\n");
+
+ for (int i = 0; i < service->method_count(); ++i) {
+ const MethodDescriptor* method = service->method(i);
+ (*vars)["input_type"] = MessageFullJavaName(generate_nano,
+ method->input_type());
+ (*vars)["output_type"] = MessageFullJavaName(generate_nano,
+ method->output_type());
+ (*vars)["lower_method_name"] = LowerMethodName(method);
+
+ // Simple RPC
+ p->Print(
+ *vars,
+ " $output_type$ $lower_method_name$($input_type$ request);\n\n");
+ // Simple Future RPC
+ p->Print(
+ *vars,
+ " $CompletableFuture$<$output_type$> $lower_method_name$Async(\n $input_type$ request);\n\n");
+// p->Print(
+// *vars,
+// "default $CompletableFuture$<$output_type$> $lower_method_name$Async(\n"
+// " $input_type$ request) {\n return CompletableFuture.completedFuture($lower_method_name$(request));\n}\n\n");
+ p->Outdent();
+ }
+
+ p->Outdent();
+ p->Print(" }\n\n");
+
+}
+
+static void PrintService(const ServiceDescriptor* service,
+ std::map* vars,
+ Printer* p,
+ bool disable_version) {
+ (*vars)["service_name"] = service->name();
+ (*vars)["file_name"] = service->file()->name();
+ (*vars)["service_class_name"] = ServiceClassName(service);
+ (*vars)["grpc_version"] = "";
+ #ifdef GRPC_VERSION
+ if (!disable_version) {
+ (*vars)["grpc_version"] = " (version " XSTR(GRPC_VERSION) ")";
+ }
+ #endif
+ // TODO(nmittler): Replace with WriteServiceDocComment once included by protobuf distro.
+ GrpcWriteServiceDocComment(p, service);
+ p->Print(
+ *vars,
+ "@$Generated$(\n"
+ " value = \"by gRPC proto compiler$grpc_version$\",\n"
+ " comments = \"Source: $file_name$\")\n");
+
+ if (service->options().deprecated()) {
+ p->Print(*vars, "@$Deprecated$\n");
+ }
+
+ p->Print(
+ *vars,
+ "public final class $service_class_name$ {\n\n");
+ p->Indent();
+
+ PrintMarshallerStaticBlock(service, vars, p);
+
+ p->Print(
+ *vars,
+ "private $service_class_name$() {}\n\n");
+
+ p->Print(
+ *vars,
+ "public static final String SERVICE_NAME = "
+ "\"$Package$$service_name$\";\n\n");
+
+ PrintDubboInterface(service, vars, p, false);
+
+ p->Outdent();
+ p->Print("}\n");
+}
+
+void PrintImports(Printer* p) {
+ p->Print(
+ "import "
+ "java.util.concurrent.CompletableFuture;\n");
+ p->Print(
+ "import "
+ "java.util.concurrent.atomic.AtomicBoolean;\n");
+}
+
+void GenerateService(const ServiceDescriptor* service,
+ google::protobuf::io::ZeroCopyOutputStream* out,
+ ProtoFlavor flavor,
+ bool disable_version) {
+ // All non-generated classes must be referred by fully qualified names to
+ // avoid collision with generated classes.
+ std::map vars;
+ vars["String"] = "java.lang.String";
+ vars["Deprecated"] = "java.lang.Deprecated";
+ vars["Override"] = "java.lang.Override";
+ vars["Iterator"] = "java.util.Iterator";
+ vars["Generated"] = "javax.annotation.Generated";
+ vars["CompletableFuture"] =
+ "java.util.concurrent.CompletableFuture";
+ vars["AtomicBoolean"] =
+ "java.util.concurrent.atomic.AtomicBoolean";
+ vars["ProtobufUtils"] =
+ "org.apache.dubbo.common.serialize.protobuf.support.ProtobufUtils";
+
+ Printer printer(out, '$');
+ string package_name = ServiceJavaPackage(service->file(),false);
+ if (!package_name.empty()) {
+ printer.Print(
+ "package $package_name$;\n\n",
+ "package_name", package_name);
+ }
+
+ PrintImports(&printer);
+
+ // Package string is used to fully qualify method names.
+ vars["Package"] = service->file()->package();
+ if (!vars["Package"].empty()) {
+ vars["Package"].append(".");
+ }
+ PrintService(service, &vars, &printer, false);
+}
+
+string ServiceJavaPackage(const FileDescriptor* file, bool nano) {
+ string result = google::protobuf::compiler::java::ClassName(file);
+ size_t last_dot_pos = result.find_last_of('.');
+ if (last_dot_pos != string::npos) {
+ result.resize(last_dot_pos);
+ } else {
+ result = "";
+ }
+ if (nano) {
+ if (!result.empty()) {
+ result += ".";
+ }
+ result += "nano";
+ }
+ return result;
+}
+
+string ServiceClassName(const google::protobuf::ServiceDescriptor* service) {
+ return service->name() + "Dubbo";
+}
+
+} // namespace java_dubbo_generator
diff --git a/compiler/src/java_plugin/cpp/java_generator.cpp b/compiler/src/java_plugin/cpp/java_generator.cpp
new file mode 100644
index 0000000000..e1861f005f
--- /dev/null
+++ b/compiler/src/java_plugin/cpp/java_generator.cpp
@@ -0,0 +1,1553 @@
+#include "java_generator.h"
+
+#include
+#include
+#include
+#include