diff --git a/integration-test-base/src/test/java/com/fullcontact/rpc/jersey/IntegrationBase.java b/integration-test-base/src/test/java/com/fullcontact/rpc/jersey/IntegrationBase.java index f30e4e4..a47ef00 100644 --- a/integration-test-base/src/test/java/com/fullcontact/rpc/jersey/IntegrationBase.java +++ b/integration-test-base/src/test/java/com/fullcontact/rpc/jersey/IntegrationBase.java @@ -4,7 +4,7 @@ import com.fullcontact.rpc.TestEnum; import com.fullcontact.rpc.TestRequest; import com.fullcontact.rpc.TestResponse; - +import com.google.common.collect.ImmutableList; import com.google.protobuf.util.JsonFormat; import io.dropwizard.testing.junit.ResourceTestRule; import org.junit.Test; @@ -42,6 +42,86 @@ public void testBasicGet() throws Exception { assertThat(response.getRequest().getNt().getF1()).isEqualTo("abcd"); } + @Test + public void testBasicGetWith1RepeatedIntParam() throws Exception { + // /users/{s}/{uint3}/{nt.f1}?rep=1&rep=2&rep=3 + String responseJson = resources().getJerseyTest() + .target("/users/string1/1234/abcd") + .queryParam("rep", 1) + .request() + .buildGet() + .invoke(String.class); + + TestResponse.Builder responseFromJson = TestResponse.newBuilder(); + JsonFormat.parser().merge(responseJson, responseFromJson); + TestResponse response = responseFromJson.build(); + + assertThat(response.getRequest().getS()).isEqualTo("string1"); + assertThat(response.getRequest().getUint3()).isEqualTo(1234); + assertThat(response.getRequest().getNt().getF1()).isEqualTo("abcd"); + assertThat(response.getRequest().getRepList()).isEqualTo(ImmutableList.of(1)); + } + + @Test + public void testBasicGetWithRepeatedIntParam() throws Exception { + // /users/{s}/{uint3}/{nt.f1}?rep=1&rep=2&rep=3 + String responseJson = resources().getJerseyTest() + .target("/users/string1/1234/abcd") + .queryParam("rep", 1, 2, 3) + .request() + .buildGet() + .invoke(String.class); + + TestResponse.Builder responseFromJson = TestResponse.newBuilder(); + JsonFormat.parser().merge(responseJson, responseFromJson); + TestResponse response = responseFromJson.build(); + + assertThat(response.getRequest().getS()).isEqualTo("string1"); + assertThat(response.getRequest().getUint3()).isEqualTo(1234); + assertThat(response.getRequest().getNt().getF1()).isEqualTo("abcd"); + assertThat(response.getRequest().getRepList()).isEqualTo(ImmutableList.of(1, 2, 3)); + } + + @Test + public void testBasicGetWithRepeatedStrParam() throws Exception { + // /users/{s}/{uint3}/{nt.f1}?repStr=a&repStr=b&repStr=c + String responseJson = resources().getJerseyTest() + .target("/users/string1/1234/abcd") + .queryParam("rep_str", "a", "b", "c") + .request() + .buildGet() + .invoke(String.class); + + TestResponse.Builder responseFromJson = TestResponse.newBuilder(); + JsonFormat.parser().merge(responseJson, responseFromJson); + TestResponse response = responseFromJson.build(); + + assertThat(response.getRequest().getS()).isEqualTo("string1"); + assertThat(response.getRequest().getUint3()).isEqualTo(1234); + assertThat(response.getRequest().getNt().getF1()).isEqualTo("abcd"); + assertThat(response.getRequest().getRepStrList()).isEqualTo(ImmutableList.of("a", "b", "c")); + } + + @Test + public void testBasicGetWithRepeatedEmptyStrParam() throws Exception { + // /users/{s}/{uint3}/{nt.f1}?repStr=a&repStr=&repStr=b&repStr= + String responseJson = resources().getJerseyTest() + .target("/users/string1/1234/abcd") + .queryParam("rep_str", "a", "", "b", "") + .request() + .buildGet() + .invoke(String.class); + + TestResponse.Builder responseFromJson = TestResponse.newBuilder(); + JsonFormat.parser().merge(responseJson, responseFromJson); + TestResponse response = responseFromJson.build(); + + assertThat(response.getRequest().getS()).isEqualTo("string1"); + assertThat(response.getRequest().getUint3()).isEqualTo(1234); + assertThat(response.getRequest().getNt().getF1()).isEqualTo("abcd"); + assertThat(response.getRequest().getRepStrList()).isEqualTo(ImmutableList.of("a", "", "b", "")); + } + @Test public void testBasicPost() throws Exception { TestRequest request = TestRequest.newBuilder() @@ -206,6 +286,4 @@ public void testPost__nestedBindingYaml() throws Exception { assertThat(response.getRequest().getNt()).isEqualTo(request); } - - } diff --git a/jersey-rpc-support/src/main/java/com/fullcontact/rpc/jersey/RequestParser.java b/jersey-rpc-support/src/main/java/com/fullcontact/rpc/jersey/RequestParser.java index 7c7ef9b..e11bc7e 100644 --- a/jersey-rpc-support/src/main/java/com/fullcontact/rpc/jersey/RequestParser.java +++ b/jersey-rpc-support/src/main/java/com/fullcontact/rpc/jersey/RequestParser.java @@ -7,6 +7,7 @@ import com.google.common.collect.Sets; import com.google.protobuf.DescriptorProtos; import com.google.protobuf.Descriptors; +import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; import com.google.protobuf.UnsafeByteOperations; @@ -17,8 +18,8 @@ import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.UriInfo; +import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.Set; /** @@ -46,7 +47,7 @@ public static void parseQueryParams(UriInfo uriInfo, Descriptors.FieldDescriptor field = Iterables.getLast(descriptors); if(!pathDescriptors.contains(field.toProto())) { - setFieldSafely(builder, queryParam, uriInfo.getQueryParameters().getFirst(queryParam)); + setFieldSafely(builder, queryParam, uriInfo.getQueryParameters().get(queryParam)); } } } @@ -67,6 +68,11 @@ public static Metadata parseHeaders(HttpHeaders headers){ public static void setFieldSafely(Message.Builder builder, String path, String value) throws InvalidProtocolBufferException { + setFieldSafely(builder, path, ImmutableList.of(value)); + } + + public static void setFieldSafely(Message.Builder builder, String path, List value) + throws InvalidProtocolBufferException { Descriptors.Descriptor descriptor = builder.getDescriptorForType(); ImmutableList fieldDescriptors = @@ -86,60 +92,73 @@ public static void setFieldSafely(Message.Builder builder, String path, String v setFieldSafely(fieldBuilder, fieldDescriptors.get(fieldDescriptors.size()-1), value); } - public static void setFieldSafely(Message.Builder builder, Descriptors.FieldDescriptor fd, String value) + public static void setFieldSafely(Message.Builder builder, Descriptors.FieldDescriptor fd, List value) throws InvalidProtocolBufferException { + Object valueToSet = getValueFor(fd, value); + builder.setField(fd, valueToSet); + } + + private static Object getValueFor(FieldDescriptor fd, List value) throws InvalidProtocolBufferException { + Object result; + if (!fd.isRepeated()) { + if (value.size() != 1) { + throw new InvalidProtocolBufferException("Unable to map " + fd + " to value: " + value); + } + result = getUnaryValueFor(fd, value.get(0)); + } else { + List listResult = new ArrayList<>(value.size()); + for (String valueStr : value) { + listResult.add(getUnaryValueFor(fd, valueStr)); + } + result = listResult; + } + return result; + } + + private static Object getUnaryValueFor(Descriptors.FieldDescriptor fd, String value) throws InvalidProtocolBufferException { try { switch(fd.getType()) { case DOUBLE: - builder.setField(fd, Double.parseDouble(value)); - break; + return Double.parseDouble(value); case FLOAT: - builder.setField(fd, Float.parseFloat(value)); - break; + return Float.parseFloat(value); case BOOL: - builder.setField(fd, Boolean.parseBoolean(value)); - break; + return Boolean.parseBoolean(value); case STRING: - builder.setField(fd, value); - break; - case GROUP: - // unsupported - break; - case MESSAGE: - // unsupported - break; + return value; case BYTES: - builder.setField(fd, UnsafeByteOperations.unsafeWrap(value.getBytes())); - break; + return UnsafeByteOperations.unsafeWrap(value.getBytes()); case ENUM: Descriptors.EnumValueDescriptor enumValueDescriptor = fd.getEnumType().findValueByName(value.toUpperCase()); - builder.setField(fd, enumValueDescriptor); // TODO eh? - break; + return enumValueDescriptor; // TODO eh? case INT32: - builder.setField(fd, Integer.parseInt(value)); - break; + return Integer.parseInt(value); case UINT32: case FIXED32: case SFIXED32: case SINT32: - builder.setField(fd, Integer.parseUnsignedInt(value)); - break; + return Integer.parseUnsignedInt(value); case INT64: - builder.setField(fd, Long.parseLong(value)); - break; + return Long.parseLong(value); case UINT64: case FIXED64: case SFIXED64: case SINT64: - builder.setField(fd, Long.parseUnsignedLong(value)); + return Long.parseUnsignedLong(value); // all are unsigned 64-bit ints + case GROUP: + // unsupported + case MESSAGE: + // unsupported + default: + throw new InvalidProtocolBufferException("Unable to map " + fd + " to value: " + value); } } catch(NumberFormatException e) { throw new InvalidProtocolBufferException("Unable to map " + fd + " to value: " + value); } } - + public static void handleBody( String fieldPath, V.Builder builder, diff --git a/jersey-rpc-support/src/test/java/com/fullcontact/rpc/jersey/RequestParserTest.java b/jersey-rpc-support/src/test/java/com/fullcontact/rpc/jersey/RequestParserTest.java index de245c9..c256823 100644 --- a/jersey-rpc-support/src/test/java/com/fullcontact/rpc/jersey/RequestParserTest.java +++ b/jersey-rpc-support/src/test/java/com/fullcontact/rpc/jersey/RequestParserTest.java @@ -5,6 +5,7 @@ import com.fullcontact.rpc.TestEnum; import com.fullcontact.rpc.TestRequest; +import com.google.common.collect.ImmutableList; import com.google.protobuf.ByteString; import com.google.protobuf.util.JsonFormat; import io.grpc.Metadata; @@ -36,7 +37,11 @@ public void parseQueryParams() throws Exception { .put("int6", "9000000000000000000") .put("f", "123.456") .put("d", "123.456") - .put("enu", "SECOND"); + .put("enu", "SECOND") + .put("rep", "1") + .put("rep", "2") + .put("rep_str", "a") + .put("rep_str", ""); RequestParser.parseQueryParams(uriInfoMap, request); @@ -53,6 +58,8 @@ public void parseQueryParams() throws Exception { assertThat(r.getF()).isEqualTo(123.456f); assertThat(r.getD()).isEqualTo(123.456d); assertThat(r.getEnu()).isEqualTo(TestEnum.SECOND); + assertThat(r.getRepList()).isEqualTo(ImmutableList.of(1, 2)); + assertThat(r.getRepStrList()).isEqualTo(ImmutableList.of("a", "")); } @Test @@ -77,6 +84,22 @@ public void setFieldSafely() throws Exception { assertThat(request.build().getNt().getF1()).isEqualTo("abc"); } + @Test + public void testSetRepeatedIntField() throws Exception { + TestRequest.Builder request = TestRequest.newBuilder(); + RequestParser.setFieldSafely(request, "rep", ImmutableList.of("1", "2", "3")); + + assertThat(request.build().getRepList()).isEqualTo(ImmutableList.of(1, 2, 3)); + } + + @Test + public void testSetRepeatedStringField() throws Exception { + TestRequest.Builder request = TestRequest.newBuilder(); + RequestParser.setFieldSafely(request, "rep_str", ImmutableList.of("a", "")); + + assertThat(request.build().getRepStrList()).isEqualTo(ImmutableList.of("a", "")); + } + @Test public void handleBody() throws Exception { TestRequest.Builder request = TestRequest.newBuilder(); diff --git a/protos/test.proto b/protos/test.proto index 6ef018b..73a81aa 100644 --- a/protos/test.proto +++ b/protos/test.proto @@ -55,6 +55,8 @@ message TestRequest { double d = 9; TestEnum enu = 10; NestedType nt = 11; + repeated uint32 rep = 12; + repeated string rep_str = 13; } message TestResponse { TestRequest request = 1;