Merge changes I6707a293,Ie7e7397c

* changes:
  Create ChangeResource with ChangeNotes and CurrentUser
  Remove ChangeResource#getControl() and migrate callers
diff --git a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
index 483e3d4..13dcb77 100644
--- a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
+++ b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -18,6 +18,7 @@
 import static com.google.common.truth.TruthJUnit.assume;
 import static com.google.gerrit.acceptance.GitUtil.initSsh;
 import static com.google.gerrit.extensions.api.changes.SubmittedTogetherOption.NON_VISIBLE_CHANGES;
+import static com.google.gerrit.extensions.client.ListChangesOption.ALL_REVISIONS;
 import static com.google.gerrit.reviewdb.client.Patch.COMMIT_MSG;
 import static com.google.gerrit.reviewdb.client.Patch.MERGE_LIST;
 import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
@@ -30,7 +31,6 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
 import com.google.common.jimfs.Jimfs;
 import com.google.common.primitives.Chars;
 import com.google.gerrit.acceptance.AcceptanceTestRequestScope.Context;
@@ -642,11 +642,7 @@
 
   private List<Boolean> getPatchSetDraftStatuses(Change.Id id) throws Exception {
     Collection<RevisionInfo> revisionInfos =
-        gApi.changes()
-            .id(id.get())
-            .get(EnumSet.of(ListChangesOption.ALL_REVISIONS))
-            .revisions
-            .values();
+        gApi.changes().id(id.get()).get(ALL_REVISIONS).revisions.values();
     return revisionInfos.stream().map(revisionInfo -> revisionInfo.draft).collect(toList());
   }
 
@@ -803,9 +799,7 @@
   }
 
   protected ChangeInfo get(String id, ListChangesOption... options) throws RestApiException {
-    return gApi.changes()
-        .id(id)
-        .get(Sets.newEnumSet(Arrays.asList(options), ListChangesOption.class));
+    return gApi.changes().id(id).get(options);
   }
 
   protected List<ChangeInfo> query(String q) throws RestApiException {
diff --git a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java
index 5fd8da2..d462b43 100644
--- a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java
+++ b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java
@@ -129,7 +129,7 @@
     }
   }
 
