aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anderson <ejona@google.com>2016-08-30 08:55:04 -0700
committerEric Anderson <ejona@google.com>2016-09-08 11:05:16 -0700
commitbdf8b0112928f3bb8b72627dbd46235dc22dbb73 (patch)
tree8796f77e6bd671fe05159226cc25111980332fce
parentf78644d7620771536428b3bc4c6471a8cba66ca1 (diff)
downloadgrpc-grpc-java-bdf8b0112928f3bb8b72627dbd46235dc22dbb73.tar.gz
core,protobuf: Add simple argument introspection for methods
The cast required in protobuf makes me question how much I like ReflectableMarshaller, but it seems to be pretty sound and the cast is more an artifact of generics than the API. Nano and Thrift were purposefully not updated, since getting just the class requires making a new message instance. That seems a bit lame. It probably is no burden to create an instance to get the class, and it may not be too hard to improve the factory to provide class information, but didn't want to bother at this point. Especially since nano users are unlikely to need the introspection functionality.
-rw-r--r--core/src/main/java/io/grpc/MethodDescriptor.java42
-rw-r--r--protobuf-lite/src/main/java/io/grpc/protobuf/lite/ProtoLiteUtils.java16
-rw-r--r--protobuf-lite/src/test/java/io/grpc/protobuf/lite/ProtoLiteUtilsTest.java9
3 files changed, 66 insertions, 1 deletions
diff --git a/core/src/main/java/io/grpc/MethodDescriptor.java b/core/src/main/java/io/grpc/MethodDescriptor.java
index b1c1d63eb..906f130f0 100644
--- a/core/src/main/java/io/grpc/MethodDescriptor.java
+++ b/core/src/main/java/io/grpc/MethodDescriptor.java
@@ -147,6 +147,34 @@ public class MethodDescriptor<ReqT, RespT> {
public T parse(InputStream stream);
}
+ /** A marshaller that supports retrieving it's type parameter {@code T} at runtime. */
+ @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2222")
+ public interface ReflectableMarshaller<T> extends Marshaller<T> {
+ /**
+ * Returns the {@code Class} that this marshaller serializes and deserializes. If inheritance is
+ * allowed, this is the base class or interface for all supported classes.
+ *
+ * @return non-{@code null} base class for all objects produced and consumed by this marshaller
+ */
+ public Class<T> getMessageClass();
+ }
+
+ /** A marshaller that uses a fixed instance of the type it produces. */
+ @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2222")
+ public interface PrototypeMarshaller<T> extends ReflectableMarshaller<T> {
+ /**
+ * An instance of the expected message type, typically used as a schema and helper for producing
+ * other message instances. The {@code null} value may be a special value for the marshaller
+ * (like the equivalent of {@link Void}), so it is a valid return value. {@code null} does
+ * <em>not</em> mean "unsupported" or "unknown".
+ *
+ * <p>It is generally expected this would return the same instance each invocation, but it is
+ * not a requirement.
+ */
+ @Nullable
+ public T getMessagePrototype();
+ }
+
/**
* Creates a new {@code MethodDescriptor}.
*
@@ -231,6 +259,20 @@ public class MethodDescriptor<ReqT, RespT> {
}
/**
+ * Returns the marshaller for the request type. Allows introspection of the request marshaller.
+ */
+ public Marshaller<ReqT> getRequestMarshaller() {
+ return requestMarshaller;
+ }
+
+ /**
+ * Returns the marshaller for the response type. Allows introspection of the response marshaller.
+ */
+ public Marshaller<RespT> getResponseMarshaller() {
+ return responseMarshaller;
+ }
+
+ /**
* Returns whether this method is idempotent.
*/
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1775")
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
index a66f57b5a..9742a7672 100644
--- a/protobuf-lite/src/main/java/io/grpc/protobuf/lite/ProtoLiteUtils.java
+++ b/protobuf-lite/src/main/java/io/grpc/protobuf/lite/ProtoLiteUtils.java
@@ -43,6 +43,7 @@ import io.grpc.ExperimentalApi;
import io.grpc.KnownLength;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor.Marshaller;
+import io.grpc.MethodDescriptor.PrototypeMarshaller;
import io.grpc.Status;
import io.grpc.internal.GrpcUtil;
@@ -81,7 +82,20 @@ public class ProtoLiteUtils {
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>() {
+ // TODO(ejona): consider changing return type to PrototypeMarshaller (assuming ABI safe)
+ return new PrototypeMarshaller<T>() {
+ @SuppressWarnings("unchecked")
+ @Override
+ public Class<T> getMessageClass() {
+ // Precisely T since protobuf doesn't let messages extend other messages.
+ return (Class<T>) defaultInstance.getClass();
+ }
+
+ @Override
+ public T getMessagePrototype() {
+ return defaultInstance;
+ }
+
@Override
public InputStream stream(T value) {
return new ProtoInputStream(value, parser);
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
index 53809deeb..612300006 100644
--- a/protobuf-lite/src/test/java/io/grpc/protobuf/lite/ProtoLiteUtilsTest.java
+++ b/protobuf-lite/src/test/java/io/grpc/protobuf/lite/ProtoLiteUtilsTest.java
@@ -47,6 +47,7 @@ import com.google.protobuf.Type;
import io.grpc.Drainable;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor.Marshaller;
+import io.grpc.MethodDescriptor.PrototypeMarshaller;
import io.grpc.Status;
import io.grpc.StatusRuntimeException;
@@ -119,6 +120,14 @@ public class ProtoLiteUtilsTest {
}
@Test
+ public void introspection() throws Exception {
+ Marshaller<Enum> enumMarshaller = ProtoLiteUtils.marshaller(Enum.getDefaultInstance());
+ PrototypeMarshaller<Enum> prototypeMarshaller = (PrototypeMarshaller<Enum>) enumMarshaller;
+ assertSame(Enum.getDefaultInstance(), prototypeMarshaller.getMessagePrototype());
+ assertSame(Enum.class, prototypeMarshaller.getMessageClass());
+ }
+
+ @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];