Skip to content

Commit

Permalink
Added support for repeated field query params
Browse files Browse the repository at this point in the history
  • Loading branch information
feso authored and Xorlev committed Dec 10, 2017
1 parent 4fa8eaa commit f66c17b
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -206,6 +286,4 @@ public void testPost__nestedBindingYaml() throws Exception {

assertThat(response.getRequest().getNt()).isEqualTo(request);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

/**
Expand Down Expand Up @@ -46,7 +47,7 @@ public static <V extends Message> 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));
}
}
}
Expand All @@ -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<String> value)
throws InvalidProtocolBufferException {
Descriptors.Descriptor descriptor = builder.getDescriptorForType();

ImmutableList<Descriptors.FieldDescriptor> fieldDescriptors =
Expand All @@ -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<String> value)
throws InvalidProtocolBufferException {
Object valueToSet = getValueFor(fd, value);
builder.setField(fd, valueToSet);
}

private static Object getValueFor(FieldDescriptor fd, List<String> 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<Object> 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 <V extends Message> void handleBody(
String fieldPath,
V.Builder builder,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand All @@ -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
Expand All @@ -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();
Expand Down
2 changes: 2 additions & 0 deletions protos/test.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit f66c17b

Please sign in to comment.