-  private static AtomicInteger CHANGE_ID_COUNTER = new AtomicInteger();
+  private static final AtomicInteger CHANGE_ID_COUNTER = new AtomicInteger();
 
   private static String nextChangeId() {
     // Tests use a variety of mechanisms for setting temporary timestamps, so we can't guarantee
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
index 8041e9f..667691b 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -22,6 +22,20 @@
 import static com.google.gerrit.acceptance.PushOneCommit.FILE_CONTENT;
 import static com.google.gerrit.acceptance.PushOneCommit.FILE_NAME;
 import static com.google.gerrit.acceptance.PushOneCommit.SUBJECT;
+import static com.google.gerrit.extensions.client.ListChangesOption.ALL_REVISIONS;
+import static com.google.gerrit.extensions.client.ListChangesOption.CHANGE_ACTIONS;
+import static com.google.gerrit.extensions.client.ListChangesOption.CHECK;
+import static com.google.gerrit.extensions.client.ListChangesOption.COMMIT_FOOTERS;
+import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_ACTIONS;
+import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_COMMIT;
+import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_REVISION;
+import static com.google.gerrit.extensions.client.ListChangesOption.DETAILED_ACCOUNTS;
+import static com.google.gerrit.extensions.client.ListChangesOption.DETAILED_LABELS;
+import static com.google.gerrit.extensions.client.ListChangesOption.LABELS;
+import static com.google.gerrit.extensions.client.ListChangesOption.MESSAGES;
+import static com.google.gerrit.extensions.client.ListChangesOption.PUSH_CERTIFICATES;
+import static com.google.gerrit.extensions.client.ListChangesOption.REVIEWED;
+import static com.google.gerrit.extensions.client.ListChangesOption.TRACKING_IDS;
 import static com.google.gerrit.extensions.client.ReviewerState.CC;
 import static com.google.gerrit.extensions.client.ReviewerState.REMOVED;
 import static com.google.gerrit.extensions.client.ReviewerState.REVIEWER;
@@ -74,7 +88,6 @@
 import com.google.gerrit.extensions.client.ChangeStatus;
 import com.google.gerrit.extensions.client.Comment.Range;
 import com.google.gerrit.extensions.client.InheritableBoolean;
-import com.google.gerrit.extensions.client.ListChangesOption;
 import com.google.gerrit.extensions.client.ReviewerState;
 import com.google.gerrit.extensions.client.Side;
 import com.google.gerrit.extensions.client.SubmitType;
@@ -129,7 +142,6 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -703,17 +715,11 @@
     rebase.call(changeId);
 
     // Second change should have 2 patch sets and an approval
-    ChangeInfo c2 =
-        gApi.changes()
-            .id(changeId)
-            .get(EnumSet.of(ListChangesOption.CURRENT_REVISION, ListChangesOption.DETAILED_LABELS));
+    ChangeInfo c2 = gApi.changes().id(changeId).get(CURRENT_REVISION, DETAILED_LABELS);
     assertThat(c2.revisions.get(c2.currentRevision)._number).isEqualTo(2);
 
     // ...and the committer and description should be correct
-    ChangeInfo info =
-        gApi.changes()
-            .id(changeId)
-            .get(EnumSet.of(ListChangesOption.CURRENT_REVISION, ListChangesOption.CURRENT_COMMIT));
+    ChangeInfo info = gApi.changes().id(changeId).get(CURRENT_REVISION, CURRENT_COMMIT);
     GitPerson committer = info.revisions.get(info.currentRevision).commit.committer;
     assertThat(committer.name).isEqualTo(admin.fullName);
     assertThat(committer.email).isEqualTo(admin.email);
@@ -2059,15 +2065,13 @@
     assertThat(result.actions).isNull();
     assertThat(result.revisions).isNull();
 
-    EnumSet<ListChangesOption> options =
-        EnumSet.of(
-            ListChangesOption.ALL_REVISIONS,
-            ListChangesOption.CHANGE_ACTIONS,
-            ListChangesOption.CURRENT_ACTIONS,
-            ListChangesOption.DETAILED_LABELS,
-            ListChangesOption.MESSAGES);
     result =
-        Iterables.getOnlyElement(gApi.changes().query(r.getChangeId()).withOptions(options).get());
+        Iterables.getOnlyElement(
+            gApi.changes()
+                .query(r.getChangeId())
+                .withOptions(
+                    ALL_REVISIONS, CHANGE_ACTIONS, CURRENT_ACTIONS, DETAILED_LABELS, MESSAGES)
+                .get());
     assertThat(Iterables.getOnlyElement(result.labels.keySet())).isEqualTo("Code-Review");
     assertThat(result.messages).hasSize(1);
     assertThat(result.actions).isNotEmpty();
@@ -2193,8 +2197,7 @@
   public void check() throws Exception {
     PushOneCommit.Result r = createChange();
     assertThat(gApi.changes().id(r.getChangeId()).get().problems).isNull();
-    assertThat(gApi.changes().id(r.getChangeId()).get(EnumSet.of(ListChangesOption.CHECK)).problems)
-        .isEmpty();
+    assertThat(gApi.changes().id(r.getChangeId()).get(CHECK).problems).isEmpty();
   }
 
   @Test
@@ -2232,9 +2235,7 @@
     in.label("Custom2", 1);
     gApi.changes().id(r2.getChangeId()).current().review(in);
 
-    EnumSet<ListChangesOption> options =
-        EnumSet.of(ListChangesOption.ALL_REVISIONS, ListChangesOption.COMMIT_FOOTERS);
-    ChangeInfo actual = gApi.changes().id(r2.getChangeId()).get(options);
+    ChangeInfo actual = gApi.changes().id(r2.getChangeId()).get(ALL_REVISIONS, COMMIT_FOOTERS);
     assertThat(actual.revisions).hasSize(2);
 
     // No footers except on latest patch set.
@@ -2277,9 +2278,7 @@
             });
     ChangeInfo actual;
     try {
-      EnumSet<ListChangesOption> options =
-          EnumSet.of(ListChangesOption.ALL_REVISIONS, ListChangesOption.COMMIT_FOOTERS);
-      actual = gApi.changes().id(change.getChangeId()).get(options);
+      actual = gApi.changes().id(change.getChangeId()).get(ALL_REVISIONS, COMMIT_FOOTERS);
     } finally {
       handle.remove();
     }
@@ -2320,9 +2319,9 @@
                   .query()
                   .withQuery("project:{" + project.get() + "} (status:open OR status:closed)")
                   // Options should match defaults in AccountDashboardScreen.
