Merge "InternalQuery: Cast setter return types to specific subtype"
diff --git a/java/com/google/gerrit/index/query/InternalQuery.java b/java/com/google/gerrit/index/query/InternalQuery.java
index 3a4b372..0b5088d 100644
--- a/java/com/google/gerrit/index/query/InternalQuery.java
+++ b/java/com/google/gerrit/index/query/InternalQuery.java
@@ -38,7 +38,7 @@
  * <p>Instances are one-time-use. Other singleton classes should inject a Provider rather than
  * holding on to a single instance.
  */
-public class InternalQuery<T> {
+public class InternalQuery<T, Q extends InternalQuery<T, Q>> {
   private final QueryProcessor<T> queryProcessor;
   private final IndexCollection<?, T, ? extends Index<?, T>> indexes;
 
@@ -53,30 +53,35 @@
     this.indexConfig = indexConfig;
   }
 
-  public InternalQuery<T> setLimit(int n) {
+  @SuppressWarnings("unchecked")
+  protected final Q self() {
+    return (Q) this;
+  }
+
+  public final Q setLimit(int n) {
     queryProcessor.setUserProvidedLimit(n);
-    return this;
+    return self();
   }
 
-  public InternalQuery<T> enforceVisibility(boolean enforce) {
+  public final Q enforceVisibility(boolean enforce) {
     queryProcessor.enforceVisibility(enforce);
-    return this;
+    return self();
   }
 
-  @SuppressWarnings("unchecked") // Can't set @SafeVarargs on a non-final method.
-  public InternalQuery<T> setRequestedFields(FieldDef<T, ?>... fields) {
+  @SafeVarargs
+  public final Q setRequestedFields(FieldDef<T, ?>... fields) {
     checkArgument(fields.length > 0, "requested field list is empty");
     queryProcessor.setRequestedFields(
         Arrays.stream(fields).map(FieldDef::getName).collect(toSet()));
-    return this;
+    return self();
   }
 
-  public InternalQuery<T> noFields() {
+  public final Q noFields() {
     queryProcessor.setRequestedFields(ImmutableSet.of());
-    return this;
+    return self();
   }
 
-  public List<T> query(Predicate<T> p) throws OrmException {
+  public final List<T> query(Predicate<T> p) throws OrmException {
     try {
       return queryProcessor.query(p).entities();
     } catch (QueryParseException e) {
@@ -94,7 +99,7 @@
    * @return results of the queries, one list of results per input query, in the same order as the
    *     input.
    */
-  public List<List<T>> query(List<Predicate<T>> queries) throws OrmException {
+  public final List<List<T>> query(List<Predicate<T>> queries) throws OrmException {
     try {
       return Lists.transform(queryProcessor.query(queries), QueryResult::entities);
     } catch (QueryParseException e) {
@@ -102,7 +107,7 @@
     }
   }
 
-  protected Schema<T> schema() {
+  protected final Schema<T> schema() {
     Index<?, T> index = indexes != null ? indexes.getSearchIndex() : null;
     return index != null ? index.getSchema() : null;
   }
diff --git a/java/com/google/gerrit/server/query/account/InternalAccountQuery.java b/java/com/google/gerrit/server/query/account/InternalAccountQuery.java
index d0840d6..6f3194e 100644
--- a/java/com/google/gerrit/server/query/account/InternalAccountQuery.java
+++ b/java/com/google/gerrit/server/query/account/InternalAccountQuery.java
@@ -42,7 +42,7 @@
  * <p>Instances are one-time-use. Other singleton classes should inject a Provider rather than
  * holding on to a single instance.
  */
-public class InternalAccountQuery extends InternalQuery<AccountState> {
+public class InternalAccountQuery extends InternalQuery<AccountState, InternalAccountQuery> {
   @Inject
   InternalAccountQuery(
       AccountQueryProcessor queryProcessor,
@@ -51,31 +51,6 @@
     super(queryProcessor, indexes, indexConfig);
   }
 
-  @Override
-  public InternalAccountQuery setLimit(int n) {
-    super.setLimit(n);
-    return this;
-  }
-
-  @Override
-  public InternalAccountQuery enforceVisibility(boolean enforce) {
-    super.enforceVisibility(enforce);
-    return this;
-  }
-
-  @SafeVarargs
-  @Override
-  public final InternalAccountQuery setRequestedFields(FieldDef<AccountState, ?>... fields) {
-    super.setRequestedFields(fields);
-    return this;
-  }
-
-  @Override
-  public InternalAccountQuery noFields() {
-    super.noFields();
-    return this;
-  }
-
   public List<AccountState> byDefault(String query) throws OrmException {
     return query(AccountPredicates.defaultPredicate(schema(), true, query));
   }
diff --git a/java/com/google/gerrit/server/query/change/InternalChangeQuery.java b/java/com/google/gerrit/server/query/change/InternalChangeQuery.java
index dc89c88..f53e663 100644
--- a/java/com/google/gerrit/server/query/change/InternalChangeQuery.java
+++ b/java/com/google/gerrit/server/query/change/InternalChangeQuery.java
@@ -25,7 +25,6 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
-import com.google.gerrit.index.FieldDef;
 import com.google.gerrit.index.IndexConfig;
 import com.google.gerrit.index.query.InternalQuery;
 import com.google.gerrit.index.query.Predicate;
@@ -55,7 +54,7 @@
  * <p>Instances are one-time-use. Other singleton classes should inject a Provider rather than
  * holding on to a single instance.
  */
-public class InternalChangeQuery extends InternalQuery<ChangeData> {
+public class InternalChangeQuery extends InternalQuery<ChangeData, InternalChangeQuery> {
   private static Predicate<ChangeData> ref(Branch.NameKey branch) {
     return new RefPredicate(branch.get());
   }
@@ -91,31 +90,6 @@
     this.notesFactory = notesFactory;
   }
 
-  @Override
-  public InternalChangeQuery setLimit(int n) {
-    super.setLimit(n);
-    return this;
-  }
-
-  @Override
-  public InternalChangeQuery enforceVisibility(boolean enforce) {
-    super.enforceVisibility(enforce);
-    return this;
-  }
-
-  @SafeVarargs
-  @Override
-  public final InternalChangeQuery setRequestedFields(FieldDef<ChangeData, ?>... fields) {
-    super.setRequestedFields(fields);
-    return this;
-  }
-
-  @Override
-  public InternalChangeQuery noFields() {
-    super.noFields();
-    return this;
-  }
-
   public List<ChangeData> byKey(Change.Key key) throws OrmException {
     return byKeyPrefix(key.get());
   }
diff --git a/java/com/google/gerrit/server/query/group/InternalGroupQuery.java b/java/com/google/gerrit/server/query/group/InternalGroupQuery.java
index d9808f2..42b38bf 100644
--- a/java/com/google/gerrit/server/query/group/InternalGroupQuery.java
+++ b/java/com/google/gerrit/server/query/group/InternalGroupQuery.java
@@ -37,7 +37,7 @@
  * <p>Instances are one-time-use. Other singleton classes should inject a Provider rather than
  * holding on to a single instance.
  */
-public class InternalGroupQuery extends InternalQuery<InternalGroup> {
+public class InternalGroupQuery extends InternalQuery<InternalGroup, InternalGroupQuery> {
   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
   @Inject