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

@@ -28,7 +28,7 @@ import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Collections2;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListeningExecutorService;
@@ -408,9 +408,9 @@ public class LuceneChangeIndex implements ChangeIndex {
}
}
private static Multimap<String, IndexableField> fields(Document doc,
private static ListMultimap<String, IndexableField> fields(Document doc,
Set<String> fields) {
Multimap<String, IndexableField> stored =
ListMultimap<String, IndexableField> stored =
ArrayListMultimap.create(fields.size(), 4);
for (IndexableField f : doc) {
String name = f.name();
@@ -421,7 +421,7 @@ public class LuceneChangeIndex implements ChangeIndex {
return stored;
}
private ChangeData toChangeData(Multimap<String, IndexableField> doc,
private ChangeData toChangeData(ListMultimap<String, IndexableField> doc,
Set<String> fields, String idFieldName) {
ChangeData cd;
// Either change or the ID field was guaranteed to be included in the call
@@ -482,7 +482,8 @@ public class LuceneChangeIndex implements ChangeIndex {
return cd;
}
private void decodePatchSets(Multimap<String, IndexableField> doc, ChangeData cd) {
private void decodePatchSets(ListMultimap<String, IndexableField> doc,
ChangeData cd) {
List<PatchSet> patchSets =
decodeProtos(doc, PATCH_SET_FIELD, PatchSetProtoField.CODEC);
if (!patchSets.isEmpty()) {
@@ -492,12 +493,14 @@ public class LuceneChangeIndex implements ChangeIndex {
}
}
private void decodeApprovals(Multimap<String, IndexableField> doc, ChangeData cd) {
private void decodeApprovals(ListMultimap<String, IndexableField> doc,
ChangeData cd) {
cd.setCurrentApprovals(
decodeProtos(doc, APPROVAL_FIELD, PatchSetApprovalProtoField.CODEC));
}
private void decodeChangedLines(Multimap<String, IndexableField> doc, ChangeData cd) {
private void decodeChangedLines(ListMultimap<String, IndexableField> doc,
ChangeData cd) {
IndexableField added = Iterables.getFirst(doc.get(ADDED_FIELD), null);
IndexableField deleted = Iterables.getFirst(doc.get(DELETED_FIELD), null);
if (added != null && deleted != null) {
@@ -513,7 +516,8 @@ public class LuceneChangeIndex implements ChangeIndex {
}
}
private void decodeMergeable(Multimap<String, IndexableField> doc, ChangeData cd) {
private void decodeMergeable(ListMultimap<String, IndexableField> doc,
ChangeData cd) {
IndexableField f = Iterables.getFirst(doc.get(MERGEABLE_FIELD), null);
if (f != null) {
String mergeable = f.stringValue();
@@ -525,7 +529,8 @@ public class LuceneChangeIndex implements ChangeIndex {
}
}
private void decodeReviewedBy(Multimap<String, IndexableField> doc, ChangeData cd) {
private void decodeReviewedBy(ListMultimap<String, IndexableField> doc,
ChangeData cd) {
Collection<IndexableField> reviewedBy = doc.get(REVIEWEDBY_FIELD);
if (reviewedBy.size() > 0) {
Set<Account.Id> accounts =
@@ -541,7 +546,8 @@ public class LuceneChangeIndex implements ChangeIndex {
}
}
private void decodeHashtags(Multimap<String, IndexableField> doc, ChangeData cd) {
private void decodeHashtags(ListMultimap<String, IndexableField> doc,
ChangeData cd) {
Collection<IndexableField> hashtag = doc.get(HASHTAG_FIELD);
Set<String> hashtags = Sets.newHashSetWithExpectedSize(hashtag.size());
for (IndexableField r : hashtag) {
@@ -550,9 +556,10 @@ public class LuceneChangeIndex implements ChangeIndex {
cd.setHashtags(hashtags);
}
private void decodeStar(Multimap<String, IndexableField> doc, ChangeData cd) {
private void decodeStar(ListMultimap<String, IndexableField> doc,
ChangeData cd) {
Collection<IndexableField> star = doc.get(STAR_FIELD);
Multimap<Account.Id, String> stars = ArrayListMultimap.create();
ListMultimap<Account.Id, String> stars = ArrayListMultimap.create();
for (IndexableField r : star) {
StarredChangesUtil.StarField starField =
StarredChangesUtil.StarField.parse(r.stringValue());
@@ -563,7 +570,7 @@ public class LuceneChangeIndex implements ChangeIndex {
cd.setStars(stars);
}
private void decodeReviewers(Multimap<String, IndexableField> doc,
private void decodeReviewers(ListMultimap<String, IndexableField> doc,
ChangeData cd) {
cd.setReviewers(
ChangeField.parseReviewerFieldValues(
@@ -571,7 +578,7 @@ public class LuceneChangeIndex implements ChangeIndex {
.transform(IndexableField::stringValue)));
}
private void decodeSubmitRecords(Multimap<String, IndexableField> doc,
private void decodeSubmitRecords(ListMultimap<String, IndexableField> doc,
String field, SubmitRuleOptions opts, ChangeData cd) {
ChangeField.parseSubmitRecords(
Collections2.transform(
@@ -579,17 +586,18 @@ public class LuceneChangeIndex implements ChangeIndex {
opts, cd);
}
private void decodeRefStates(Multimap<String, IndexableField> doc,
private void decodeRefStates(ListMultimap<String, IndexableField> doc,
ChangeData cd) {
cd.setRefStates(copyAsBytes(doc.get(REF_STATE_FIELD)));
}
private void decodeRefStatePatterns(Multimap<String, IndexableField> doc,
private void decodeRefStatePatterns(ListMultimap<String, IndexableField> doc,
ChangeData cd) {
cd.setRefStatePatterns(copyAsBytes(doc.get(REF_STATE_PATTERN_FIELD)));
}
private static <T> List<T> decodeProtos(Multimap<String, IndexableField> doc,
private static <T> List<T> decodeProtos(
ListMultimap<String, IndexableField> doc,
String fieldName, ProtobufCodec<T> codec) {
Collection<IndexableField> fields = doc.get(fieldName);
if (fields.isEmpty()) {