-                  .withOption(ListChangesOption.LABELS)
-                  .withOption(ListChangesOption.DETAILED_ACCOUNTS)
-                  .withOption(ListChangesOption.REVIEWED)
+                  .withOption(LABELS)
+                  .withOption(DETAILED_ACCOUNTS)
+                  .withOption(REVIEWED)
                   .get())
           .hasSize(2);
     } finally {
@@ -2335,7 +2334,7 @@
     PushOneCommit.Result r = createChange();
     String triplet = project.get() + "~master~" + r.getChangeId();
     gApi.changes().id(triplet).addReviewer(user.username);
-    ChangeInfo c = gApi.changes().id(triplet).get(EnumSet.of(ListChangesOption.DETAILED_LABELS));
+    ChangeInfo c = gApi.changes().id(triplet).get(DETAILED_LABELS);
     LabelInfo codeReview = c.labels.get("Code-Review");
     assertThat(codeReview.all).hasSize(1);
     ApprovalInfo approval = codeReview.all.get(0);
@@ -2345,7 +2344,7 @@
     ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
     Util.blockLabel(cfg, "Code-Review", REGISTERED_USERS, "refs/heads/*");
     saveProjectConfig(project, cfg);
-    c = gApi.changes().id(triplet).get(EnumSet.of(ListChangesOption.DETAILED_LABELS));
+    c = gApi.changes().id(triplet).get(DETAILED_LABELS);
     codeReview = c.labels.get("Code-Review");
     assertThat(codeReview.all).hasSize(1);
     approval = codeReview.all.get(0);
@@ -2360,10 +2359,7 @@
     PushOneCommit.Result r1 = createChange();
     PushOneCommit.Result r2 = amendChange(r1.getChangeId());
 
-    ChangeInfo info =
-        gApi.changes()
-            .id(r1.getChangeId())
-            .get(EnumSet.of(ListChangesOption.ALL_REVISIONS, ListChangesOption.PUSH_CERTIFICATES));
+    ChangeInfo info = gApi.changes().id(r1.getChangeId()).get(ALL_REVISIONS, PUSH_CERTIFICATES);
 
     RevisionInfo rev1 = info.revisions.get(r1.getCommit().name());
     assertThat(rev1).isNotNull();
@@ -2675,13 +2671,7 @@
     in.subject = "update change by merge ps2";
     gApi.changes().id(changeId).createMergePatchSet(in);
     ChangeInfo changeInfo =
-        gApi.changes()
-            .id(changeId)
-            .get(
-                EnumSet.of(
-                    ListChangesOption.ALL_REVISIONS,
-                    ListChangesOption.CURRENT_COMMIT,
-                    ListChangesOption.CURRENT_REVISION));
+        gApi.changes().id(changeId).get(ALL_REVISIONS, CURRENT_COMMIT, CURRENT_REVISION);
     assertThat(changeInfo.revisions.size()).isEqualTo(2);
     assertThat(changeInfo.subject).isEqualTo(in.subject);
     assertThat(changeInfo.revisions.get(changeInfo.currentRevision).commit.parents.get(0).commit)
@@ -2718,13 +2708,7 @@
     in.inheritParent = true;
     gApi.changes().id(changeId).createMergePatchSet(in);
     ChangeInfo changeInfo =
-        gApi.changes()
-            .id(changeId)
-            .get(
-                EnumSet.of(
-                    ListChangesOption.ALL_REVISIONS,
-                    ListChangesOption.CURRENT_COMMIT,
-                    ListChangesOption.CURRENT_REVISION));
+        gApi.changes().id(changeId).get(ALL_REVISIONS, CURRENT_COMMIT, CURRENT_REVISION);
 
     assertThat(changeInfo.revisions.size()).isEqualTo(2);
     assertThat(changeInfo.subject).isEqualTo(in.subject);
@@ -2930,7 +2914,7 @@
 
     gApi.changes().id(triplet).addReviewer(user.username);
 
-    ChangeInfo c = gApi.changes().id(triplet).get(EnumSet.of(ListChangesOption.DETAILED_LABELS));
+    ChangeInfo c = gApi.changes().id(triplet).get(DETAILED_LABELS);
     LabelInfo codeReview = c.labels.get("Code-Review");
     assertThat(codeReview.all).hasSize(1);
     ApprovalInfo approval = codeReview.all.get(0);
@@ -2950,7 +2934,7 @@
         heads);
     saveProjectConfig(project, cfg);
 
-    c = gApi.changes().id(triplet).get(EnumSet.of(ListChangesOption.DETAILED_LABELS));
+    c = gApi.changes().id(triplet).get(DETAILED_LABELS);
     codeReview = c.labels.get("Code-Review");
     assertThat(codeReview.all).hasSize(1);
     approval = codeReview.all.get(0);
@@ -2971,7 +2955,7 @@
 
     gApi.changes().id(triplet).addReviewer(user.username);
 
-    ChangeInfo c = gApi.changes().id(triplet).get(EnumSet.of(ListChangesOption.DETAILED_LABELS));
+    ChangeInfo c = gApi.changes().id(triplet).get(DETAILED_LABELS);
     LabelInfo codeReview = c.labels.get("Code-Review");
     assertThat(codeReview.all).hasSize(1);
     ApprovalInfo approval = codeReview.all.get(0);
@@ -3155,14 +3139,7 @@
     ri.comments = ImmutableMap.of(FILE_NAME, ImmutableList.of(ci));
     gApi.changes().id(id).current().review(ri);
 
-    ChangeInfo info =
-        gApi.changes()
-            .id(id)
-            .get(
-                EnumSet.of(
-                    ListChangesOption.MESSAGES,
-                    ListChangesOption.CURRENT_COMMIT,
-                    ListChangesOption.CURRENT_REVISION));
+    ChangeInfo info = gApi.changes().id(id).get(MESSAGES, CURRENT_COMMIT, CURRENT_REVISION);
     assertThat(info.subject).isEqualTo(subject);
     assertThat(Iterables.getLast(info.messages).message).endsWith(ri.message);
     assertThat(Iterables.getOnlyElement(info.revisions.values()).commit.message)
