Prefer subtypes of Multimap
Guava team recommends using the subinterfaces of Multimap, for the same reasons they recommend using Set and List rather than Collection: it documents expectations about ordering, uniqueness, and behavior of equals. Do this across the board in Gerrit. Mostly this is straightforward and I tried to exactly match existing behavior where possible. However, there were a few wrinkles, where different callers passed different subtypes to the same method. The main one is arguments to ParameterParser#parse and splitQueryString, where some callers used SetMultimaps (perhaps semi-intentionally, or perhaps misunderstanding the nature of HashMultimap). For the purposes of parameter parsing, a ListMultimap makes more sense, because it preserves argument order and repetition. Another instance is a couple places in ReceiveCommits and downstream where there were SetMultimap<?, Ref>. Since Refs do not implement equals, this is effectively the same thing as a ListMultimap, and changing the interface no longer misleads readers into thinking there might be some deduplication happening. Finally, this change includes a breaking API change to the return type of ExternalIncludedIn#getIncludedIn. Change-Id: I5f1d15e27a32e534a6aaefe204e7a31815f4c8d7
This commit is contained in:

committed by
David Pursehouse

parent
e5c5953205
commit
484da493b3
@@ -17,7 +17,7 @@ package com.google.gerrit.httpd.plugins;
|
||||
import static com.google.gerrit.server.plugins.AutoRegisterUtil.calculateBindAnnotation;
|
||||
|
||||
import com.google.common.collect.LinkedListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.gerrit.extensions.annotations.Export;
|
||||
import com.google.gerrit.server.plugins.InvalidPluginException;
|
||||
import com.google.gerrit.server.plugins.ModuleGenerator;
|
||||
@@ -35,7 +35,8 @@ import javax.servlet.http.HttpServlet;
|
||||
class HttpAutoRegisterModuleGenerator extends ServletModule
|
||||
implements ModuleGenerator {
|
||||
private final Map<String, Class<HttpServlet>> serve = new HashMap<>();
|
||||
private final Multimap<TypeLiteral<?>, Class<?>> listeners = LinkedListMultimap.create();
|
||||
private final ListMultimap<TypeLiteral<?>, Class<?>> listeners =
|
||||
LinkedListMultimap.create();
|
||||
|
||||
@Override
|
||||
protected void configureServlets() {
|
||||
|
@@ -23,7 +23,7 @@ import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||
import com.google.gerrit.extensions.restapi.BinaryResult;
|
||||
import com.google.gerrit.extensions.restapi.Url;
|
||||
@@ -59,7 +59,7 @@ class ParameterParser {
|
||||
}
|
||||
|
||||
<T> boolean parse(T param,
|
||||
Multimap<String, String> in,
|
||||
ListMultimap<String, String> in,
|
||||
HttpServletRequest req,
|
||||
HttpServletResponse res)
|
||||
throws IOException {
|
||||
@@ -90,8 +90,8 @@ class ParameterParser {
|
||||
}
|
||||
|
||||
static void splitQueryString(String queryString,
|
||||
Multimap<String, String> config,
|
||||
Multimap<String, String> params) {
|
||||
ListMultimap<String, String> config,
|
||||
ListMultimap<String, String> params) {
|
||||
if (!Strings.isNullOrEmpty(queryString)) {
|
||||
for (String kvPair : Splitter.on('&').split(queryString)) {
|
||||
Iterator<String> i = Splitter.on('=').limit(2).split(kvPair).iterator();
|
||||
|
@@ -45,13 +45,13 @@ import com.google.common.base.CharMatcher;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import com.google.common.io.CountingOutputStream;
|
||||
import com.google.common.math.IntMath;
|
||||
@@ -245,8 +245,8 @@ public class RestApiServlet extends HttpServlet {
|
||||
int status = SC_OK;
|
||||
long responseBytes = -1;
|
||||
Object result = null;
|
||||
Multimap<String, String> params = LinkedHashMultimap.create();
|
||||
Multimap<String, String> config = LinkedHashMultimap.create();
|
||||
ListMultimap<String, String> params = ArrayListMultimap.create();
|
||||
ListMultimap<String, String> config = ArrayListMultimap.create();
|
||||
Object inputRequestBody = null;
|
||||
RestResource rsrc = TopLevelResource.INSTANCE;
|
||||
ViewData viewData = null;
|
||||
@@ -460,9 +460,9 @@ public class RestApiServlet extends HttpServlet {
|
||||
metric,
|
||||
System.nanoTime() - startNanos,
|
||||
TimeUnit.NANOSECONDS);
|
||||
globals.auditService.dispatch(new ExtendedHttpAuditEvent(globals.webSession.get()
|
||||
.getSessionId(), globals.currentUser.get(), req,
|
||||
auditStartTs, params, inputRequestBody, status,
|
||||
globals.auditService.dispatch(new ExtendedHttpAuditEvent(
|
||||
globals.webSession.get().getSessionId(), globals.currentUser.get(),
|
||||
req, auditStartTs, params, inputRequestBody, status,
|
||||
result, rsrc, viewData == null ? null : viewData.view));
|
||||
}
|
||||
}
|
||||
@@ -777,7 +777,7 @@ public class RestApiServlet extends HttpServlet {
|
||||
|
||||
public static long replyJson(@Nullable HttpServletRequest req,
|
||||
HttpServletResponse res,
|
||||
Multimap<String, String> config,
|
||||
ListMultimap<String, String> config,
|
||||
Object result)
|
||||
throws IOException {
|
||||
TemporaryBuffer.Heap buf = heap(HEAP_EST_SIZE, Integer.MAX_VALUE);
|
||||
@@ -796,7 +796,7 @@ public class RestApiServlet extends HttpServlet {
|
||||
.setCharacterEncoding(UTF_8));
|
||||
}
|
||||
|
||||
private static Gson newGson(Multimap<String, String> config,
|
||||
private static Gson newGson(ListMultimap<String, String> config,
|
||||
@Nullable HttpServletRequest req) {
|
||||
GsonBuilder gb = OutputFormat.JSON_COMPACT.newGsonBuilder();
|
||||
|
||||
@@ -807,7 +807,7 @@ public class RestApiServlet extends HttpServlet {
|
||||
}
|
||||
|
||||
private static void enablePrettyPrint(GsonBuilder gb,
|
||||
Multimap<String, String> config,
|
||||
ListMultimap<String, String> config,
|
||||
@Nullable HttpServletRequest req) {
|
||||
String pp = Iterables.getFirst(config.get("pp"), null);
|
||||
if (pp == null) {
|
||||
@@ -822,7 +822,7 @@ public class RestApiServlet extends HttpServlet {
|
||||
}
|
||||
|
||||
private static void enablePartialGetFields(GsonBuilder gb,
|
||||
Multimap<String, String> config) {
|
||||
ListMultimap<String, String> config) {
|
||||
final Set<String> want = new HashSet<>();
|
||||
for (String p : config.get("fields")) {
|
||||
Iterables.addAll(want, OptionUtil.splitOptionValue(p));
|
||||
@@ -1130,7 +1130,8 @@ public class RestApiServlet extends HttpServlet {
|
||||
static long replyText(@Nullable HttpServletRequest req,
|
||||
HttpServletResponse res, String text) throws IOException {
|
||||
if ((req == null || isRead(req)) && isMaybeHTML(text)) {
|
||||
return replyJson(req, res, ImmutableMultimap.of("pp", "0"), new JsonPrimitive(text));
|
||||
return replyJson(req, res, ImmutableListMultimap.of("pp", "0"),
|
||||
new JsonPrimitive(text));
|
||||
}
|
||||
if (!text.endsWith("\n")) {
|
||||
text += "\n";
|
||||
|
@@ -15,7 +15,7 @@
|
||||
package com.google.gerrit.httpd.rpc;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.gerrit.audit.AuditService;
|
||||
import com.google.gerrit.audit.RpcAuditEvent;
|
||||
import com.google.gerrit.common.TimeUtil;
|
||||
@@ -133,25 +133,28 @@ final class GerritJsonServlet extends JsonServlet<GerritJsonServlet.GerritCall>
|
||||
}
|
||||
Audit note = method.getAnnotation(Audit.class);
|
||||
if (note != null) {
|
||||
final String sid = call.getWebSession().getSessionId();
|
||||
final CurrentUser username = call.getWebSession().getUser();
|
||||
final Multimap<String, ?> args =
|
||||
extractParams(note, call);
|
||||
final String what = extractWhat(note, call);
|
||||
final Object result = call.getResult();
|
||||
String sid = call.getWebSession().getSessionId();
|
||||
CurrentUser username = call.getWebSession().getUser();
|
||||
ListMultimap<String, ?> args = extractParams(note, call);
|
||||
String what = extractWhat(note, call);
|
||||
Object result = call.getResult();
|
||||
|
||||
audit.dispatch(new RpcAuditEvent(sid, username, what, call.getWhen(),
|
||||
args, call.getHttpServletRequest().getMethod(), call.getHttpServletRequest().getMethod(),
|
||||
((AuditedHttpServletResponse) (call.getHttpServletResponse()))
|
||||
.getStatus(), result));
|
||||
audit.dispatch(
|
||||
new RpcAuditEvent(
|
||||
sid, username, what, call.getWhen(), args,
|
||||
call.getHttpServletRequest().getMethod(),
|
||||
call.getHttpServletRequest().getMethod(),
|
||||
((AuditedHttpServletResponse) (call.getHttpServletResponse()))
|
||||
.getStatus(),
|
||||
result));
|
||||
}
|
||||
} catch (Throwable all) {
|
||||
log.error("Unable to log the call", all);
|
||||
}
|
||||
}
|
||||
|
||||
private Multimap<String, ?> extractParams(final Audit note, final GerritCall call) {
|
||||
Multimap<String, Object> args = ArrayListMultimap.create();
|
||||
private ListMultimap<String, ?> extractParams(Audit note, GerritCall call) {
|
||||
ListMultimap<String, Object> args = ArrayListMultimap.create();
|
||||
|
||||
Object[] params = call.getParams();
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
|
@@ -15,8 +15,7 @@
|
||||
package com.google.gerrit.httpd.rpc.doc;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.gerrit.httpd.restapi.RestApiServlet;
|
||||
import com.google.gerrit.server.documentation.QueryDocumentationExecutor;
|
||||
import com.google.gerrit.server.documentation.QueryDocumentationExecutor.DocQueryException;
|
||||
@@ -68,8 +67,7 @@ public class QueryDocumentationFilter implements Filter {
|
||||
HttpServletResponse rsp = (HttpServletResponse) response;
|
||||
try {
|
||||
List<DocResult> result = searcher.doQuery(request.getParameter("q"));
|
||||
Multimap<String, String> config = LinkedHashMultimap.create();
|
||||
RestApiServlet.replyJson(req, rsp, config, result);
|
||||
RestApiServlet.replyJson(req, rsp, ImmutableListMultimap.of(), result);
|
||||
} catch (DocQueryException e) {
|
||||
log.error("Doc search failed:", e);
|
||||
rsp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
|
Reference in New Issue
Block a user