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:
Dave Borowitz
2017-01-13 16:26:45 -05:00
committed by David Pursehouse
parent e5c5953205
commit 484da493b3
76 changed files with 367 additions and 355 deletions

View File

@@ -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() {

View File

@@ -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();

View File

@@ -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";

View File

@@ -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++) {

View File

@@ -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);