@@ -3308,7 +3285,7 @@
 
   private Optional<ReviewerState> getReviewerState(String changeId, Account.Id accountId)
       throws Exception {
-    ChangeInfo c = gApi.changes().id(changeId).get(EnumSet.of(ListChangesOption.DETAILED_LABELS));
+    ChangeInfo c = gApi.changes().id(changeId).get(DETAILED_LABELS);
     Set<ReviewerState> states =
         c.reviewers
             .entrySet()
@@ -3369,8 +3346,7 @@
     PushOneCommit.Result result = push.to("refs/for/master");
     result.assertOkStatus();
 
-    ChangeInfo change =
-        gApi.changes().id(result.getChangeId()).get(EnumSet.of(ListChangesOption.TRACKING_IDS));
+    ChangeInfo change = gApi.changes().id(result.getChangeId()).get(TRACKING_IDS);
     Collection<TrackingIdInfo> trackingIds = change.trackingIds;
     assertThat(trackingIds).isNotNull();
     assertThat(trackingIds).hasSize(1);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/StickyApprovalsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/StickyApprovalsIT.java
index 94f8494..28933ad 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/StickyApprovalsIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/StickyApprovalsIT.java
@@ -20,6 +20,9 @@
 import static com.google.gerrit.extensions.client.ChangeKind.NO_CODE_CHANGE;
 import static com.google.gerrit.extensions.client.ChangeKind.REWORK;
 import static com.google.gerrit.extensions.client.ChangeKind.TRIVIAL_REBASE;
+import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_COMMIT;
+import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_REVISION;
+import static com.google.gerrit.extensions.client.ListChangesOption.DETAILED_LABELS;
 import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
 import static com.google.gerrit.server.project.Util.category;
 import static com.google.gerrit.server.project.Util.value;
@@ -38,7 +41,6 @@
 import com.google.gerrit.extensions.api.changes.ReviewInput;
 import com.google.gerrit.extensions.api.changes.RevisionApi;
 import com.google.gerrit.extensions.client.ChangeKind;
-import com.google.gerrit.extensions.client.ListChangesOption;
 import com.google.gerrit.extensions.common.ApprovalInfo;
 import com.google.gerrit.extensions.common.ChangeInfo;
 import com.google.gerrit.extensions.common.CommitInfo;
@@ -336,13 +338,7 @@
   }
 
   private ChangeInfo detailedChange(String changeId) throws Exception {
-    return gApi.changes()
-        .id(changeId)
-        .get(
-            EnumSet.of(
-                ListChangesOption.DETAILED_LABELS,
-                ListChangesOption.CURRENT_REVISION,
-                ListChangesOption.CURRENT_COMMIT));
+    return gApi.changes().id(changeId).get(DETAILED_LABELS, CURRENT_REVISION, CURRENT_COMMIT);
   }
 
   private void assertNotSticky(Set<ChangeKind> changeKinds) throws Exception {
@@ -533,7 +529,7 @@
   }
 
   private ChangeKind getChangeKind(String changeId) throws Exception {
-    ChangeInfo c = gApi.changes().id(changeId).get(EnumSet.of(ListChangesOption.CURRENT_REVISION));
+    ChangeInfo c = gApi.changes().id(changeId).get(CURRENT_REVISION);
     return c.revisions.get(c.currentRevision).kind;
   }
 
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
index 33bbe6b..bc89e22 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
@@ -53,7 +53,6 @@
 import com.google.gerrit.extensions.api.changes.RevisionApi;
 import com.google.gerrit.extensions.api.projects.BranchInput;
 import com.google.gerrit.extensions.client.ChangeStatus;
-import com.google.gerrit.extensions.client.ListChangesOption;
 import com.google.gerrit.extensions.client.ReviewerState;
 import com.google.gerrit.extensions.client.SubmitType;
 import com.google.gerrit.extensions.common.AccountInfo;
@@ -92,7 +91,6 @@
 import java.text.SimpleDateFormat;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -162,8 +160,7 @@
     approval = getApproval(changeId, label);
     assertThat(approval.value).isEqualTo(1);
     assertThat(approval.postSubmit).isNull();
-    assertPermitted(
-        gApi.changes().id(changeId).get(EnumSet.of(DETAILED_LABELS)), "Code-Review", 1, 2);
+    assertPermitted(gApi.changes().id(changeId).get(DETAILED_LABELS), "Code-Review", 1, 2);
 
     // Repeating the current label is allowed. Does not flip the postSubmit bit
     // due to deduplication codepath.
@@ -190,7 +187,7 @@
     approval = getApproval(changeId, label);
     assertThat(approval.value).isEqualTo(2);
     assertThat(approval.postSubmit).isTrue();
