From 2f020e92e2bc863511c81b0dd5a0e7eec63ca825 Mon Sep 17 00:00:00 2001 From: Edwin Kempin Date: Fri, 8 Jun 2018 15:01:31 +0200 Subject: [PATCH] Allow empty request body for POST/PUT/DELETE REST endpoints that expect List/Map as input If a REST endpoint expects a List or a Map as input, but the user provides an empty request body we currently fail with 500 Internal Server Error, e.g.: POST /accounts//watched.projects Instead just create an empty List/Map and provide it to the REST endpoint. This is consistent with instantiating empty Input objects when the REST endpoint expects a non-generic input type and the user provides no body. Change-Id: I78fe66b2d0f63a6078411dd50a55196424d88490 Signed-off-by: Edwin Kempin --- .../google/gerrit/httpd/restapi/RestApiServlet.java | 11 ++++++++++- .../acceptance/rest/account/WatchedProjectsIT.java | 5 +++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java index 4c9a03508f..8b770f996e 100644 --- a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java +++ b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java @@ -846,16 +846,25 @@ public class RestApiServlet extends HttpServlet { throw new BadRequestException("Expected JSON object"); } + @SuppressWarnings("unchecked") private static Object createInstance(Type type) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { if (type instanceof Class) { - @SuppressWarnings("unchecked") Class clazz = (Class) type; Constructor c = clazz.getDeclaredConstructor(); c.setAccessible(true); return c.newInstance(); } + if (type instanceof ParameterizedType) { + Type rawType = ((ParameterizedType) type).getRawType(); + if (rawType instanceof Class && List.class.isAssignableFrom((Class) rawType)) { + return new ArrayList<>(); + } + if (rawType instanceof Class && Map.class.isAssignableFrom((Class) rawType)) { + return new HashMap<>(); + } + } throw new InstantiationException("Cannot make " + type); } diff --git a/javatests/com/google/gerrit/acceptance/rest/account/WatchedProjectsIT.java b/javatests/com/google/gerrit/acceptance/rest/account/WatchedProjectsIT.java index 9edafb8b6a..bc84593a9f 100644 --- a/javatests/com/google/gerrit/acceptance/rest/account/WatchedProjectsIT.java +++ b/javatests/com/google/gerrit/acceptance/rest/account/WatchedProjectsIT.java @@ -235,4 +235,9 @@ public class WatchedProjectsIT extends AbstractDaemonTest { assertThat(persistedWatchedProjects).doesNotContain(pwi); assertThat(persistedWatchedProjects).containsAllIn(projectsToWatch); } + + @Test + public void postWithoutBody() throws Exception { + adminRestSession.post("/accounts/" + admin.username + "/watched.projects").assertOK(); + } }