Merge branch 'stable-2.13'

* stable-2.13:
  DynamicSet: Disable circular proxies on binder
  StreamEventsApiListener: Extend module from AbstractModule
  QueryProcessor: Add missing space in exception message
  ProjectConfig: resolve rule's group when saving access
  ProjectConfig: resolve rule's group when loading permission rules

Change-Id: I21a17c81b87a4ee450d9a92447ba38bacc02479f
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSet.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSet.java
index 28052ef..6eb11bc 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSet.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSet.java
@@ -53,6 +53,7 @@
    * @param member type of entry in the set.
    */
   public static <T> void setOf(Binder binder, Class<T> member) {
+    binder.disableCircularProxies();
     setOf(binder, TypeLiteral.get(member));
   }
 
@@ -71,6 +72,7 @@
     @SuppressWarnings("unchecked")
     Key<DynamicSet<T>> key = (Key<DynamicSet<T>>) Key.get(
         Types.newParameterizedType(DynamicSet.class, member.getType()));
+    binder.disableCircularProxies();
     binder.bind(key)
       .toProvider(new DynamicSetProvider<>(member))
       .in(Scopes.SINGLETON);
@@ -84,6 +86,7 @@
    * @return a binder to continue configuring the new set member.
    */
   public static <T> LinkedBindingBuilder<T> bind(Binder binder, Class<T> type) {
+    binder.disableCircularProxies();
     return bind(binder, TypeLiteral.get(type));
   }
 
@@ -95,6 +98,7 @@
    * @return a binder to continue configuring the new set member.
    */
   public static <T> LinkedBindingBuilder<T> bind(Binder binder, TypeLiteral<T> type) {
+    binder.disableCircularProxies();
     return binder.bind(type).annotatedWith(UniqueAnnotations.create());
   }
 
@@ -110,6 +114,7 @@
   public static <T> LinkedBindingBuilder<T> bind(Binder binder,
       Class<T> type,
       Named name) {
+    binder.disableCircularProxies();
     return bind(binder, TypeLiteral.get(type));
   }
 
@@ -125,6 +130,7 @@
   public static <T> LinkedBindingBuilder<T> bind(Binder binder,
       TypeLiteral<T> type,
       Named name) {
+    binder.disableCircularProxies();
     return binder.bind(type).annotatedWith(name);
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/events/StreamEventsApiListener.java b/gerrit-server/src/main/java/com/google/gerrit/server/events/StreamEventsApiListener.java
index 85098d4d..c867d26 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/events/StreamEventsApiListener.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/events/StreamEventsApiListener.java
@@ -39,7 +39,6 @@
 import com.google.gerrit.extensions.events.TopicEditedListener;
 import com.google.gerrit.extensions.registration.DynamicItem;
 import com.google.gerrit.extensions.registration.DynamicSet;
-import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Branch;
 import com.google.gerrit.reviewdb.client.Change;
@@ -56,6 +55,7 @@
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gwtorm.server.OrmException;
+import com.google.inject.AbstractModule;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
@@ -90,7 +90,7 @@
   private static final Logger log =
       LoggerFactory.getLogger(StreamEventsApiListener.class);
 
-  public static class Module extends LifecycleModule {
+  public static class Module extends AbstractModule {
     @Override
     protected void configure() {
       DynamicSet.bind(binder(), AssigneeChangedListener.class)
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
index 1429079..801f259 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
@@ -713,7 +713,7 @@
         // no valid UUID for it. Pool the reference anyway so at least
         // all rules in the same file share the same GroupReference.
         //
-        ref = rule.getGroup();
+        ref = resolve(rule.getGroup());
         groupsByName.put(ref.getName(), ref);
         error(new ValidationError(PROJECT_CONFIG,
             "group \"" + ref.getName() + "\" not in " + GroupList.FILE_NAME));
@@ -1098,7 +1098,7 @@
         boolean needRange = GlobalCapability.hasRange(permission.getName());
         List<String> rules = new ArrayList<>();
         for (PermissionRule rule : sort(permission.getRules())) {
-          GroupReference group = rule.getGroup();
+          GroupReference group = resolve(rule.getGroup());
           if (group.getUUID() != null) {
             keepGroups.add(group.getUUID());
           }
@@ -1143,7 +1143,7 @@
         boolean needRange = Permission.hasRange(permission.getName());
         List<String> rules = new ArrayList<>();
         for (PermissionRule rule : sort(permission.getRules())) {
-          GroupReference group = rule.getGroup();
+          GroupReference group = resolve(rule.getGroup());
           if (group.getUUID() != null) {
             keepGroups.add(group.getUUID());
           }