-    assertPermitted(gApi.changes().id(changeId).get(EnumSet.of(DETAILED_LABELS)), "Code-Review", 2);
+    assertPermitted(gApi.changes().id(changeId).get(DETAILED_LABELS), "Code-Review", 2);
 
     // Decreasing to previous post-submit vote is still not allowed.
     try {
@@ -241,7 +238,7 @@
     ApprovalInfo cr =
         gApi.changes()
             .id(changeId)
-            .get(EnumSet.of(ListChangesOption.DETAILED_LABELS))
+            .get(DETAILED_LABELS)
             .labels
             .get("Code-Review")
             .all
@@ -1359,7 +1356,7 @@
   }
 
   private ApprovalInfo getApproval(String changeId, String label) throws Exception {
-    ChangeInfo info = gApi.changes().id(changeId).get(EnumSet.of(DETAILED_LABELS));
+    ChangeInfo info = gApi.changes().id(changeId).get(DETAILED_LABELS);
     LabelInfo li = info.labels.get(label);
     assertThat(li).isNotNull();
     int accountId = atrScope.get().getUser().getAccountId().get();
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java
index 930b996..c6c4f3e 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java
@@ -22,6 +22,8 @@
 import static com.google.gerrit.acceptance.GitUtil.pushHead;
 import static com.google.gerrit.acceptance.PushOneCommit.FILE_NAME;
 import static com.google.gerrit.common.FooterConstants.CHANGE_ID;
+import static com.google.gerrit.extensions.client.ListChangesOption.ALL_REVISIONS;
+import static com.google.gerrit.extensions.client.ListChangesOption.MESSAGES;
 import static com.google.gerrit.extensions.common.EditInfoSubject.assertThat;
 import static com.google.gerrit.server.git.receive.ReceiveConstants.PUSH_OPTION_SKIP_VALIDATION;
 import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
@@ -1640,8 +1642,7 @@
     String ref = "refs/for/master%merged";
     assertPushOk(pushHead(testRepo, ref, false), ref);
 
-    EnumSet<ListChangesOption> opts = EnumSet.of(ListChangesOption.ALL_REVISIONS);
-    ChangeInfo info = gApi.changes().id(r.getChangeId()).get(opts);
+    ChangeInfo info = gApi.changes().id(r.getChangeId()).get(ALL_REVISIONS);
     assertThat(info.currentRevision).isEqualTo(c2.name());
     assertThat(info.revisions.keySet()).containsExactly(c1.name(), c2.name());
     // TODO(dborowitz): Fix ReceiveCommits to also auto-close the change.
@@ -1849,12 +1850,7 @@
 
   private String getLastMessage(String changeId) throws Exception {
     return Streams.findLast(
-            gApi.changes()
-                .id(changeId)
-                .get(EnumSet.of(ListChangesOption.MESSAGES))
-                .messages
-                .stream()
-                .map(m -> m.message))
+            gApi.changes().id(changeId).get(MESSAGES).messages.stream().map(m -> m.message))
         .get();
   }
 
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/ImpersonationIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/ImpersonationIT.java
index 05e5f99..36843a5 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/ImpersonationIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/ImpersonationIT.java
@@ -16,6 +16,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.TruthJUnit.assume;
+import static com.google.gerrit.extensions.client.ListChangesOption.MESSAGES;
 import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
 import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
 
@@ -39,7 +40,6 @@
 import com.google.gerrit.extensions.api.changes.RevisionApi;
 import com.google.gerrit.extensions.api.changes.SubmitInput;
 import com.google.gerrit.extensions.api.groups.GroupInput;
-import com.google.gerrit.extensions.client.ListChangesOption;
 import com.google.gerrit.extensions.client.Side;
 import com.google.gerrit.extensions.common.AccountInfo;
 import com.google.gerrit.extensions.common.ChangeInfo;
@@ -64,7 +64,6 @@
 import com.google.gerrit.server.project.Util;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.inject.Inject;
-import java.util.EnumSet;
 import org.apache.http.Header;
 import org.apache.http.message.BasicHeader;
 import org.junit.After;
@@ -545,8 +544,7 @@
     setApiUser(accountCreator.user2());
     gApi.changes().id(r.getChangeId()).revision(r.getPatchSetId().getId()).review(in);
 
-    ChangeInfo info =
-        gApi.changes().id(r.getChangeId()).get(EnumSet.of(ListChangesOption.MESSAGES));
+    ChangeInfo info = gApi.changes().id(r.getChangeId()).get(MESSAGES);
     assertThat(info.messages).hasSize(2);
 
     ChangeMessageInfo changeMessageInfo = Iterables.getLast(info.messages);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ActionsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ActionsIT.java
index 239c296..0061103 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ActionsIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ActionsIT.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.acceptance.rest.change;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.extensions.client.ListChangesOption.CHANGE_ACTIONS;
 import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_ACTIONS;
 import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_REVISION;
 
