Use injector and factory to instantiate SubmitRuleEvaluator

All callers of SubmitRuleEvaluator get AccountCache, Accounts and
Emails injected just to pass them to SubmitRuleEvaluator manually.

This commit adds a Factory to SubmitRuleEvaluator and migrates callers
to use the factory instead to remove boilerplate.

In addition, this commit moves the instantiation of ChangeControl from
the constructor closer to where it is needed to prevent the constructor
from throwing an OrmException.

Change-Id: I429e7a67e4f1a45be1cf2c2f05692661c086cabe
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/BatchProgramModule.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/BatchProgramModule.java
index d677ec0..32d8dd8 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/BatchProgramModule.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/BatchProgramModule.java
@@ -68,6 +68,7 @@
 import com.google.gerrit.server.project.ProjectCacheImpl;
 import com.google.gerrit.server.project.ProjectState;
 import com.google.gerrit.server.project.SectionSortCache;
+import com.google.gerrit.server.project.SubmitRuleEvaluator;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.server.query.change.ChangeQueryProcessor;
 import com.google.gerrit.server.update.BatchUpdate;
@@ -167,6 +168,7 @@
     factory(CapabilityCollection.Factory.class);
     factory(ChangeData.AssistedFactory.class);
     factory(ProjectState.Factory.class);
+    factory(SubmitRuleEvaluator.Factory.class);
 
     bind(ChangeJson.Factory.class).toProvider(Providers.<ChangeJson.Factory>of(null));
     bind(AccountVisibility.class).toProvider(AccountVisibilityProvider.class).in(SINGLETON);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Mergeable.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Mergeable.java
index 929529d..8e0d9d9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Mergeable.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Mergeable.java
@@ -26,9 +26,6 @@
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.reviewdb.server.ReviewDbUtil;
 import com.google.gerrit.server.ChangeUtil;
-import com.google.gerrit.server.account.AccountCache;
-import com.google.gerrit.server.account.Accounts;
-import com.google.gerrit.server.account.Emails;
 import com.google.gerrit.server.git.BranchOrderSection;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.MergeUtil;
@@ -64,38 +61,32 @@
   private boolean otherBranches;
 
   private final GitRepositoryManager gitManager;
-  private final AccountCache accountCache;
-  private final Accounts accounts;
-  private final Emails emails;
   private final ProjectCache projectCache;
   private final MergeUtil.Factory mergeUtilFactory;
   private final ChangeData.Factory changeDataFactory;
   private final Provider<ReviewDb> db;
   private final ChangeIndexer indexer;
   private final MergeabilityCache cache;
