aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes1
-rw-r--r--compiler/build.gradle20
-rw-r--r--compiler/src/java_plugin/cpp/java_generator.cpp31
-rw-r--r--compiler/src/java_plugin/cpp/java_generator.h6
-rw-r--r--compiler/src/java_plugin/cpp/java_plugin.cpp15
-rw-r--r--compiler/src/test/golden/TestServiceLite.java.txt323
-rw-r--r--compiler/src/test/proto/test_lite.proto54
-rw-r--r--protobuf-lite/build.gradle15
-rw-r--r--protobuf-lite/src/main/java/io/grpc/protobuf/lite/ProtoInputStream.java (renamed from protobuf/src/main/java/io/grpc/protobuf/ProtoInputStream.java)2
-rw-r--r--protobuf-lite/src/main/java/io/grpc/protobuf/lite/ProtoLiteUtils.java136
-rw-r--r--protobuf-lite/src/test/java/io/grpc/protobuf/lite/ProtoLiteUtilsTest.java214
-rw-r--r--protobuf/build.gradle1
-rw-r--r--protobuf/src/main/java/io/grpc/protobuf/ProtoUtils.java92
-rw-r--r--protobuf/src/test/java/io/grpc/protobuf/ProtoUtilsTest.java161
-rw-r--r--settings.gradle2
15 files changed, 817 insertions, 256 deletions
diff --git a/.gitattributes b/.gitattributes
index af34525bb..6754557ea 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,2 +1,3 @@
TestService.java.txt binary
+TestServiceLite.java.txt binary
TestServiceNano.java.txt binary
diff --git a/compiler/build.gradle b/compiler/build.gradle
index a48799297..740bf4b1e 100644
--- a/compiler/build.gradle
+++ b/compiler/build.gradle
@@ -127,6 +127,11 @@ sourceSets {
}
}
+compileTestJava {
+ // Protobuf-generated Lite produces quite a few warnings.
+ it.options.compilerArgs.removeAll(["-Xlint:unchecked", "-Xlint:rawtypes"])
+}
+
protobuf {
protoc {
if (project.hasProperty('protoc')) {
@@ -223,10 +228,11 @@ artifacts {
}
}
-test.dependsOn('testGolden', 'testNanoGolden')
+test.dependsOn('testGolden', 'testLiteGolden', 'testNanoGolden')
-def configureTestTask(Task task, String suffix, String extraPackage) {
- task.dependsOn "generateTest${suffix}Proto"
+def configureTestTask(Task task, String suffix, String dep,
+ String extraPackage) {
+ task.dependsOn "generateTest${dep}Proto"
if (osdetector.os != 'windows') {
task.executable "diff"
} else {
@@ -234,11 +240,13 @@ def configureTestTask(Task task, String suffix, String extraPackage) {
}
// File isn't found on Windows if last slash is forward-slash
def slash = System.getProperty("file.separator")
- task.args "$buildDir/generated/source/proto/test${suffix}/grpc/io/grpc/testing/integration${extraPackage}${slash}TestServiceGrpc.java",
+ task.args "$buildDir/generated/source/proto/test${dep}/grpc/io/grpc/testing/integration${extraPackage}${slash}TestServiceGrpc.java",
"$projectDir/src/test/golden/TestService${suffix}.java.txt"
}
task testGolden(type: Exec)
+task testLiteGolden(type: Exec)
task testNanoGolden(type: Exec)
-configureTestTask(testGolden, '', '')
-configureTestTask(testNanoGolden, 'Nano', '/nano')
+configureTestTask(testGolden, '', '', '')
+configureTestTask(testLiteGolden, 'Lite', '', '/lite')
+configureTestTask(testNanoGolden, 'Nano', 'Nano', '/nano')
diff --git a/compiler/src/java_plugin/cpp/java_generator.cpp b/compiler/src/java_plugin/cpp/java_generator.cpp
index 30a62229a..cf8cdbe79 100644
--- a/compiler/src/java_plugin/cpp/java_generator.cpp
+++ b/compiler/src/java_plugin/cpp/java_generator.cpp
@@ -83,7 +83,7 @@ static inline string MessageFullJavaName(bool nano, const Descriptor* desc) {
static void PrintMethodFields(
const ServiceDescriptor* service, map<string, string>* vars, Printer* p,
- bool generate_nano) {
+ ProtoFlavor flavor) {
p->Print("// Static method descriptors that strictly reflect the proto.\n");
(*vars)["service_name"] = service->name();
for (int i = 0; i < service->method_count(); ++i) {
@@ -91,9 +91,9 @@ static void PrintMethodFields(
(*vars)["arg_in_id"] = to_string(2 * i);
(*vars)["arg_out_id"] = to_string(2 * i + 1);
(*vars)["method_name"] = method->name();
- (*vars)["input_type"] = MessageFullJavaName(generate_nano,
+ (*vars)["input_type"] = MessageFullJavaName(flavor == ProtoFlavor::NANO,
method->input_type());
- (*vars)["output_type"] = MessageFullJavaName(generate_nano,
+ (*vars)["output_type"] = MessageFullJavaName(flavor == ProtoFlavor::NANO,
method->output_type());
(*vars)["method_field_name"] = MethodPropertiesFieldName(method);
bool client_streaming = method->client_streaming();
@@ -112,7 +112,7 @@ static void PrintMethodFields(
}
}
- if (generate_nano) {
+ if (flavor == ProtoFlavor::NANO) {
// TODO(zsurocking): we're creating two NanoFactories for each method right now.
// We could instead create static NanoFactories and reuse them if some methods
// share the same request or response messages.
@@ -133,6 +133,11 @@ static void PrintMethodFields(
" new NanoFactory<$output_type$>(ARG_OUT_$method_field_name$))\n"
" );\n");
} else {
+ if (flavor == ProtoFlavor::LITE) {
+ (*vars)["ProtoUtils"] = "io.grpc.protobuf.lite.ProtoLiteUtils";
+ } else {
+ (*vars)["ProtoUtils"] = "io.grpc.protobuf.ProtoUtils";
+ }
p->Print(
*vars,
"@$ExperimentalApi$\n"
@@ -148,7 +153,7 @@ static void PrintMethodFields(
}
p->Print("\n");
- if (generate_nano) {
+ if (flavor == ProtoFlavor::NANO) {
p->Print(
"private static final class NanoFactory<T extends com.google.protobuf.nano.MessageNano>\n"
" implements io.grpc.protobuf.nano.MessageNanoFactory<T> {\n"
@@ -162,6 +167,7 @@ static void PrintMethodFields(
" public T newInstance() {\n"
" Object o;\n"
" switch (id) {\n");
+ bool generate_nano = true;
for (int i = 0; i < service->method_count(); ++i) {
const MethodDescriptor* method = service->method(i);
(*vars)["input_type"] = MessageFullJavaName(generate_nano,
@@ -639,7 +645,7 @@ static void PrintBindServiceMethod(const ServiceDescriptor* service,
static void PrintService(const ServiceDescriptor* service,
map<string, string>* vars,
Printer* p,
- bool generate_nano) {
+ ProtoFlavor flavor) {
(*vars)["service_name"] = service->name();
(*vars)["file_name"] = service->file()->name();
(*vars)["service_class_name"] = ServiceClassName(service);
@@ -659,7 +665,7 @@ static void PrintService(const ServiceDescriptor* service,
"public static final String SERVICE_NAME = "
"\"$Package$$service_name$\";\n\n");
- PrintMethodFields(service, vars, p, generate_nano);
+ PrintMethodFields(service, vars, p, flavor);
p->Print(
*vars,
@@ -691,6 +697,7 @@ static void PrintService(const ServiceDescriptor* service,
p->Outdent();
p->Print("}\n\n");
+ bool generate_nano = flavor == ProtoFlavor::NANO;
PrintStub(service, vars, p, ASYNC_INTERFACE, generate_nano);
PrintStub(service, vars, p, BLOCKING_CLIENT_INTERFACE, generate_nano);
PrintStub(service, vars, p, FUTURE_CLIENT_INTERFACE, generate_nano);
@@ -736,7 +743,7 @@ void PrintImports(Printer* p, bool generate_nano) {
void GenerateService(const ServiceDescriptor* service,
google::protobuf::io::ZeroCopyOutputStream* out,
- bool generate_nano) {
+ ProtoFlavor flavor) {
// All non-generated classes must be referred by fully qualified names to
// avoid collision with generated classes.
map<string, string> vars;
@@ -753,7 +760,6 @@ void GenerateService(const ServiceDescriptor* service,
vars["ImmutableList"] = "com.google.common.collect.ImmutableList";
vars["Collection"] = "java.util.Collection";
vars["MethodDescriptor"] = "io.grpc.MethodDescriptor";
- vars["ProtoUtils"] = "io.grpc.protobuf.ProtoUtils";
vars["NanoUtils"] = "io.grpc.protobuf.nano.NanoUtils";
vars["StreamObserver"] = "io.grpc.stub.StreamObserver";
vars["Iterator"] = "java.util.Iterator";
@@ -766,20 +772,21 @@ void GenerateService(const ServiceDescriptor* service,
vars["ExperimentalApi"] = "io.grpc.ExperimentalApi";
Printer printer(out, '$');
- string package_name = ServiceJavaPackage(service->file(), generate_nano);
+ string package_name = ServiceJavaPackage(service->file(),
+ flavor == ProtoFlavor::NANO);
if (!package_name.empty()) {
printer.Print(
"package $package_name$;\n\n",
"package_name", package_name);
}
- PrintImports(&printer, generate_nano);
+ PrintImports(&printer, flavor == ProtoFlavor::NANO);
// 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, generate_nano);
+ PrintService(service, &vars, &printer, flavor);
}
string ServiceJavaPackage(const FileDescriptor* file, bool nano) {
diff --git a/compiler/src/java_plugin/cpp/java_generator.h b/compiler/src/java_plugin/cpp/java_generator.h
index 96b3b8aaa..29c6fd952 100644
--- a/compiler/src/java_plugin/cpp/java_generator.h
+++ b/compiler/src/java_plugin/cpp/java_generator.h
@@ -38,6 +38,10 @@ using namespace std;
namespace java_grpc_generator {
+enum ProtoFlavor {
+ NORMAL, LITE, NANO
+};
+
// Returns the package name of the gRPC services defined in the given file.
string ServiceJavaPackage(const google::protobuf::FileDescriptor* file, bool nano);
@@ -48,7 +52,7 @@ string ServiceClassName(const google::protobuf::ServiceDescriptor* service);
// Writes the generated service interface into the given ZeroCopyOutputStream
void GenerateService(const google::protobuf::ServiceDescriptor* service,
google::protobuf::io::ZeroCopyOutputStream* out,
- bool generate_nano);
+ ProtoFlavor flavor);
} // namespace java_grpc_generator
diff --git a/compiler/src/java_plugin/cpp/java_plugin.cpp b/compiler/src/java_plugin/cpp/java_plugin.cpp
index 8f9a2e81f..1c95497ba 100644
--- a/compiler/src/java_plugin/cpp/java_plugin.cpp
+++ b/compiler/src/java_plugin/cpp/java_plugin.cpp
@@ -9,6 +9,7 @@
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/compiler/plugin.h>
#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/zero_copy_stream.h>
static string JavaPackageToDir(const string& package_name) {
@@ -34,14 +35,20 @@ class JavaGrpcGenerator : public google::protobuf::compiler::CodeGenerator {
vector<pair<string, string> > options;
google::protobuf::compiler::ParseGeneratorParameter(parameter, &options);
- bool generate_nano = false;
+ java_grpc_generator::ProtoFlavor flavor =
+ java_grpc_generator::ProtoFlavor::NORMAL;
+ if (file->options().optimize_for() ==
+ google::protobuf::FileOptions::LITE_RUNTIME) {
+ flavor = java_grpc_generator::ProtoFlavor::LITE;
+ }
for (int i = 0; i < options.size(); i++) {
if (options[i].first == "nano" && options[i].second == "true") {
- generate_nano = true;
+ flavor = java_grpc_generator::ProtoFlavor::NANO;
}
}
- string package_name = java_grpc_generator::ServiceJavaPackage(file, generate_nano);
+ string package_name = java_grpc_generator::ServiceJavaPackage(
+ file, flavor == java_grpc_generator::ProtoFlavor::NANO);
string package_filename = JavaPackageToDir(package_name);
for (int i = 0; i < file->service_count(); ++i) {
const google::protobuf::ServiceDescriptor* service = file->service(i);
@@ -49,7 +56,7 @@ class JavaGrpcGenerator : public google::protobuf::compiler::CodeGenerator {
+ java_grpc_generator::ServiceClassName(service) + ".java";
std::unique_ptr<google::protobuf::io::ZeroCopyOutputStream> output(
context->Open(filename));
- java_grpc_generator::GenerateService(service, output.get(), generate_nano);
+ java_grpc_generator::GenerateService(service, output.get(), flavor);
}
return true;
}
diff --git a/compiler/src/test/golden/TestServiceLite.java.txt b/compiler/src/test/golden/TestServiceLite.java.txt
new file mode 100644
index 000000000..86da7e77e
--- /dev/null
+++ b/compiler/src/test/golden/TestServiceLite.java.txt
@@ -0,0 +1,323 @@
+package io.grpc.testing.integration.lite;
+
+import static io.grpc.stub.ClientCalls.asyncUnaryCall;
+import static io.grpc.stub.ClientCalls.asyncServerStreamingCall;
+import static io.grpc.stub.ClientCalls.asyncClientStreamingCall;
+import static io.grpc.stub.ClientCalls.asyncBidiStreamingCall;
+import static io.grpc.stub.ClientCalls.blockingUnaryCall;
+import static io.grpc.stub.ClientCalls.blockingServerStreamingCall;
+import static io.grpc.stub.ClientCalls.futureUnaryCall;
+import static io.grpc.MethodDescriptor.generateFullMethodName;
+import static io.grpc.stub.ServerCalls.asyncUnaryCall;
+import static io.grpc.stub.ServerCalls.asyncServerStreamingCall;
+import static io.grpc.stub.ServerCalls.asyncClientStreamingCall;
+import static io.grpc.stub.ServerCalls.asyncBidiStreamingCall;
+
+@javax.annotation.Generated(
+ value = "by gRPC proto compiler",
+ comments = "Source: test_lite.proto")
+public class TestServiceGrpc {
+
+ private TestServiceGrpc() {}
+
+ public static final String SERVICE_NAME = "grpc.testing.lite.TestService";
+
+ // Static method descriptors that strictly reflect the proto.
+ @io.grpc.ExperimentalApi
+ public static final io.grpc.MethodDescriptor<io.grpc.testing.integration.lite.TestLite.SimpleRequest,
+ io.grpc.testing.integration.lite.TestLite.SimpleResponse> METHOD_UNARY_CALL =
+ io.grpc.MethodDescriptor.create(
+ io.grpc.MethodDescriptor.MethodType.UNARY,
+ generateFullMethodName(
+ "grpc.testing.lite.TestService", "UnaryCall"),
+ io.grpc.protobuf.lite.ProtoLiteUtils.marshaller(io.grpc.testing.integration.lite.TestLite.SimpleRequest.getDefaultInstance()),
+ io.grpc.protobuf.lite.ProtoLiteUtils.marshaller(io.grpc.testing.integration.lite.TestLite.SimpleResponse.getDefaultInstance()));
+ @io.grpc.ExperimentalApi
+ public static final io.grpc.MethodDescriptor<io.grpc.testing.integration.lite.TestLite.StreamingOutputCallRequest,
+ io.grpc.testing.integration.lite.TestLite.StreamingOutputCallResponse> METHOD_STREAMING_OUTPUT_CALL =
+ io.grpc.MethodDescriptor.create(
+ io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING,
+ generateFullMethodName(
+ "grpc.testing.lite.TestService", "StreamingOutputCall"),
+ io.grpc.protobuf.lite.ProtoLiteUtils.marshaller(io.grpc.testing.integration.lite.TestLite.StreamingOutputCallRequest.getDefaultInstance()),
+ io.grpc.protobuf.lite.ProtoLiteUtils.marshaller(io.grpc.testing.integration.lite.TestLite.StreamingOutputCallResponse.getDefaultInstance()));
+ @io.grpc.ExperimentalApi
+ public static final io.grpc.MethodDescriptor<io.grpc.testing.integration.lite.TestLite.StreamingInputCallRequest,
+ io.grpc.testing.integration.lite.TestLite.StreamingInputCallResponse> METHOD_STREAMING_INPUT_CALL =
+ io.grpc.MethodDescriptor.create(
+ io.grpc.MethodDescriptor.MethodType.CLIENT_STREAMING,
+ generateFullMethodName(
+ "grpc.testing.lite.TestService", "StreamingInputCall"),
+ io.grpc.protobuf.lite.ProtoLiteUtils.marshaller(io.grpc.testing.integration.lite.TestLite.StreamingInputCallRequest.getDefaultInstance()),
+ io.grpc.protobuf.lite.ProtoLiteUtils.marshaller(io.grpc.testing.integration.lite.TestLite.StreamingInputCallResponse.getDefaultInstance()));
+ @io.grpc.ExperimentalApi
+ public static final io.grpc.MethodDescriptor<io.grpc.testing.integration.lite.TestLite.StreamingOutputCallRequest,
+ io.grpc.testing.integration.lite.TestLite.StreamingOutputCallResponse> METHOD_FULL_BIDI_CALL =
+ io.grpc.MethodDescriptor.create(
+ io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING,
+ generateFullMethodName(
+ "grpc.testing.lite.TestService", "FullBidiCall"),
+ io.grpc.protobuf.lite.ProtoLiteUtils.marshaller(io.grpc.testing.integration.lite.TestLite.StreamingOutputCallRequest.getDefaultInstance()),
+ io.grpc.protobuf.lite.ProtoLiteUtils.marshaller(io.grpc.testing.integration.lite.TestLite.StreamingOutputCallResponse.getDefaultInstance()));
+ @io.grpc.ExperimentalApi
+ public static final io.grpc.MethodDescriptor<io.grpc.testing.integration.lite.TestLite.StreamingOutputCallRequest,
+ io.grpc.testing.integration.lite.TestLite.StreamingOutputCallResponse> METHOD_HALF_BIDI_CALL =
+ io.grpc.MethodDescriptor.create(
+ io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING,
+ generateFullMethodName(
+ "grpc.testing.lite.TestService", "HalfBidiCall"),
+ io.grpc.protobuf.lite.ProtoLiteUtils.marshaller(io.grpc.testing.integration.lite.TestLite.StreamingOutputCallRequest.getDefaultInstance()),
+ io.grpc.protobuf.lite.ProtoLiteUtils.marshaller(io.grpc.testing.integration.lite.TestLite.StreamingOutputCallResponse.getDefaultInstance()));
+
+ public static TestServiceStub newStub(io.grpc.Channel channel) {
+ return new TestServiceStub(channel);
+ }
+
+ public static TestServiceBlockingStub newBlockingStub(
+ io.grpc.Channel channel) {
+ return new TestServiceBlockingStub(channel);
+ }
+
+ public static TestServiceFutureStub newFutureStub(
+ io.grpc.Channel channel) {
+ return new TestServiceFutureStub(channel);
+ }
+
+ public static interface TestService {
+
+ public void unaryCall(io.grpc.testing.integration.lite.TestLite.SimpleRequest request,
+ io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.SimpleResponse> responseObserver);
+
+ public void streamingOutputCall(io.grpc.testing.integration.lite.TestLite.StreamingOutputCallRequest request,
+ io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.StreamingOutputCallResponse> responseObserver);
+
+ public io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.StreamingInputCallRequest> streamingInputCall(
+ io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.StreamingInputCallResponse> responseObserver);
+
+ public io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.StreamingOutputCallRequest> fullBidiCall(
+ io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.StreamingOutputCallResponse> responseObserver);
+
+ public io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.StreamingOutputCallRequest> halfBidiCall(
+ io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.StreamingOutputCallResponse> responseObserver);
+ }
+
+ public static interface TestServiceBlockingClient {
+
+ public io.grpc.testing.integration.lite.TestLite.SimpleResponse unaryCall(io.grpc.testing.integration.lite.TestLite.SimpleRequest request);
+
+ public java.util.Iterator<io.grpc.testing.integration.lite.TestLite.StreamingOutputCallResponse> streamingOutputCall(
+ io.grpc.testing.integration.lite.TestLite.StreamingOutputCallRequest request);
+ }
+
+ public static interface TestServiceFutureClient {
+
+ public com.google.common.util.concurrent.ListenableFuture<io.grpc.testing.integration.lite.TestLite.SimpleResponse> unaryCall(
+ io.grpc.testing.integration.lite.TestLite.SimpleRequest request);
+ }
+
+ public static class TestServiceStub extends io.grpc.stub.AbstractStub<TestServiceStub>
+ implements TestService {
+ private TestServiceStub(io.grpc.Channel channel) {
+ super(channel);
+ }
+
+ private TestServiceStub(io.grpc.Channel channel,
+ io.grpc.CallOptions callOptions) {
+ super(channel, callOptions);
+ }
+
+ @java.lang.Override
+ protected TestServiceStub build(io.grpc.Channel channel,
+ io.grpc.CallOptions callOptions) {
+ return new TestServiceStub(channel, callOptions);
+ }
+
+ @java.lang.Override
+ public void unaryCall(io.grpc.testing.integration.lite.TestLite.SimpleRequest request,
+ io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.SimpleResponse> responseObserver) {
+ asyncUnaryCall(
+ getChannel().newCall(METHOD_UNARY_CALL, getCallOptions()), request, responseObserver);
+ }
+
+ @java.lang.Override
+ public void streamingOutputCall(io.grpc.testing.integration.lite.TestLite.StreamingOutputCallRequest request,
+ io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.StreamingOutputCallResponse> responseObserver) {
+ asyncServerStreamingCall(
+ getChannel().newCall(METHOD_STREAMING_OUTPUT_CALL, getCallOptions()), request, responseObserver);
+ }
+
+ @java.lang.Override
+ public io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.StreamingInputCallRequest> streamingInputCall(
+ io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.StreamingInputCallResponse> responseObserver) {
+ return asyncClientStreamingCall(
+ getChannel().newCall(METHOD_STREAMING_INPUT_CALL, getCallOptions()), responseObserver);
+ }
+
+ @java.lang.Override
+ public io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.StreamingOutputCallRequest> fullBidiCall(
+ io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.StreamingOutputCallResponse> responseObserver) {
+ return asyncBidiStreamingCall(
+ getChannel().newCall(METHOD_FULL_BIDI_CALL, getCallOptions()), responseObserver);
+ }
+
+ @java.lang.Override
+ public io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.StreamingOutputCallRequest> halfBidiCall(
+ io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.StreamingOutputCallResponse> responseObserver) {
+ return asyncBidiStreamingCall(
+ getChannel().newCall(METHOD_HALF_BIDI_CALL, getCallOptions()), responseObserver);
+ }
+ }
+
+ public static class TestServiceBlockingStub extends io.grpc.stub.AbstractStub<TestServiceBlockingStub>
+ implements TestServiceBlockingClient {
+ private TestServiceBlockingStub(io.grpc.Channel channel) {
+ super(channel);
+ }
+
+ private TestServiceBlockingStub(io.grpc.Channel channel,
+ io.grpc.CallOptions callOptions) {
+ super(channel, callOptions);
+ }
+
+ @java.lang.Override
+ protected TestServiceBlockingStub build(io.grpc.Channel channel,
+ io.grpc.CallOptions callOptions) {
+ return new TestServiceBlockingStub(channel, callOptions);
+ }
+
+ @java.lang.Override
+ public io.grpc.testing.integration.lite.TestLite.SimpleResponse unaryCall(io.grpc.testing.integration.lite.TestLite.SimpleRequest request) {
+ return blockingUnaryCall(
+ getChannel(), METHOD_UNARY_CALL, getCallOptions(), request);
+ }
+
+ @java.lang.Override
+ public java.util.Iterator<io.grpc.testing.integration.lite.TestLite.StreamingOutputCallResponse> streamingOutputCall(
+ io.grpc.testing.integration.lite.TestLite.StreamingOutputCallRequest request) {
+ return blockingServerStreamingCall(
+ getChannel(), METHOD_STREAMING_OUTPUT_CALL, getCallOptions(), request);
+ }
+ }
+
+ public static class TestServiceFutureStub extends io.grpc.stub.AbstractStub<TestServiceFutureStub>
+ implements TestServiceFutureClient {
+ private TestServiceFutureStub(io.grpc.Channel channel) {
+ super(channel);
+ }
+
+ private TestServiceFutureStub(io.grpc.Channel channel,
+ io.grpc.CallOptions callOptions) {
+ super(channel, callOptions);
+ }
+
+ @java.lang.Override
+ protected TestServiceFutureStub build(io.grpc.Channel channel,
+ io.grpc.CallOptions callOptions) {
+ return new TestServiceFutureStub(channel, callOptions);
+ }
+
+ @java.lang.Override
+ public com.google.common.util.concurrent.ListenableFuture<io.grpc.testing.integration.lite.TestLite.SimpleResponse> unaryCall(
+ io.grpc.testing.integration.lite.TestLite.SimpleRequest request) {
+ return futureUnaryCall(
+ getChannel().newCall(METHOD_UNARY_CALL, getCallOptions()), request);
+ }
+ }
+
+ private static final int METHODID_UNARY_CALL = 0;
+ private static final int METHODID_STREAMING_OUTPUT_CALL = 1;
+ private static final int METHODID_STREAMING_INPUT_CALL = 2;
+ private static final int METHODID_FULL_BIDI_CALL = 3;
+ private static final int METHODID_HALF_BIDI_CALL = 4;
+
+ private static class MethodHandlers<Req, Resp> implements
+ io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,
+ io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,
+ io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,
+ io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {
+ private final TestService serviceImpl;
+ private final int methodId;
+
+ public MethodHandlers(TestService serviceImpl, int methodId) {
+ this.serviceImpl = serviceImpl;
+ this.methodId = methodId;
+ }
+
+ @java.lang.Override
+ @java.lang.SuppressWarnings("unchecked")
+ public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {
+ switch (methodId) {
+ case METHODID_UNARY_CALL:
+ serviceImpl.unaryCall((io.grpc.testing.integration.lite.TestLite.SimpleRequest) request,
+ (io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.SimpleResponse>) responseObserver);
+ break;
+ case METHODID_STREAMING_OUTPUT_CALL:
+ serviceImpl.streamingOutputCall((io.grpc.testing.integration.lite.TestLite.StreamingOutputCallRequest) request,
+ (io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.StreamingOutputCallResponse>) responseObserver);
+ break;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ @java.lang.Override
+ @java.lang.SuppressWarnings("unchecked")
+ public io.grpc.stub.StreamObserver<Req> invoke(
+ io.grpc.stub.StreamObserver<Resp> responseObserver) {
+ switch (methodId) {
+ case METHODID_STREAMING_INPUT_CALL:
+ return (io.grpc.stub.StreamObserver<Req>) serviceImpl.streamingInputCall(
+ (io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.StreamingInputCallResponse>) responseObserver);
+ case METHODID_FULL_BIDI_CALL:
+ return (io.grpc.stub.StreamObserver<Req>) serviceImpl.fullBidiCall(
+ (io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.StreamingOutputCallResponse>) responseObserver);
+ case METHODID_HALF_BIDI_CALL:
+ return (io.grpc.stub.StreamObserver<Req>) serviceImpl.halfBidiCall(
+ (io.grpc.stub.StreamObserver<io.grpc.testing.integration.lite.TestLite.StreamingOutputCallResponse>) responseObserver);
+ default:
+ throw new AssertionError();
+ }
+ }
+ }
+
+ public static io.grpc.ServerServiceDefinition bindService(
+ final TestService serviceImpl) {
+ return io.grpc.ServerServiceDefinition.builder(SERVICE_NAME)
+ .addMethod(
+ METHOD_UNARY_CALL,
+ asyncUnaryCall(
+ new MethodHandlers<
+ io.grpc.testing.integration.lite.TestLite.SimpleRequest,
+ io.grpc.testing.integration.lite.TestLite.SimpleResponse>(
+ serviceImpl, METHODID_UNARY_CALL)))
+ .addMethod(
+ METHOD_STREAMING_OUTPUT_CALL,
+ asyncServerStreamingCall(
+ new MethodHandlers<
+ io.grpc.testing.integration.lite.TestLite.StreamingOutputCallRequest,
+ io.grpc.testing.integration.lite.TestLite.StreamingOutputCallResponse>(
+ serviceImpl, METHODID_STREAMING_OUTPUT_CALL)))
+ .addMethod(
+ METHOD_STREAMING_INPUT_CALL,
+ asyncClientStreamingCall(
+ new MethodHandlers<
+ io.grpc.testing.integration.lite.TestLite.StreamingInputCallRequest,
+ io.grpc.testing.integration.lite.TestLite.StreamingInputCallResponse>(
+ serviceImpl, METHODID_STREAMING_INPUT_CALL)))
+ .addMethod(
+ METHOD_FULL_BIDI_CALL,
+ asyncBidiStreamingCall(
+ new MethodHandlers<
+ io.grpc.testing.integration.lite.TestLite.StreamingOutputCallRequest,
+ io.grpc.testing.integration.lite.TestLite.StreamingOutputCallResponse>(
+ serviceImpl, METHODID_FULL_BIDI_CALL)))
+ .addMethod(
+ METHOD_HALF_BIDI_CALL,
+ asyncBidiStreamingCall(
+ new MethodHandlers<
+ io.grpc.testing.integration.lite.TestLite.StreamingOutputCallRequest,
+ io.grpc.testing.integration.lite.TestLite.StreamingOutputCallResponse>(
+ serviceImpl, METHODID_HALF_BIDI_CALL)))
+ .build();
+ }
+}
diff --git a/compiler/src/test/proto/test_lite.proto b/compiler/src/test/proto/test_lite.proto
new file mode 100644
index 000000000..0e422033e
--- /dev/null
+++ b/compiler/src/test/proto/test_lite.proto
@@ -0,0 +1,54 @@
+// A simple service definition for testing the protoc plugin.
+syntax = "proto2";
+
+package grpc.testing.lite;
+
+option java_package = "io.grpc.testing.integration.lite";
+option optimize_for = LITE_RUNTIME;
+
+message SimpleRequest {
+}
+
+message SimpleResponse {
+}
+
+message StreamingInputCallRequest {
+}
+
+message StreamingInputCallResponse {
+}
+
+message StreamingOutputCallRequest {
+}
+
+message StreamingOutputCallResponse {
+}
+
+service TestService {
+ // One request followed by one response.
+ // The server returns the client payload as-is.
+ rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
+
+ // One request followed by a sequence of responses (streamed download).
+ // The server returns the payload with client desired type and sizes.
+ rpc StreamingOutputCall(StreamingOutputCallRequest)
+ returns (stream StreamingOutputCallResponse);
+
+ // A sequence of requests followed by one response (streamed upload).
+ // The server returns the aggregated size of client payload as the result.
+ rpc StreamingInputCall(stream StreamingInputCallRequest)
+ returns (StreamingInputCallResponse);
+
+ // A sequence of requests with each request served by the server immediately.
+ // As one request could lead to multiple responses, this interface
+ // demonstrates the idea of full bidirectionality.
+ rpc FullBidiCall(stream StreamingOutputCallRequest)
+ returns (stream StreamingOutputCallResponse);
+
+ // A sequence of requests followed by a sequence of responses.
+ // The server buffers all the client requests and then serves them in order. A
+ // stream of responses are returned to the client when the server starts with
+ // first request.
+ rpc HalfBidiCall(stream StreamingOutputCallRequest)
+ returns (stream StreamingOutputCallResponse);
+}
diff --git a/protobuf-lite/build.gradle b/protobuf-lite/build.gradle
new file mode 100644
index 000000000..1425a3bb8
--- /dev/null
+++ b/protobuf-lite/build.gradle
@@ -0,0 +1,15 @@
+plugins {
+ id "be.insaneprogramming.gradle.animalsniffer" version "1.4.0"
+}
+
+description = 'gRPC: Protobuf Lite'
+
+dependencies {
+ compile project(':grpc-core'),
+ libraries.protobuf,
+ libraries.guava
+}
+
+animalsniffer {
+ signature = "org.codehaus.mojo.signature:java16:+@signature"
+}
diff --git a/protobuf/src/main/java/io/grpc/protobuf/ProtoInputStream.java b/protobuf-lite/src/main/java/io/grpc/protobuf/lite/ProtoInputStream.java
index 186e3c12e..b2e4282f5 100644
--- a/protobuf/src/main/java/io/grpc/protobuf/ProtoInputStream.java
+++ b/protobuf-lite/src/main/java/io/grpc/protobuf/lite/ProtoInputStream.java
@@ -29,7 +29,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package io.grpc.protobuf;
+package io.grpc.protobuf.lite;
import com.google.common.io.ByteStreams;
import com.google.protobuf.CodedOutputStream;
diff --git a/protobuf-lite/src/main/java/io/grpc/protobuf/lite/ProtoLiteUtils.java b/protobuf-lite/src/main/java/io/grpc/protobuf/lite/ProtoLiteUtils.java
new file mode 100644
index 000000000..c5677ff5e
--- /dev/null
+++ b/protobuf-lite/src/main/java/io/grpc/protobuf/lite/ProtoLiteUtils.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2014, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package io.grpc.protobuf.lite;
+
+import com.google.protobuf.CodedInputStream;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.MessageLite;
+import com.google.protobuf.Parser;
+
+import io.grpc.ExperimentalApi;
+import io.grpc.Metadata;
+import io.grpc.MethodDescriptor.Marshaller;
+import io.grpc.Status;
+
+import java.io.InputStream;
+
+/**
+ * Utility methods for using protobuf with grpc.
+ */
+@ExperimentalApi("Experimental until Lite is stable in protobuf")
+public class ProtoLiteUtils {
+
+ /** Create a {@code Marshaller} for protos of the same type as {@code defaultInstance}. */
+ public static <T extends MessageLite> Marshaller<T> marshaller(final T defaultInstance) {
+ @SuppressWarnings("unchecked")
+ final Parser<T> parser = (Parser<T>) defaultInstance.getParserForType();
+ return new Marshaller<T>() {
+ @Override
+ public InputStream stream(T value) {
+ return new ProtoInputStream(value, parser);
+ }
+
+ @Override
+ public T parse(InputStream stream) {
+ if (stream instanceof ProtoInputStream) {
+ ProtoInputStream protoStream = (ProtoInputStream) stream;
+ // Optimization for in-memory transport. Returning provided object is safe since protobufs
+ // are immutable.
+ //
+ // However, we can't assume the types match, so we have to verify the parser matches.
+ // Today the parser is always the same for a given proto, but that isn't guaranteed. Even
+ // if not, using the same MethodDescriptor would ensure the parser matches and permit us
+ // to enable this optimization.
+ if (protoStream.parser() == parser) {
+ try {
+ @SuppressWarnings("unchecked")
+ T message = (T) ((ProtoInputStream) stream).message();
+ return message;
+ } catch (IllegalStateException ex) {
+ // Stream must have been read from, which is a strange state. Since the point of this
+ // optimization is to be transparent, instead of throwing an error we'll continue,
+ // even though it seems likely there's a bug.
+ }
+ }
+ }
+ try {
+ return parseFrom(stream);
+ } catch (InvalidProtocolBufferException ipbe) {
+ throw Status.INTERNAL.withDescription("Invalid protobuf byte sequence")
+ .withCause(ipbe).asRuntimeException();
+ }
+ }
+
+ private T parseFrom(InputStream stream) throws InvalidProtocolBufferException {
+ // Pre-create the CodedInputStream so that we can remove the size limit restriction
+ // when parsing.
+ CodedInputStream codedInput = CodedInputStream.newInstance(stream);
+ codedInput.setSizeLimit(Integer.MAX_VALUE);
+
+ T message = parser.parseFrom(codedInput);
+ try {
+ codedInput.checkLastTagWas(0);
+ return message;
+ } catch (InvalidProtocolBufferException e) {
+ e.setUnfinishedMessage(message);
+ throw e;
+ }
+ }
+ };
+ }
+
+ /**
+ * Produce a metadata marshaller for a protobuf type.
+ */
+ public static <T extends MessageLite> Metadata.BinaryMarshaller<T> metadataMarshaller(
+ final T instance) {
+ return new Metadata.BinaryMarshaller<T>() {
+ @Override
+ public byte[] toBytes(T value) {
+ return value.toByteArray();
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public T parseBytes(byte[] serialized) {
+ try {
+ return (T) instance.getParserForType().parseFrom(serialized);
+ } catch (InvalidProtocolBufferException ipbe) {
+ throw new IllegalArgumentException(ipbe);
+ }
+ }
+ };
+ }
+
+ private ProtoLiteUtils() {
+ }
+}
diff --git a/protobuf-lite/src/test/java/io/grpc/protobuf/lite/ProtoLiteUtilsTest.java b/protobuf-lite/src/test/java/io/grpc/protobuf/lite/ProtoLiteUtilsTest.java
new file mode 100644
index 000000000..a5042a435
--- /dev/null
+++ b/protobuf-lite/src/test/java/io/grpc/protobuf/lite/ProtoLiteUtilsTest.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2015, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package io.grpc.protobuf.lite;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+
+import com.google.common.io.ByteStreams;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.Empty;
+import com.google.protobuf.Enum;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.Type;
+
+import io.grpc.Drainable;
+import io.grpc.Metadata;
+import io.grpc.MethodDescriptor.Marshaller;
+import io.grpc.Status;
+import io.grpc.StatusRuntimeException;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+
+/** Unit tests for {@link ProtoLiteUtils}. */
+@RunWith(JUnit4.class)
+public class ProtoLiteUtilsTest {
+ private Marshaller<Type> marshaller = ProtoLiteUtils.marshaller(Type.getDefaultInstance());
+ private Type proto = Type.newBuilder().setName("name").build();
+
+ @Test
+ public void testPassthrough() {
+ assertSame(proto, marshaller.parse(marshaller.stream(proto)));
+ }
+
+ @Test
+ public void testRoundtrip() throws Exception {
+ InputStream is = marshaller.stream(proto);
+ is = new ByteArrayInputStream(ByteStreams.toByteArray(is));
+ assertEquals(proto, marshaller.parse(is));
+ }
+
+ @Test
+ public void testInvalidatedMessage() throws Exception {
+ InputStream is = marshaller.stream(proto);
+ // Invalidates message, and drains all bytes
+ ByteStreams.toByteArray(is);
+ try {
+ ((ProtoInputStream) is).message();
+ fail("Expected exception");
+ } catch (IllegalStateException ex) {
+ // expected
+ }
+ // Zero bytes is the default message
+ assertEquals(Type.getDefaultInstance(), marshaller.parse(is));
+ }
+
+ @Test
+ public void parseInvalid() throws Exception {
+ InputStream is = new ByteArrayInputStream(new byte[] {-127});
+ try {
+ marshaller.parse(is);
+ fail("Expected exception");
+ } catch (StatusRuntimeException ex) {
+ assertEquals(Status.Code.INTERNAL, ex.getStatus().getCode());
+ assertNotNull(((InvalidProtocolBufferException) ex.getCause()).getUnfinishedMessage());
+ }
+ }
+
+ @Test
+ public void testMismatch() throws Exception {
+ Marshaller<Enum> enumMarshaller = ProtoLiteUtils.marshaller(Enum.getDefaultInstance());
+ // Enum's name and Type's name are both strings with tag 1.
+ Enum altProto = Enum.newBuilder().setName(proto.getName()).build();
+ assertEquals(proto, marshaller.parse(enumMarshaller.stream(altProto)));
+ }
+
+ @Test
+ public void marshallerShouldNotLimitProtoSize() throws Exception {
+ // The default limit is 64MB. Using a larger proto to verify that the limit is not enforced.
+ byte[] bigName = new byte[70 * 1024 * 1024];
+ Arrays.fill(bigName, (byte) 32);
+
+ proto = Type.newBuilder().setNameBytes(ByteString.copyFrom(bigName)).build();
+
+ // Just perform a round trip to verify that it works.
+ testRoundtrip();
+ }
+
+ @Test
+ public void testAvailable() throws Exception {
+ InputStream is = marshaller.stream(proto);
+ assertEquals(proto.getSerializedSize(), is.available());
+ is.read();
+ assertEquals(proto.getSerializedSize() - 1, is.available());
+ while (is.read() != -1) {}
+ assertEquals(-1, is.read());
+ assertEquals(0, is.available());
+ }
+
+ @Test
+ public void testEmpty() throws IOException {
+ Marshaller<Empty> marshaller = ProtoLiteUtils.marshaller(Empty.getDefaultInstance());
+ InputStream is = marshaller.stream(Empty.getDefaultInstance());
+ assertEquals(0, is.available());
+ byte[] b = new byte[10];
+ assertEquals(-1, is.read(b));
+ assertArrayEquals(new byte[10], b);
+ // Do the same thing again, because the internal state may be different
+ assertEquals(-1, is.read(b));
+ assertArrayEquals(new byte[10], b);
+ assertEquals(-1, is.read());
+ assertEquals(0, is.available());
+ }
+
+ @Test
+ public void testDrainTo_all() throws Exception {
+ byte[] golden = ByteStreams.toByteArray(marshaller.stream(proto));
+ InputStream is = marshaller.stream(proto);
+ Drainable d = (Drainable) is;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ int drained = d.drainTo(baos);
+ assertEquals(baos.size(), drained);
+ assertArrayEquals(golden, baos.toByteArray());
+ assertEquals(0, is.available());
+ }
+
+ @Test
+ public void testDrainTo_partial() throws Exception {
+ final byte[] golden;
+ {
+ InputStream is = marshaller.stream(proto);
+ is.read();
+ golden = ByteStreams.toByteArray(is);
+ }
+ InputStream is = marshaller.stream(proto);
+ is.read();
+ Drainable d = (Drainable) is;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ int drained = d.drainTo(baos);
+ assertEquals(baos.size(), drained);
+ assertArrayEquals(golden, baos.toByteArray());
+ assertEquals(0, is.available());
+ }
+
+ @Test
+ public void testDrainTo_none() throws Exception {
+ byte[] golden = ByteStreams.toByteArray(marshaller.stream(proto));
+ InputStream is = marshaller.stream(proto);
+ ByteStreams.toByteArray(is);
+ Drainable d = (Drainable) is;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ assertEquals(0, d.drainTo(baos));
+ assertArrayEquals(new byte[0], baos.toByteArray());
+ assertEquals(0, is.available());
+ }
+
+ @Test
+ public void metadataMarshaller_roundtrip() {
+ Metadata.BinaryMarshaller<Type> metadataMarshaller =
+ ProtoLiteUtils.metadataMarshaller(Type.getDefaultInstance());
+ assertEquals(proto, metadataMarshaller.parseBytes(metadataMarshaller.toBytes(proto)));
+ }
+
+ @Test
+ public void metadataMarshaller_invalid() {
+ Metadata.BinaryMarshaller<Type> metadataMarshaller =
+ ProtoLiteUtils.metadataMarshaller(Type.getDefaultInstance());
+ try {
+ metadataMarshaller.parseBytes(new byte[] {-127});
+ fail("Expected exception");
+ } catch (IllegalArgumentException ex) {
+ assertNotNull(((InvalidProtocolBufferException) ex.getCause()).getUnfinishedMessage());
+ }
+ }
+}
diff --git a/protobuf/build.gradle b/protobuf/build.gradle
index 89da4b023..6b54173eb 100644
--- a/protobuf/build.gradle
+++ b/protobuf/build.gradle
@@ -6,6 +6,7 @@ description = 'gRPC: Protobuf'
dependencies {
compile project(':grpc-core'),
+ project(':grpc-protobuf-lite'),
libraries.protobuf,
libraries.guava,
libraries.protobuf_util
diff --git a/protobuf/src/main/java/io/grpc/protobuf/ProtoUtils.java b/protobuf/src/main/java/io/grpc/protobuf/ProtoUtils.java
index ae8f0013e..48cb6e1d7 100644
--- a/protobuf/src/main/java/io/grpc/protobuf/ProtoUtils.java
+++ b/protobuf/src/main/java/io/grpc/protobuf/ProtoUtils.java
@@ -31,13 +31,10 @@
package io.grpc.protobuf;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.protobuf.CodedInputStream;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Message;
import com.google.protobuf.Message.Builder;
import com.google.protobuf.MessageLite;
-import com.google.protobuf.Parser;
import com.google.protobuf.util.JsonFormat;
import com.google.protobuf.util.JsonFormat.Printer;
@@ -45,6 +42,7 @@ import io.grpc.ExperimentalApi;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor.Marshaller;
import io.grpc.Status;
+import io.grpc.protobuf.lite.ProtoLiteUtils;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -58,63 +56,19 @@ import java.nio.charset.Charset;
*/
public class ProtoUtils {
- /** Create a {@code Marshaller} for protos of the same type as {@code defaultInstance}. */
+ /**
+ * Create a {@code Marshaller} for protos of the same type as {@code defaultInstance}.
+ *
+ * @deprecated Use ProtoLiteUtils.marshaller() or Message-based marshaller() instead
+ */
+ @Deprecated
public static <T extends MessageLite> Marshaller<T> marshaller(final T defaultInstance) {
- @SuppressWarnings("unchecked")
- final Parser<T> parser = (Parser<T>) defaultInstance.getParserForType();
- return new Marshaller<T>() {
- @Override
- public InputStream stream(T value) {
- return new ProtoInputStream(value, parser);
- }
-
- @Override
- public T parse(InputStream stream) {
- if (stream instanceof ProtoInputStream) {
- ProtoInputStream protoStream = (ProtoInputStream) stream;
- // Optimization for in-memory transport. Returning provided object is safe since protobufs
- // are immutable.
- //
- // However, we can't assume the types match, so we have to verify the parser matches.
- // Today the parser is always the same for a given proto, but that isn't guaranteed. Even
- // if not, using the same MethodDescriptor would ensure the parser matches and permit us
- // to enable this optimization.
- if (protoStream.parser() == parser) {
- try {
- @SuppressWarnings("unchecked")
- T message = (T) ((ProtoInputStream) stream).message();
- return message;
- } catch (IllegalStateException ex) {
- // Stream must have been read from, which is a strange state. Since the point of this
- // optimization is to be transparent, instead of throwing an error we'll continue,
- // even though it seems likely there's a bug.
- }
- }
- }
- try {
- return parseFrom(stream);
- } catch (InvalidProtocolBufferException ipbe) {
- throw Status.INTERNAL.withDescription("Invalid protobuf byte sequence")
- .withCause(ipbe).asRuntimeException();
- }
- }
-
- private T parseFrom(InputStream stream) throws InvalidProtocolBufferException {
- // Pre-create the CodedInputStream so that we can remove the size limit restriction
- // when parsing.
- CodedInputStream codedInput = CodedInputStream.newInstance(stream);
- codedInput.setSizeLimit(Integer.MAX_VALUE);
+ return ProtoLiteUtils.marshaller(defaultInstance);
+ }
- T message = parser.parseFrom(codedInput);
- try {
- codedInput.checkLastTagWas(0);
- return message;
- } catch (InvalidProtocolBufferException e) {
- e.setUnfinishedMessage(message);
- throw e;
- }
- }
- };
+ /** Create a {@code Marshaller} for protos of the same type as {@code defaultInstance}. */
+ public static <T extends Message> Marshaller<T> marshaller(final T defaultInstance) {
+ return ProtoLiteUtils.marshaller(defaultInstance);
}
/**
@@ -170,27 +124,7 @@ public class ProtoUtils {
public static <T extends Message> Metadata.Key<T> keyForProto(T instance) {
return Metadata.Key.of(
instance.getDescriptorForType().getFullName() + Metadata.BINARY_HEADER_SUFFIX,
- keyMarshaller(instance));
- }
-
- @VisibleForTesting
- static <T extends MessageLite> Metadata.BinaryMarshaller<T> keyMarshaller(final T instance) {
- return new Metadata.BinaryMarshaller<T>() {
- @Override
- public byte[] toBytes(T value) {
- return value.toByteArray();
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public T parseBytes(byte[] serialized) {
- try {
- return (T) instance.getParserForType().parseFrom(serialized);
- } catch (InvalidProtocolBufferException ipbe) {
- throw new IllegalArgumentException(ipbe);
- }
- }
- };
+ ProtoLiteUtils.metadataMarshaller(instance));
}
private ProtoUtils() {
diff --git a/protobuf/src/test/java/io/grpc/protobuf/ProtoUtilsTest.java b/protobuf/src/test/java/io/grpc/protobuf/ProtoUtilsTest.java
index dc9ede460..8281da89c 100644
--- a/protobuf/src/test/java/io/grpc/protobuf/ProtoUtilsTest.java
+++ b/protobuf/src/test/java/io/grpc/protobuf/ProtoUtilsTest.java
@@ -31,166 +31,42 @@
package io.grpc.protobuf;
-import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.fail;
import com.google.common.io.ByteStreams;
-import com.google.protobuf.ByteString;
-import com.google.protobuf.Empty;
-import com.google.protobuf.Enum;
-import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.MessageLite;
import com.google.protobuf.Type;
-import io.grpc.Drainable;
-import io.grpc.Metadata;
import io.grpc.MethodDescriptor.Marshaller;
-import io.grpc.Status;
-import io.grpc.StatusRuntimeException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
import java.io.InputStream;
-import java.util.Arrays;
/** Unit tests for {@link ProtoUtils}. */
@RunWith(JUnit4.class)
public class ProtoUtilsTest {
- private Marshaller<Type> marshaller = ProtoUtils.marshaller(Type.getDefaultInstance());
private Type proto = Type.newBuilder().setName("name").build();
@Test
- public void testPassthrough() {
- assertSame(proto, marshaller.parse(marshaller.stream(proto)));
- }
-
- @Test
public void testRoundtrip() throws Exception {
+ Marshaller<Type> marshaller = ProtoUtils.marshaller(Type.getDefaultInstance());
InputStream is = marshaller.stream(proto);
is = new ByteArrayInputStream(ByteStreams.toByteArray(is));
assertEquals(proto, marshaller.parse(is));
}
@Test
- public void testInvalidatedMessage() throws Exception {
- InputStream is = marshaller.stream(proto);
- // Invalidates message, and drains all bytes
- ByteStreams.toByteArray(is);
- try {
- ((ProtoInputStream) is).message();
- fail("Expected exception");
- } catch (IllegalStateException ex) {
- // expected
- }
- // Zero bytes is the default message
- assertEquals(Type.getDefaultInstance(), marshaller.parse(is));
- }
-
- @Test
- public void parseInvalid() throws Exception {
- InputStream is = new ByteArrayInputStream(new byte[] {-127});
- try {
- marshaller.parse(is);
- fail("Expected exception");
- } catch (StatusRuntimeException ex) {
- assertEquals(Status.Code.INTERNAL, ex.getStatus().getCode());
- assertNotNull(((InvalidProtocolBufferException) ex.getCause()).getUnfinishedMessage());
- }
- }
-
- @Test
- public void testMismatch() throws Exception {
- Marshaller<Enum> enumMarshaller = ProtoUtils.marshaller(Enum.getDefaultInstance());
- // Enum's name and Type's name are both strings with tag 1.
- Enum altProto = Enum.newBuilder().setName(proto.getName()).build();
- assertEquals(proto, marshaller.parse(enumMarshaller.stream(altProto)));
- }
-
- @Test
- public void marshallerShouldNotLimitProtoSize() throws Exception {
- // The default limit is 64MB. Using a larger proto to verify that the limit is not enforced.
- byte[] bigName = new byte[70 * 1024 * 1024];
- Arrays.fill(bigName, (byte) 32);
-
- proto = Type.newBuilder().setNameBytes(ByteString.copyFrom(bigName)).build();
-
- // Just perform a round trip to verify that it works.
- testRoundtrip();
- }
-
- @Test
- public void testAvailable() throws Exception {
+ @Deprecated
+ public void testRoundtripLite() throws Exception {
+ Marshaller<MessageLite> marshaller
+ = ProtoUtils.marshaller((MessageLite) Type.getDefaultInstance());
InputStream is = marshaller.stream(proto);
- assertEquals(proto.getSerializedSize(), is.available());
- is.read();
- assertEquals(proto.getSerializedSize() - 1, is.available());
- while (is.read() != -1) {}
- assertEquals(-1, is.read());
- assertEquals(0, is.available());
- }
-
- @Test
- public void testEmpty() throws IOException {
- Marshaller<Empty> marshaller = ProtoUtils.marshaller(Empty.getDefaultInstance());
- InputStream is = marshaller.stream(Empty.getDefaultInstance());
- assertEquals(0, is.available());
- byte[] b = new byte[10];
- assertEquals(-1, is.read(b));
- assertArrayEquals(new byte[10], b);
- // Do the same thing again, because the internal state may be different
- assertEquals(-1, is.read(b));
- assertArrayEquals(new byte[10], b);
- assertEquals(-1, is.read());
- assertEquals(0, is.available());
- }
-
- @Test
- public void testDrainTo_all() throws Exception {
- byte[] golden = ByteStreams.toByteArray(marshaller.stream(proto));
- InputStream is = marshaller.stream(proto);
- Drainable d = (Drainable) is;
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- int drained = d.drainTo(baos);
- assertEquals(baos.size(), drained);
- assertArrayEquals(golden, baos.toByteArray());
- assertEquals(0, is.available());
- }
-
- @Test
- public void testDrainTo_partial() throws Exception {
- final byte[] golden;
- {
- InputStream is = marshaller.stream(proto);
- is.read();
- golden = ByteStreams.toByteArray(is);
- }
- InputStream is = marshaller.stream(proto);
- is.read();
- Drainable d = (Drainable) is;
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- int drained = d.drainTo(baos);
- assertEquals(baos.size(), drained);
- assertArrayEquals(golden, baos.toByteArray());
- assertEquals(0, is.available());
- }
-
- @Test
- public void testDrainTo_none() throws Exception {
- byte[] golden = ByteStreams.toByteArray(marshaller.stream(proto));
- InputStream is = marshaller.stream(proto);
- ByteStreams.toByteArray(is);
- Drainable d = (Drainable) is;
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- assertEquals(0, d.drainTo(baos));
- assertArrayEquals(new byte[0], baos.toByteArray());
- assertEquals(0, is.available());
+ is = new ByteArrayInputStream(ByteStreams.toByteArray(is));
+ assertEquals(proto, marshaller.parse(is));
}
@Test
@@ -198,25 +74,4 @@ public class ProtoUtilsTest {
assertEquals("google.protobuf.Type-bin",
ProtoUtils.keyForProto(Type.getDefaultInstance()).originalName());
}
-
- @Test
- public void keyMarshaller_roundtrip() {
- Metadata.BinaryMarshaller<Type> keyMarshaller =
- ProtoUtils.keyMarshaller(Type.getDefaultInstance());
- assertEquals(proto, keyMarshaller.parseBytes(keyMarshaller.toBytes(proto)));
- }
-
- @Test
- public void keyMarshaller_invalid() {
- Metadata.BinaryMarshaller<Type> keyMarshaller =
- ProtoUtils.keyMarshaller(Type.getDefaultInstance());
- try {
- keyMarshaller.parseBytes(new byte[] {-127});
- fail("Expected exception");
- } catch (IllegalArgumentException ex) {
- assertNotNull(((InvalidProtocolBufferException) ex.getCause()).getUnfinishedMessage());
- }
- }
-
-
}
diff --git a/settings.gradle b/settings.gradle
index f235a3351..9bed7a107 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -4,6 +4,7 @@ include ":grpc-stub"
include ":grpc-auth"
include ":grpc-okhttp"
include ":grpc-protobuf"
+include ":grpc-protobuf-lite"
include ":grpc-protobuf-nano"
include ":grpc-netty"
include ":grpc-grpclb"
@@ -18,6 +19,7 @@ project(':grpc-stub').projectDir = "$rootDir/stub" as File
project(':grpc-auth').projectDir = "$rootDir/auth" as File
project(':grpc-okhttp').projectDir = "$rootDir/okhttp" as File
project(':grpc-protobuf').projectDir = "$rootDir/protobuf" as File
+project(':grpc-protobuf-lite').projectDir = "$rootDir/protobuf-lite" as File
project(':grpc-protobuf-nano').projectDir = "$rootDir/protobuf-nano" as File
project(':grpc-netty').projectDir = "$rootDir/netty" as File
project(':grpc-grpclb').projectDir = "$rootDir/grpclb" as File