@@ -316,7 +317,7 @@
   @Test
   public void changeActionVisitor() throws Exception {
     String id = createChange().getChangeId();
-    ChangeInfo origChange = gApi.changes().id(id).get(EnumSet.of(ListChangesOption.CHANGE_ACTIONS));
+    ChangeInfo origChange = gApi.changes().id(id).get(CHANGE_ACTIONS);
 
     class Visitor implements ActionVisitor {
       @Override
@@ -362,7 +363,7 @@
   public void currentRevisionActionVisitor() throws Exception {
     String id = createChange().getChangeId();
     amendChange(id);
-    ChangeInfo origChange = gApi.changes().id(id).get(EnumSet.of(ListChangesOption.CHANGE_ACTIONS));
+    ChangeInfo origChange = gApi.changes().id(id).get(CHANGE_ACTIONS);
     Change.Id changeId = new Change.Id(origChange._number);
 
     class Visitor implements ActionVisitor {
@@ -429,7 +430,7 @@
   public void oldRevisionActionVisitor() throws Exception {
     String id = createChange().getChangeId();
     amendChange(id);
-    ChangeInfo origChange = gApi.changes().id(id).get(EnumSet.of(ListChangesOption.CHANGE_ACTIONS));
+    ChangeInfo origChange = gApi.changes().id(id).get(CHANGE_ACTIONS);
 
     class Visitor implements ActionVisitor {
       @Override
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeReviewersByEmailIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeReviewersByEmailIT.java
index 6762263..93bb3fa 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeReviewersByEmailIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeReviewersByEmailIT.java
@@ -16,6 +16,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.TruthJUnit.assume;
+import static com.google.gerrit.extensions.client.ListChangesOption.DETAILED_LABELS;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -28,13 +29,11 @@
 import com.google.gerrit.extensions.api.changes.ReviewInput;
 import com.google.gerrit.extensions.api.projects.ConfigInput;
 import com.google.gerrit.extensions.client.InheritableBoolean;
-import com.google.gerrit.extensions.client.ListChangesOption;
 import com.google.gerrit.extensions.client.ReviewerState;
 import com.google.gerrit.extensions.common.AccountInfo;
 import com.google.gerrit.extensions.common.ChangeInfo;
 import com.google.gerrit.server.mail.Address;
 import com.google.gerrit.testutil.FakeEmailSender.Message;
-import java.util.EnumSet;
 import java.util.List;
 import org.junit.Before;
 import org.junit.Test;
@@ -62,8 +61,7 @@
       input.state = state;
       gApi.changes().id(r.getChangeId()).addReviewer(input);
 
-      ChangeInfo info =
-          gApi.changes().id(r.getChangeId()).get(EnumSet.of(ListChangesOption.DETAILED_LABELS));
+      ChangeInfo info = gApi.changes().id(r.getChangeId()).get(DETAILED_LABELS);
       assertThat(info.reviewers).isEqualTo(ImmutableMap.of(state, ImmutableList.of(acc)));
       // All reviewers added by email should be removable
       assertThat(info.removableReviewers).isEqualTo(ImmutableList.of(acc));
@@ -89,8 +87,7 @@
       inputById.state = state;
       gApi.changes().id(r.getChangeId()).addReviewer(inputById);
 
-      ChangeInfo info =
-          gApi.changes().id(r.getChangeId()).get(EnumSet.of(ListChangesOption.DETAILED_LABELS));
+      ChangeInfo info = gApi.changes().id(r.getChangeId()).get(DETAILED_LABELS);
       assertThat(info.reviewers).isEqualTo(ImmutableMap.of(state, ImmutableList.of(byId, byEmail)));
       // All reviewers (both by id and by email) should be removable
       assertThat(info.removableReviewers).isEqualTo(ImmutableList.of(byId, byEmail));
@@ -112,8 +109,7 @@
 
       gApi.changes().id(r.getChangeId()).reviewer(acc.email).remove();
 
-      ChangeInfo info =
-          gApi.changes().id(r.getChangeId()).get(EnumSet.of(ListChangesOption.DETAILED_LABELS));
+      ChangeInfo info = gApi.changes().id(r.getChangeId()).get(DETAILED_LABELS);
       assertThat(info.reviewers).isEmpty();
     }
   }
@@ -135,8 +131,7 @@
     modifyInput.state = ReviewerState.REVIEWER;
     gApi.changes().id(r.getChangeId()).addReviewer(modifyInput);
 
-    ChangeInfo info =
-        gApi.changes().id(r.getChangeId()).get(EnumSet.of(ListChangesOption.DETAILED_LABELS));
+    ChangeInfo info = gApi.changes().id(r.getChangeId()).get(DETAILED_LABELS);
     assertThat(info.reviewers)
         .isEqualTo(ImmutableMap.of(ReviewerState.REVIEWER, ImmutableList.of(acc)));
   }
@@ -329,10 +324,7 @@
       try {
         ChangeInfo info =
             Iterables.getOnlyElement(
-                gApi.changes()
-                    .query(r.getChangeId())
-                    .withOption(ListChangesOption.DETAILED_LABELS)
-                    .get());
+                gApi.changes().query(r.getChangeId()).withOption(DETAILED_LABELS).get());
         assertThat(info.reviewers).isEqualTo(ImmutableMap.of(state, ImmutableList.of(acc)));
       } finally {
         notesMigration.setFailOnLoadForTest(false);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeReviewersIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeReviewersIT.java
index c7c02b2..3cc21a6 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeReviewersIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeReviewersIT.java
@@ -48,7 +48,6 @@
 import com.google.gson.stream.JsonReader;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -806,6 +805,6 @@
   }
 
   private Map<String, LabelInfo> getChangeLabels(String changeId) throws Exception {
-    return gApi.changes().id(changeId).get(EnumSet.of(DETAILED_LABELS)).labels;
+    return gApi.changes().id(changeId).get(DETAILED_LABELS).labels;
   }
 }
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/NoteDbOnlyIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/NoteDbOnlyIT.java
index 2cd1800..d0e3ba5 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/NoteDbOnlyIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/NoteDbOnlyIT.java
@@ -18,6 +18,7 @@
 import static com.google.common.truth.Truth.assert_;
 import static com.google.common.truth.Truth8.assertThat;
 import static com.google.common.truth.TruthJUnit.assume;
+import static com.google.gerrit.extensions.client.ListChangesOption.MESSAGES;
 import static java.util.stream.Collectors.toList;
 
 import com.google.common.collect.Iterables;
@@ -26,7 +27,6 @@
 import com.google.gerrit.acceptance.PushOneCommit;
 import com.google.gerrit.common.TimeUtil;
 import com.google.gerrit.extensions.api.changes.ReviewInput;
-import com.google.gerrit.extensions.client.ListChangesOption;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.update.BatchUpdate;
@@ -39,7 +39,6 @@
 import com.google.inject.Inject;
 import java.io.IOException;
 import java.util.Collections;
-import java.util.EnumSet;
 import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -280,7 +279,7 @@
   private List<String> getMessages(Change.Id id) throws Exception {
     return gApi.changes()
         .id(id.get())
-        .get(EnumSet.of(ListChangesOption.MESSAGES))
+        .get(MESSAGES)
         .messages
         .stream()
         .map(m -> m.message)
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
index 53bf6a0..9bc09d2 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.extensions.api.changes;
 
+import com.google.common.collect.Sets;
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.extensions.client.ListChangesOption;
 import com.google.gerrit.extensions.common.AccountInfo;
@@ -27,6 +28,7 @@
 import com.google.gerrit.extensions.common.SuggestedReviewerInfo;
 import com.google.gerrit.extensions.restapi.NotImplementedException;
 import com.google.gerrit.extensions.restapi.RestApiException;
+import java.util.Arrays;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Map;
@@ -170,6 +172,14 @@
 
   ChangeInfo get(EnumSet<ListChangesOption> options) throws RestApiException;
 
+  default ChangeInfo get(Iterable<ListChangesOption> options) throws RestApiException {
+    return get(Sets.newEnumSet(options, ListChangesOption.class));
+  }
+
+  default ChangeInfo get(ListChangesOption... options) throws RestApiException {
+    return get(Arrays.asList(options));
+  }
+
   /** {@code get} with {@link ListChangesOption} set to all except CHECK. */
   ChangeInfo get() throws RestApiException;
   /** {@code get} with {@link ListChangesOption} set to none. */
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeReportFormatter.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeReportFormatter.java
index 6b1fd85..3f3e2dd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeReportFormatter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeReportFormatter.java
@@ -14,68 +14,72 @@
 
 package com.google.gerrit.server.git;
 
+import com.google.auto.value.AutoValue;
+import com.google.gerrit.common.Nullable;
 import com.google.gerrit.reviewdb.client.Change;
 
 public interface ChangeReportFormatter {
-  public static class Input {
-    private final Change change;
-    private String subject;
-    private Boolean draft;
-    private Boolean edit;
-    private Boolean isPrivate;
-    private Boolean wip;
+  @AutoValue
+  public abstract static class Input {
+    public abstract Change change();
 
-    public Input(Change change) {
-      this.change = change;
+    @Nullable
+    public abstract String subject();
+
+    @Nullable
+    public abstract Boolean isDraft();
+
+    @Nullable
+    public abstract Boolean isEdit();
+
+    @Nullable
+    public abstract Boolean isPrivate();
+
+    @Nullable
+    public abstract Boolean isWorkInProgress();
+
+    public static Builder builder() {
+      return new AutoValue_ChangeReportFormatter_Input.Builder();
     }
 
-    public Input setPrivate(boolean isPrivate) {
-      this.isPrivate = isPrivate;
-      return this;
-    }
+    @AutoValue.Builder
+    public abstract static class Builder {
+      public abstract Builder setChange(Change val);
 
-    public Input setDraft(boolean draft) {
-      this.draft = draft;
-      return this;
-    }
+      public abstract Builder setSubject(String val);
 
-    public Input setEdit(boolean edit) {
-      this.edit = edit;
-      return this;
-    }
+      public abstract Builder setIsDraft(Boolean val);
 
-    public Input setWorkInProgress(boolean wip) {
-      this.wip = wip;
-      return this;
-    }
+      public abstract Builder setIsEdit(Boolean val);
 
-    public Input setSubject(String subject) {
-      this.subject = subject;
-      return this;
-    }
+      public abstract Builder setIsPrivate(Boolean val);
 
-    public Change getChange() {
-      return change;
-    }
+      public abstract Builder setIsWorkInProgress(Boolean val);
 
-    public String getSubject() {
-      return subject == null ? change.getSubject() : subject;
-    }
+      abstract Change change();
 
-    public boolean isDraft() {
-      return draft == null ? Change.Status.DRAFT == change.getStatus() : draft;
-    }
+      abstract String subject();
 
-    public boolean isEdit() {
-      return edit == null ? false : edit;
-    }
+      abstract Boolean isDraft();
 
-    public boolean isPrivate() {
-      return isPrivate == null ? change.isPrivate() : isPrivate;
-    }
+      abstract Boolean isEdit();
 
-    public boolean isWorkInProgress() {
-      return wip == null ? change.isWorkInProgress() : wip;
+      abstract Boolean isPrivate();
+
+      abstract Boolean isWorkInProgress();
+
+      abstract Input autoBuild();
+
+      public Input build() {
+        setChange(change());
+        setSubject(subject() == null ? change().getSubject() : subject());
+        setIsDraft(isDraft() == null ? Change.Status.DRAFT == change().getStatus() : isDraft());
+        setIsEdit(isEdit() == null ? false : isEdit());
+        setIsPrivate(isPrivate() == null ? change().isPrivate() : isPrivate());
+        setIsWorkInProgress(
+            isWorkInProgress() == null ? change().isWorkInProgress() : isWorkInProgress());
+        return autoBuild();
+      }
     }
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/DefaultChangeReportFormatter.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/DefaultChangeReportFormatter.java
index 297770c..8b5ab06 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/DefaultChangeReportFormatter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/DefaultChangeReportFormatter.java
@@ -39,16 +39,16 @@
   @Override
   public String changeClosed(ChangeReportFormatter.Input input) {
     return String.format(
-        "change %s closed", ChangeUtil.formatChangeUrl(canonicalWebUrl, input.getChange()));
+        "change %s closed", ChangeUtil.formatChangeUrl(canonicalWebUrl, input.change()));
   }
 
   private String formatChangeUrl(String url, Input input) {
     StringBuilder m =
         new StringBuilder()
             .append("  ")
-            .append(ChangeUtil.formatChangeUrl(url, input.getChange()))
+            .append(ChangeUtil.formatChangeUrl(url, input.change()))
             .append(" ")
-            .append(ChangeUtil.cropSubject(input.getSubject()));
+            .append(ChangeUtil.cropSubject(input.subject()));
     if (input.isDraft()) {
       m.append(" [DRAFT]");
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index b1edb92..634ffce 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -605,7 +605,9 @@
       addMessage("");
       addMessage("New Changes:");
       for (CreateRequest c : created) {
-        addMessage(changeFormatter.newChange(new ChangeReportFormatter.Input(c.change)));
+        addMessage(
+            changeFormatter.newChange(
+                ChangeReportFormatter.Input.builder().setChange(c.change).build()));
       }
       addMessage("");
     }
@@ -657,12 +659,14 @@
         }
 
         ChangeReportFormatter.Input input =
-            new ChangeReportFormatter.Input(u.notes.getChange())
+            ChangeReportFormatter.Input.builder()
+                .setChange(u.notes.getChange())
                 .setSubject(subject)
-                .setDraft(u.replaceOp != null && u.replaceOp.getPatchSet().isDraft())
-                .setEdit(edit)
-                .setPrivate(isPrivate)
-                .setWorkInProgress(wip);
+                .setIsDraft(u.replaceOp != null && u.replaceOp.getPatchSet().isDraft())
+                .setIsEdit(edit)
+                .setIsPrivate(isPrivate)
+                .setIsWorkInProgress(wip)
+                .build();
         addMessage(changeFormatter.changeUpdated(input));
       }
       addMessage("");
@@ -1678,7 +1682,10 @@
   private boolean requestReplace(
       ReceiveCommand cmd, boolean checkMergedInto, Change change, RevCommit newCommit) {
     if (change.getStatus().isClosed()) {
-      reject(cmd, changeFormatter.changeClosed(new ChangeReportFormatter.Input(change)));
+      reject(
+          cmd,
+          changeFormatter.changeClosed(
+              ChangeReportFormatter.Input.builder().setChange(change).build()));
       return false;
     }
 
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/ChangeArgumentParser.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/ChangeArgumentParser.java
index da61db8..1c55f48 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/ChangeArgumentParser.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/ChangeArgumentParser.java
@@ -28,7 +28,6 @@
 import com.google.gerrit.server.permissions.GlobalPermission;
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.permissions.PermissionBackendException;
-import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.sshd.BaseCommand.UnloggedFailure;
 import com.google.gwtorm.server.OrmException;
@@ -44,7 +43,6 @@
   private final ChangeFinder changeFinder;
   private final ReviewDb db;
   private final ChangeNotes.Factory changeNotesFactory;
-  private final ChangeControl.GenericFactory changeControlFactory;
   private final PermissionBackend permissionBackend;
 
   @Inject
@@ -54,14 +52,12 @@
       ChangeFinder changeFinder,
       ReviewDb db,
       ChangeNotes.Factory changeNotesFactory,
-      ChangeControl.GenericFactory changeControlFactory,
       PermissionBackend permissionBackend) {
     this.currentUser = currentUser;
     this.changesCollection = changesCollection;
     this.changeFinder = changeFinder;
     this.db = db;
     this.changeNotesFactory = changeNotesFactory;
-    this.changeControlFactory = changeControlFactory;
     this.permissionBackend = permissionBackend;
   }