+  private final SubmitRuleEvaluator.Factory submitRuleEvaluatorFactory;
 
   @Inject
   Mergeable(
       GitRepositoryManager gitManager,
-      AccountCache accountCache,
-      Accounts accounts,
-      Emails emails,
       ProjectCache projectCache,
       MergeUtil.Factory mergeUtilFactory,
       ChangeData.Factory changeDataFactory,
       Provider<ReviewDb> db,
       ChangeIndexer indexer,
-      MergeabilityCache cache) {
+      MergeabilityCache cache,
+      SubmitRuleEvaluator.Factory submitRuleEvaluatorFactory) {
     this.gitManager = gitManager;
-    this.accountCache = accountCache;
-    this.accounts = accounts;
-    this.emails = emails;
     this.projectCache = projectCache;
     this.mergeUtilFactory = mergeUtilFactory;
     this.changeDataFactory = changeDataFactory;
     this.db = db;
     this.indexer = indexer;
     this.cache = cache;
+    this.submitRuleEvaluatorFactory = submitRuleEvaluatorFactory;
   }
 
   public void setOtherBranches(boolean otherBranches) {
@@ -152,9 +143,7 @@
 
   private SubmitType getSubmitType(ChangeData cd, PatchSet patchSet) throws OrmException {
     SubmitTypeRecord rec =
-        new SubmitRuleEvaluator(accountCache, accounts, emails, cd)
-            .setPatchSet(patchSet)
-            .getSubmitType();
+        submitRuleEvaluatorFactory.create(cd).setPatchSet(patchSet).getSubmitType();
     if (rec.status != SubmitTypeRecord.Status.OK) {
       throw new OrmException("Submit type rule failed: " + rec);
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerJson.java
index 9b1a5dc..4b2f5b7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerJson.java
@@ -27,10 +27,7 @@
 import com.google.gerrit.reviewdb.client.PatchSetApproval;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.ApprovalsUtil;
-import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.account.AccountLoader;
-import com.google.gerrit.server.account.Accounts;
-import com.google.gerrit.server.account.Emails;
 import com.google.gerrit.server.permissions.LabelPermission;
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.permissions.PermissionBackendException;
@@ -49,30 +46,24 @@
   private final Provider<ReviewDb> db;
   private final PermissionBackend permissionBackend;
   private final ChangeData.Factory changeDataFactory;
-  private final AccountCache accountCache;
-  private final Accounts accounts;
-  private final Emails emails;
   private final ApprovalsUtil approvalsUtil;
   private final AccountLoader.Factory accountLoaderFactory;
+  private final SubmitRuleEvaluator.Factory submitRuleEvaluatorFactory;
 
   @Inject
   ReviewerJson(
       Provider<ReviewDb> db,
       PermissionBackend permissionBackend,
       ChangeData.Factory changeDataFactory,
-      AccountCache accountCache,
-      Accounts accounts,
-      Emails emails,
       ApprovalsUtil approvalsUtil,
-      AccountLoader.Factory accountLoaderFactory) {
+      AccountLoader.Factory accountLoaderFactory,
+      SubmitRuleEvaluator.Factory submitRuleEvaluatorFactory) {
     this.db = db;
     this.permissionBackend = permissionBackend;
     this.changeDataFactory = changeDataFactory;
-    this.accountCache = accountCache;
-    this.accounts = accounts;
-    this.emails = emails;
     this.approvalsUtil = approvalsUtil;
     this.accountLoaderFactory = accountLoaderFactory;
+    this.submitRuleEvaluatorFactory = submitRuleEvaluatorFactory;
   }
 
   public List<ReviewerInfo> format(Collection<ReviewerResource> rsrcs)
@@ -133,7 +124,8 @@
     PatchSet ps = cd.currentPatchSet();
     if (ps != null) {
       for (SubmitRecord rec :
-          new SubmitRuleEvaluator(accountCache, accounts, emails, cd)
+          submitRuleEvaluatorFactory
+              .create(cd)
               .setFastEvalLabels(true)
               .setAllowDraft(true)
               .evaluate()) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitRule.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitRule.java
index ad716e6..371c796 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitRule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitRule.java
@@ -24,10 +24,7 @@
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.rules.RulesCache;
-import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.account.AccountLoader;
-import com.google.gerrit.server.account.Accounts;
-import com.google.gerrit.server.account.Emails;
 import com.google.gerrit.server.project.SubmitRuleEvaluator;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gwtorm.server.OrmException;
@@ -42,10 +39,8 @@
   private final Provider<ReviewDb> db;
   private final ChangeData.Factory changeDataFactory;
   private final RulesCache rules;
-  private final AccountCache accountCache;
   private final AccountLoader.Factory accountInfoFactory;
-  private final Accounts accounts;
-  private final Emails emails;
+  private final SubmitRuleEvaluator.Factory submitRuleEvaluatorFactory;
 
   @Option(name = "--filters", usage = "impact of filters in parent projects")
   private Filters filters = Filters.RUN;
@@ -55,17 +50,13 @@
       Provider<ReviewDb> db,
       ChangeData.Factory changeDataFactory,
       RulesCache rules,
-      AccountCache accountCache,
       AccountLoader.Factory infoFactory,
-      Accounts accounts,
-      Emails emails) {
+      SubmitRuleEvaluator.Factory submitRuleEvaluatorFactory) {
     this.db = db;
     this.changeDataFactory = changeDataFactory;
     this.rules = rules;
-    this.accountCache = accountCache;
     this.accountInfoFactory = infoFactory;
-    this.accounts = accounts;
-    this.emails = emails;
+    this.submitRuleEvaluatorFactory = submitRuleEvaluatorFactory;
   }
 
   @Override
@@ -79,10 +70,7 @@
     }
     input.filters = MoreObjects.firstNonNull(input.filters, filters);
     SubmitRuleEvaluator evaluator =
-        new SubmitRuleEvaluator(
-            accountCache,
-            accounts,
-            emails,
+        submitRuleEvaluatorFactory.create(
             changeDataFactory.create(db.get(), rsrc.getChangeResource()));
 
     List<SubmitRecord> records =
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitType.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitType.java
index 48b657e..0dd1019 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitType.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitType.java
@@ -25,9 +25,6 @@
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.rules.RulesCache;
-import com.google.gerrit.server.account.AccountCache;
-import com.google.gerrit.server.account.Accounts;
-import com.google.gerrit.server.account.Emails;
 import com.google.gerrit.server.project.SubmitRuleEvaluator;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gwtorm.server.OrmException;
@@ -37,11 +34,9 @@
 
 public class TestSubmitType implements RestModifyView<RevisionResource, TestSubmitRuleInput> {
   private final Provider<ReviewDb> db;
-  private final AccountCache accountCache;
-  private final Accounts accounts;
-  private final Emails emails;
   private final ChangeData.Factory changeDataFactory;
   private final RulesCache rules;
+  private final SubmitRuleEvaluator.Factory submitRuleEvaluatorFactory;
 
   @Option(name = "--filters", usage = "impact of filters in parent projects")
   private Filters filters = Filters.RUN;
@@ -49,17 +44,13 @@
   @Inject
   TestSubmitType(
       Provider<ReviewDb> db,
-      AccountCache accountCache,
-      Accounts accounts,
-      Emails emails,
       ChangeData.Factory changeDataFactory,
-      RulesCache rules) {
+      RulesCache rules,
+      SubmitRuleEvaluator.Factory submitRuleEvaluatorFactory) {
     this.db = db;
-    this.accountCache = accountCache;
-    this.accounts = accounts;
-    this.emails = emails;
     this.changeDataFactory = changeDataFactory;
     this.rules = rules;
+    this.submitRuleEvaluatorFactory = submitRuleEvaluatorFactory;
   }
 
   @Override
@@ -73,10 +64,7 @@
     }
     input.filters = MoreObjects.firstNonNull(input.filters, filters);
     SubmitRuleEvaluator evaluator =
-        new SubmitRuleEvaluator(
-            accountCache,
-            accounts,
-            emails,
+        submitRuleEvaluatorFactory.create(
             changeDataFactory.create(db.get(), rsrc.getChangeResource()));
 
     SubmitTypeRecord rec =
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
index 9073b41..8751787 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -166,6 +166,7 @@
 import com.google.gerrit.server.project.ProjectNode;
 import com.google.gerrit.server.project.ProjectState;
 import com.google.gerrit.server.project.SectionSortCache;
+import com.google.gerrit.server.project.SubmitRuleEvaluator;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.server.query.change.ChangeQueryBuilder;
 import com.google.gerrit.server.query.change.ChangeQueryProcessor;
@@ -264,6 +265,7 @@
     bind(PermissionCollection.Factory.class);
     bind(AccountVisibility.class).toProvider(AccountVisibilityProvider.class).in(SINGLETON);
     factory(ProjectOwnerGroupsProvider.Factory.class);
+    factory(SubmitRuleEvaluator.Factory.class);
 
     bind(AuthBackend.class).to(UniversalAuthBackend.class).in(SINGLETON);
     DynamicSet.setOf(binder(), AuthBackend.class);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeSuperSet.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeSuperSet.java
index 978ef3e..85e5d06 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeSuperSet.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeSuperSet.java
@@ -31,9 +31,6 @@
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.account.AccountCache;
-import com.google.gerrit.server.account.Accounts;
-import com.google.gerrit.server.account.Emails;
 import com.google.gerrit.server.change.Submit;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.git.MergeOpRepoManager.OpenRepo;
@@ -100,9 +97,6 @@
     abstract ImmutableSet<String> hashes();
   }
 
-  private final AccountCache accountCache;
-  private final Accounts accounts;
-  private final Emails emails;
   private final ChangeData.Factory changeDataFactory;
   private final Provider<InternalChangeQuery> queryProvider;
   private final Provider<MergeOpRepoManager> repoManagerProvider;
@@ -110,6 +104,7 @@
   private final Config cfg;
   private final Map<QueryKey, List<ChangeData>> queryCache;
   private final Map<Branch.NameKey, Optional<RevCommit>> heads;
+  private final SubmitRuleEvaluator.Factory submitRuleEvaluatorFactory;
 
   private MergeOpRepoManager orm;
   private boolean closeOrm;
@@ -117,21 +112,17 @@
   @Inject
   MergeSuperSet(
       @GerritServerConfig Config cfg,
-      AccountCache accountCache,
-      Accounts accounts,
-      Emails emails,
       ChangeData.Factory changeDataFactory,
       Provider<InternalChangeQuery> queryProvider,
       Provider<MergeOpRepoManager> repoManagerProvider,
-      PermissionBackend permissionBackend) {
+      PermissionBackend permissionBackend,
+      SubmitRuleEvaluator.Factory submitRuleEvaluatorFactory) {
     this.cfg = cfg;
-    this.accountCache = accountCache;
-    this.accounts = accounts;
-    this.emails = emails;
     this.changeDataFactory = changeDataFactory;
     this.queryProvider = queryProvider;
     this.repoManagerProvider = repoManagerProvider;
     this.permissionBackend = permissionBackend;
+    this.submitRuleEvaluatorFactory = submitRuleEvaluatorFactory;
     queryCache = new HashMap<>();
     heads = new HashMap<>();
   }
@@ -181,9 +172,7 @@
     SubmitTypeRecord str =
         ps == cd.currentPatchSet()
             ? cd.submitTypeRecord()
-            : new SubmitRuleEvaluator(accountCache, accounts, emails, cd)
-                .setPatchSet(ps)
-                .getSubmitType();
+            : submitRuleEvaluatorFactory.create(cd).setPatchSet(ps).getSubmitType();
     if (!str.isOk()) {
       logErrorAndThrow("Failed to get submit type for " + cd.getId() + ": " + str.errorMessage);
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
index 5ab629a..87d10c9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
@@ -32,6 +32,8 @@
 import com.google.gerrit.server.account.Emails;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
 import com.googlecode.prolog_cafe.exceptions.CompileException;
 import com.googlecode.prolog_cafe.exceptions.ReductionLimitException;
 import com.googlecode.prolog_cafe.lang.IntegerTerm;
@@ -84,28 +86,31 @@
     }
   }
 
+  public interface Factory {
+    SubmitRuleEvaluator create(ChangeData cd);
+  }
+
   private final AccountCache accountCache;
   private final Accounts accounts;
   private final Emails emails;
   private final ChangeData cd;
-  private final ChangeControl control;
 
   private SubmitRuleOptions.Builder optsBuilder = SubmitRuleOptions.defaults();
   private SubmitRuleOptions opts;
   private PatchSet patchSet;
   private boolean logErrors = true;
   private long reductionsConsumed;
+  private ChangeControl control;
 
   private Term submitRule;
 
-  public SubmitRuleEvaluator(
-      AccountCache accountCache, Accounts accounts, Emails emails, ChangeData cd)
-      throws OrmException {
+  @Inject
+  SubmitRuleEvaluator(
+      AccountCache accountCache, Accounts accounts, Emails emails, @Assisted ChangeData cd) {
     this.accountCache = accountCache;
     this.accounts = accounts;
     this.emails = emails;
     this.cd = cd;
-    this.control = cd.changeControl();
   }
 
   /**
@@ -219,6 +224,12 @@
    */
   public List<SubmitRecord> evaluate() {
     initOptions();
+    try {
+      initChange();
+    } catch (OrmException e) {
+      return ruleError("Error looking up change " + cd.getId(), e);
+    }
+
     Change c = control.getChange();
     if (!opts.allowClosed() && c.getStatus().isClosed()) {
       SubmitRecord rec = new SubmitRecord();
@@ -226,12 +237,6 @@
       return Collections.singletonList(rec);
     }
     if (!opts.allowDraft()) {
-      try {
-        initPatchSet();
-      } catch (OrmException e) {
-        return ruleError(
-            "Error looking up patch set " + control.getChange().currentPatchSetId(), e);
-      }
       if (c.getStatus() == Change.Status.DRAFT || patchSet.isDraft()) {
         return cannotSubmitDraft();
       }
@@ -409,9 +414,9 @@
   public SubmitTypeRecord getSubmitType() {
     initOptions();
     try {
-      initPatchSet();
+      initChange();
     } catch (OrmException e) {
-      return typeError("Error looking up patch set " + control.getChange().currentPatchSetId(), e);
+      return typeError("Error looking up change " + cd.getId(), e);
     }
 
     try {
@@ -679,7 +684,11 @@
     }
   }
 
-  private void initPatchSet() throws OrmException {
+  private void initChange() throws OrmException {
+    if (control == null) {
+      control = cd.changeControl();
+    }
+
     if (patchSet == null) {
       patchSet = cd.currentPatchSet();
       if (patchSet == null) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
index b750019..2a3ff45 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
@@ -59,9 +59,6 @@
 import com.google.gerrit.server.ReviewerStatusUpdate;
 import com.google.gerrit.server.StarredChangesUtil;
 import com.google.gerrit.server.StarredChangesUtil.StarRef;
-import com.google.gerrit.server.account.AccountCache;
-import com.google.gerrit.server.account.Accounts;
-import com.google.gerrit.server.account.Emails;
 import com.google.gerrit.server.change.ChangeResource;
 import com.google.gerrit.server.change.GetPureRevert;
 import com.google.gerrit.server.change.MergeabilityCache;
@@ -352,22 +349,19 @@
     ChangeData cd =
         new ChangeData(
             null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-            null, null, null, null, null, null, null, project, id, null, null, null);
+            null, null, null, null, null, project, id, null, null, null);
     cd.currentPatchSet = new PatchSet(new PatchSet.Id(id, currentPatchSetId));
     return cd;
   }
 
   // Injected fields.
   private @Nullable final StarredChangesUtil starredChangesUtil;
-  private final AccountCache accountCache;
-  private final Accounts accounts;
   private final AllUsersName allUsersName;
   private final ApprovalsUtil approvalsUtil;
   private final ChangeControl.GenericFactory changeControlFactory;
   private final ChangeMessagesUtil cmUtil;
   private final ChangeNotes.Factory notesFactory;
   private final CommentsUtil commentsUtil;
-  private final Emails emails;
   private final GitRepositoryManager repoManager;
   private final IdentifiedUser.GenericFactory userFactory;
   private final MergeUtil.Factory mergeUtilFactory;
@@ -378,6 +372,7 @@
   private final ProjectCache projectCache;
   private final TrackingFooters trackingFooters;
   private final GetPureRevert pureRevert;
+  private final SubmitRuleEvaluator.Factory submitRuleEvaluatorFactory;
 
   // Required assisted injected fields.
   private final ReviewDb db;
@@ -431,15 +426,12 @@
   @Inject
   private ChangeData(
       @Nullable StarredChangesUtil starredChangesUtil,
-      AccountCache accountCache,
-      Accounts accounts,
       ApprovalsUtil approvalsUtil,
       AllUsersName allUsersName,
       ChangeControl.GenericFactory changeControlFactory,
       ChangeMessagesUtil cmUtil,
       ChangeNotes.Factory notesFactory,
       CommentsUtil commentsUtil,
-      Emails emails,
       GitRepositoryManager repoManager,
       IdentifiedUser.GenericFactory userFactory,
       MergeUtil.Factory mergeUtilFactory,
@@ -450,21 +442,19 @@
       ProjectCache projectCache,
       TrackingFooters trackingFooters,
       GetPureRevert pureRevert,
+      SubmitRuleEvaluator.Factory submitRuleEvaluatorFactory,
       @Assisted ReviewDb db,
       @Assisted Project.NameKey project,
       @Assisted Change.Id id,
       @Assisted @Nullable Change change,
       @Assisted @Nullable ChangeNotes notes,
       @Assisted @Nullable ChangeControl control) {
-    this.accountCache = accountCache;
-    this.accounts = accounts;
     this.approvalsUtil = approvalsUtil;
     this.allUsersName = allUsersName;
     this.changeControlFactory = changeControlFactory;
     this.cmUtil = cmUtil;
     this.notesFactory = notesFactory;
     this.commentsUtil = commentsUtil;
-    this.emails = emails;
     this.repoManager = repoManager;
     this.userFactory = userFactory;
     this.mergeUtilFactory = mergeUtilFactory;
@@ -476,6 +466,7 @@
     this.starredChangesUtil = starredChangesUtil;
     this.trackingFooters = trackingFooters;
     this.pureRevert = pureRevert;
+    this.submitRuleEvaluatorFactory = submitRuleEvaluatorFactory;
 
     // May be null in tests when created via createForTest above, in which case lazy-loading will
     // intentionally fail with NPE. Still not marked @Nullable in the constructor, to force callers
@@ -1032,10 +1023,7 @@
       if (!lazyLoad) {
         return Collections.emptyList();
       }
-      records =
-          new SubmitRuleEvaluator(accountCache, accounts, emails, this)
-              .setOptions(options)
-              .evaluate();
+      records = submitRuleEvaluatorFactory.create(this).setOptions(options).evaluate();
       submitRecords.put(options, records);
     }
     return records;
@@ -1052,8 +1040,7 @@
 
   public SubmitTypeRecord submitTypeRecord() throws OrmException {
     if (submitTypeRecord == null) {
-      submitTypeRecord =
-          new SubmitRuleEvaluator(accountCache, accounts, emails, this).getSubmitType();
+      submitTypeRecord = submitRuleEvaluatorFactory.create(this).getSubmitType();
     }
     return submitTypeRecord;
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OutputStreamQuery.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OutputStreamQuery.java
index 7b53a30..1fe982f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OutputStreamQuery.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OutputStreamQuery.java
@@ -25,9 +25,6 @@
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.account.AccountCache;
-import com.google.gerrit.server.account.Accounts;
-import com.google.gerrit.server.account.Emails;
 import com.google.gerrit.server.config.TrackingFooters;
 import com.google.gerrit.server.data.ChangeAttribute;
 import com.google.gerrit.server.data.PatchSetAttribute;
@@ -75,15 +72,13 @@
   }
 
   private final ReviewDb db;
-  private final AccountCache accountCache;
-  private final Accounts accounts;
-  private final Emails emails;
   private final GitRepositoryManager repoManager;
   private final ChangeQueryBuilder queryBuilder;
   private final ChangeQueryProcessor queryProcessor;
   private final EventFactory eventFactory;
   private final TrackingFooters trackingFooters;
   private final CurrentUser user;
+  private final SubmitRuleEvaluator.Factory submitRuleEvaluatorFactory;
 
   private OutputFormat outputFormat = OutputFormat.TEXT;
   private boolean includePatchSets;
@@ -102,25 +97,21 @@
   @Inject
   OutputStreamQuery(
       ReviewDb db,
-      AccountCache accountCache,
-      Accounts accounts,
-      Emails emails,
       GitRepositoryManager repoManager,
       ChangeQueryBuilder queryBuilder,
       ChangeQueryProcessor queryProcessor,
       EventFactory eventFactory,
       TrackingFooters trackingFooters,
-      CurrentUser user) {
+      CurrentUser user,
+      SubmitRuleEvaluator.Factory submitRuleEvaluatorFactory) {
     this.db = db;
-    this.accountCache = accountCache;
-    this.accounts = accounts;
-    this.emails = emails;
     this.repoManager = repoManager;
     this.queryBuilder = queryBuilder;
     this.queryProcessor = queryProcessor;
     this.eventFactory = eventFactory;
     this.trackingFooters = trackingFooters;
     this.user = user;
+    this.submitRuleEvaluatorFactory = submitRuleEvaluatorFactory;
   }
 
   void setLimit(int n) {
@@ -259,10 +250,7 @@
     if (includeSubmitRecords) {
       eventFactory.addSubmitRecords(
           c,
-          new SubmitRuleEvaluator(accountCache, accounts, emails, d)
-              .setAllowClosed(true)
-              .setAllowDraft(true)
-              .evaluate());
+          submitRuleEvaluatorFactory.create(d).setAllowClosed(true).setAllowDraft(true).evaluate());
     }
 
     if (includeCommitMessage) {