From 8378711fd0efb558c33035c0875d6d64cc81a89c Mon Sep 17 00:00:00 2001 From: Daniel Tang Date: Fri, 16 Feb 2018 16:08:39 -0800 Subject: [PATCH] fix array path parameter deserialization This change fixes path parameter deserialization when the parameter is an array-like structure. Previously, this only worked for query parameters, and a string literal was injected as an array for path parameters. --- .../RestServletRequestParamReader.java | 16 ++++++++-- .../RestServletRequestParamReaderTest.java | 32 ++++++++++++++++--- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/request/RestServletRequestParamReader.java b/endpoints-framework/src/main/java/com/google/api/server/spi/request/RestServletRequestParamReader.java index 62fcdbbb..43560d09 100644 --- a/endpoints-framework/src/main/java/com/google/api/server/spi/request/RestServletRequestParamReader.java +++ b/endpoints-framework/src/main/java/com/google/api/server/spi/request/RestServletRequestParamReader.java @@ -23,6 +23,7 @@ import com.google.api.server.spi.config.model.ApiParameterConfig; import com.google.api.server.spi.config.model.ApiSerializationConfig; import com.google.api.server.spi.response.BadRequestException; +import com.google.common.base.Splitter; import com.google.common.collect.ImmutableMap; import com.fasterxml.jackson.databind.JsonNode; @@ -31,6 +32,7 @@ import java.io.IOException; import java.lang.reflect.InvocationTargetException; +import java.util.Collection; import java.util.Enumeration; import java.util.List; import java.util.Map; @@ -48,8 +50,10 @@ * by stuffing path and query parameters into the main request body. */ public class RestServletRequestParamReader extends ServletRequestParamReader { + private static final Logger logger = Logger .getLogger(RestServletRequestParamReader.class.getName()); + private static final Splitter COMPOSITE_PATH_SPLITTER = Splitter.on(','); private final Map rawPathParameters; private final Map parameterConfigMap; @@ -99,11 +103,10 @@ public Object[] read() throws ServiceException { Class parameterClass = parameterMap.get(parameterName); ApiParameterConfig parameterConfig = parameterConfigMap.get(parameterName); if (parameterClass != null && parameterConfig.isRepeated()) { - ArrayNode values = (ArrayNode) objectReader.createArrayNode(); + ArrayNode values = body.putArray(parameterName); for (String value : servletRequest.getParameterValues(parameterName)) { values.add(value); } - body.set(parameterName, values); } else { body.put(parameterName, servletRequest.getParameterValues(parameterName)[0]); } @@ -113,7 +116,14 @@ public Object[] read() throws ServiceException { String parameterName = entry.getKey(); Class parameterClass = parameterMap.get(parameterName); if (parameterClass != null && !body.has(parameterName)) { - body.put(parameterName, entry.getValue()); + if (parameterConfigMap.get(parameterName).isRepeated()) { + ArrayNode values = body.putArray(parameterName); + for (String value : COMPOSITE_PATH_SPLITTER.split(entry.getValue())) { + values.add(value); + } + } else { + body.put(parameterName, entry.getValue()); + } } } for (Entry entry : parameterConfigMap.entrySet()) { diff --git a/endpoints-framework/src/test/java/com/google/api/server/spi/request/RestServletRequestParamReaderTest.java b/endpoints-framework/src/test/java/com/google/api/server/spi/request/RestServletRequestParamReaderTest.java index 15023dac..165418da 100644 --- a/endpoints-framework/src/test/java/com/google/api/server/spi/request/RestServletRequestParamReaderTest.java +++ b/endpoints-framework/src/test/java/com/google/api/server/spi/request/RestServletRequestParamReaderTest.java @@ -35,6 +35,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import java.util.ArrayList; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -61,6 +62,7 @@ public class RestServletRequestParamReaderTest { private EndpointMethod endpointMethod; private MockHttpServletRequest request; private ApiSerializationConfig serializationConfig; + private ApiConfig apiConfig; private ApiMethodConfig methodConfig; @Before @@ -72,13 +74,12 @@ public void setUp() throws Exception { ServiceContext serviceContext = ServiceContext.create(); serializationConfig = new ApiSerializationConfig(); TypeLoader typeLoader = new TypeLoader(); - ApiConfig config = (new ApiConfig.Factory()).create(serviceContext, typeLoader, - TestApi.class); + apiConfig = new ApiConfig.Factory().create(serviceContext, typeLoader, TestApi.class); ApiConfigAnnotationReader annotationReader = new ApiConfigAnnotationReader(); - annotationReader.loadEndpointClass(serviceContext, TestApi.class, config); + annotationReader.loadEndpointClass(serviceContext, TestApi.class, apiConfig); annotationReader.loadEndpointMethods(serviceContext, TestApi.class, - config.getApiClassConfig().getMethods()); - methodConfig = config.getApiClassConfig().getMethods().get(endpointMethod); + apiConfig.getApiClassConfig().getMethods()); + methodConfig = apiConfig.getApiClassConfig().getMethods().get(endpointMethod); } @Test @@ -186,6 +187,20 @@ public void gzippedRequest() throws Exception { .inOrder(); } + @Test + public void arrayPathParam() throws Exception { + endpointMethod = EndpointMethod.create(TestApi.class, + TestApi.class.getMethod("testArrayPathParam", ArrayList.class)); + methodConfig = apiConfig.getApiClassConfig().getMethods().get(endpointMethod); + RestServletRequestParamReader reader = createReader(ImmutableMap.of("values", "4,3,2,1")); + + Object[] params = reader.read(); + + assertThat(params).hasLength(endpointMethod.getParameterClasses().length); + assertThat(params).asList() + .containsExactly(ImmutableList.of("4", "3", "2", "1")); + } + private RestServletRequestParamReader createReader(Map rawPathParameters) { return new RestServletRequestParamReader(endpointMethod, request, null, serializationConfig, methodConfig, rawPathParameters); @@ -213,6 +228,13 @@ public void test(@Named("path") long path, @Named("dates") List date @Named("defaultvalue") @DefaultValue("2015-01-01") SimpleDate defaultValue, TestResource resource) { } + + @ApiMethod( + name = "testArrayPathParam", + httpMethod = HttpMethod.GET, + path = "testArrayPathParam/{values}") + public void testArrayPathParam(@Named("values") ArrayList values) { + } } private static byte[] compress(byte[] bytes) {