Merge "Update highlight.js build documentation"
diff --git a/Documentation/dev-bazel.txt b/Documentation/dev-bazel.txt
index 8b4bece..979d021 100644
--- a/Documentation/dev-bazel.txt
+++ b/Documentation/dev-bazel.txt
@@ -41,8 +41,7 @@
 
 === Gerrit Development WAR File
 
-To build the Gerrit web application that includes the GWT UI and the
-PolyGerrit UI:
+To build the Gerrit web application that includes the PolyGerrit UI:
 
 ----
   bazel build gerrit
@@ -76,7 +75,8 @@
 
 === Headless Mode
 
-To build Gerrit in headless mode, i.e. without the GWT Web UI:
+To build Gerrit in headless mode, i.e. without the PolyGerrit and GWT
+Web UI:
 
 ----
   bazel build headless
diff --git a/Documentation/json.txt b/Documentation/json.txt
index 3b8a8cb..dc82ad1 100644
--- a/Documentation/json.txt
+++ b/Documentation/json.txt
@@ -29,6 +29,8 @@
 commitMessage:: The full commit message for the change's current patch
 set.
 
+hashtags:: List of hashtags associated with this change.
+
 createdOn:: Time in seconds since the UNIX epoch when this change
 was created.
 
diff --git a/java/com/google/gerrit/acceptance/RestSession.java b/java/com/google/gerrit/acceptance/RestSession.java
index 300e75f..ae921a5 100644
--- a/java/com/google/gerrit/acceptance/RestSession.java
+++ b/java/com/google/gerrit/acceptance/RestSession.java
@@ -116,10 +116,10 @@
   }
 
   public RestResponse post(String endPoint, Object content) throws IOException {
-    return postWithHeader(endPoint, content, null);
+    return postWithHeader(endPoint, null, content);
   }
 
-  public RestResponse postWithHeader(String endPoint, Object content, Header header)
+  public RestResponse postWithHeader(String endPoint, Header header, Object content)
       throws IOException {
     Request post = Request.Post(getUrl(endPoint));
     if (header != null) {
diff --git a/java/com/google/gerrit/pgm/BUILD b/java/com/google/gerrit/pgm/BUILD
index 64dd1d8..ba27991 100644
--- a/java/com/google/gerrit/pgm/BUILD
+++ b/java/com/google/gerrit/pgm/BUILD
@@ -40,6 +40,7 @@
         "//java/com/google/gerrit/server/cache/h2",
         "//java/com/google/gerrit/server/cache/mem",
         "//java/com/google/gerrit/server/git/receive",
+        "//java/com/google/gerrit/server/ioutil",
         "//java/com/google/gerrit/server/restapi",
         "//java/com/google/gerrit/server/schema",
         "//java/com/google/gerrit/sshd",
diff --git a/java/com/google/gerrit/pgm/Init.java b/java/com/google/gerrit/pgm/Init.java
index b9c7068..a93e64c 100644
--- a/java/com/google/gerrit/pgm/Init.java
+++ b/java/com/google/gerrit/pgm/Init.java
@@ -26,8 +26,8 @@
 import com.google.gerrit.pgm.util.ErrorLogFile;
 import com.google.gerrit.server.config.GerritServerConfigModule;
 import com.google.gerrit.server.config.SitePath;
+import com.google.gerrit.server.ioutil.HostPlatform;
 import com.google.gerrit.server.securestore.SecureStoreClassName;
-import com.google.gerrit.server.util.HostPlatform;
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Inject;
diff --git a/java/com/google/gerrit/pgm/init/BUILD b/java/com/google/gerrit/pgm/init/BUILD
index c781a60..8a1c08b 100644
--- a/java/com/google/gerrit/pgm/init/BUILD
+++ b/java/com/google/gerrit/pgm/init/BUILD
@@ -17,6 +17,7 @@
         "//java/com/google/gerrit/pgm/util",
         "//java/com/google/gerrit/reviewdb:server",
         "//java/com/google/gerrit/server",
+        "//java/com/google/gerrit/server/ioutil",
         "//java/com/google/gerrit/server/schema",
         "//lib:guava",
         "//lib:gwtjsonrpc",
diff --git a/java/com/google/gerrit/pgm/init/InitSshd.java b/java/com/google/gerrit/pgm/init/InitSshd.java
index d2e280d..0cc30f8 100644
--- a/java/com/google/gerrit/pgm/init/InitSshd.java
+++ b/java/com/google/gerrit/pgm/init/InitSshd.java
@@ -21,7 +21,7 @@
 import com.google.gerrit.pgm.init.api.InitStep;
 import com.google.gerrit.pgm.init.api.Section;
 import com.google.gerrit.server.config.SitePaths;
-import com.google.gerrit.server.util.HostPlatform;
+import com.google.gerrit.server.ioutil.HostPlatform;
 import com.google.gerrit.server.util.SocketUtil;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
diff --git a/java/com/google/gerrit/server/data/ChangeAttribute.java b/java/com/google/gerrit/server/data/ChangeAttribute.java
index ec76f50..fde5922 100644
--- a/java/com/google/gerrit/server/data/ChangeAttribute.java
+++ b/java/com/google/gerrit/server/data/ChangeAttribute.java
@@ -30,6 +30,7 @@
   public AccountAttribute assignee;
   public String url;
   public String commitMessage;
+  public List<String> hashtags;
 
   public Long createdOn;
   public Long lastUpdated;
diff --git a/java/com/google/gerrit/server/events/EventFactory.java b/java/com/google/gerrit/server/events/EventFactory.java
index f675dd5..75a08bd 100644
--- a/java/com/google/gerrit/server/events/EventFactory.java
+++ b/java/com/google/gerrit/server/events/EventFactory.java
@@ -130,9 +130,9 @@
    * @param change
    * @return object suitable for serialization to JSON
    */
-  public ChangeAttribute asChangeAttribute(Change change) {
+  public ChangeAttribute asChangeAttribute(Change change, ChangeNotes notes) {
     try (ReviewDb db = schema.open()) {
-      return asChangeAttribute(db, change);
+      return asChangeAttribute(db, change, notes);
     } catch (OrmException e) {
       logger.atSevere().withCause(e).log("Cannot open database connection");
       return new ChangeAttribute();
@@ -171,6 +171,24 @@
   }
 
   /**
+   * Create a ChangeAttribute for the given change suitable for serialization to JSON.
+   *
+   * @param db Review database
+   * @param change
+   * @param notes
+   * @return object suitable for serialization to JSON
+   */
+  public ChangeAttribute asChangeAttribute(ReviewDb db, Change change, ChangeNotes notes)
+      throws OrmException {
+    ChangeAttribute a = asChangeAttribute(db, change);
+    Set<String> hashtags = notes.load().getHashtags();
+    if (!hashtags.isEmpty()) {
+      a.hashtags = new ArrayList<String>(hashtags.size());
+      a.hashtags.addAll(hashtags);
+    }
+    return a;
+  }
+  /**
    * Create a RefUpdateAttribute for the given old ObjectId, new ObjectId, and branch that is
    * suitable for serialization to JSON.
    *
diff --git a/java/com/google/gerrit/server/events/StreamEventsApiListener.java b/java/com/google/gerrit/server/events/StreamEventsApiListener.java
index 9592238..7a78055 100644
--- a/java/com/google/gerrit/server/events/StreamEventsApiListener.java
+++ b/java/com/google/gerrit/server/events/StreamEventsApiListener.java
@@ -156,12 +156,12 @@
     return psUtil.get(db.get(), notes, PatchSet.Id.fromRef(info.ref));
   }
 
-  private Supplier<ChangeAttribute> changeAttributeSupplier(Change change) {
+  private Supplier<ChangeAttribute> changeAttributeSupplier(Change change, ChangeNotes notes) {
     return Suppliers.memoize(
         new Supplier<ChangeAttribute>() {
           @Override
           public ChangeAttribute get() {
-            return eventFactory.asChangeAttribute(change);
+            return eventFactory.asChangeAttribute(change, notes);
           }
         });
   }
@@ -257,10 +257,11 @@
   @Override
   public void onAssigneeChanged(AssigneeChangedListener.Event ev) {
     try {
-      Change change = getChange(ev.getChange());
+      ChangeNotes notes = getNotes(ev.getChange());
+      Change change = notes.getChange();
       AssigneeChangedEvent event = new AssigneeChangedEvent(change);
 
-      event.change = changeAttributeSupplier(change);
+      event.change = changeAttributeSupplier(change, notes);
       event.changer = accountAttributeSupplier(ev.getWho());
       event.oldAssignee = accountAttributeSupplier(ev.getOldAssignee());
 
@@ -273,10 +274,11 @@
   @Override
   public void onTopicEdited(TopicEditedListener.Event ev) {
     try {
-      Change change = getChange(ev.getChange());
+      ChangeNotes notes = getNotes(ev.getChange());
+      Change change = notes.getChange();
       TopicChangedEvent event = new TopicChangedEvent(change);
 
-      event.change = changeAttributeSupplier(change);
+      event.change = changeAttributeSupplier(change, notes);
       event.changer = accountAttributeSupplier(ev.getWho());
       event.oldTopic = ev.getOldTopic();
 
@@ -294,7 +296,7 @@
       PatchSet patchSet = getPatchSet(notes, ev.getRevision());
       PatchSetCreatedEvent event = new PatchSetCreatedEvent(change);
 
-      event.change = changeAttributeSupplier(change);
+      event.change = changeAttributeSupplier(change, notes);
       event.patchSet = patchSetAttributeSupplier(change, patchSet);
       event.uploader = accountAttributeSupplier(ev.getWho());
 
@@ -310,7 +312,7 @@
       ChangeNotes notes = getNotes(ev.getChange());
       Change change = notes.getChange();
       ReviewerDeletedEvent event = new ReviewerDeletedEvent(change);
-      event.change = changeAttributeSupplier(change);
+      event.change = changeAttributeSupplier(change, notes);
       event.patchSet = patchSetAttributeSupplier(change, psUtil.current(db.get(), notes));
       event.reviewer = accountAttributeSupplier(ev.getReviewer());
       event.remover = accountAttributeSupplier(ev.getWho());
@@ -331,7 +333,7 @@
       Change change = notes.getChange();
       ReviewerAddedEvent event = new ReviewerAddedEvent(change);
 
-      event.change = changeAttributeSupplier(change);
+      event.change = changeAttributeSupplier(change, notes);
       event.patchSet = patchSetAttributeSupplier(change, psUtil.current(db.get(), notes));
       for (AccountInfo reviewer : ev.getReviewers()) {
         event.reviewer = accountAttributeSupplier(reviewer);
@@ -354,10 +356,11 @@
   @Override
   public void onHashtagsEdited(HashtagsEditedListener.Event ev) {
     try {
-      Change change = getChange(ev.getChange());
+      ChangeNotes notes = getNotes(ev.getChange());
+      Change change = notes.getChange();
       HashtagsChangedEvent event = new HashtagsChangedEvent(change);
 
-      event.change = changeAttributeSupplier(change);
+      event.change = changeAttributeSupplier(change, notes);
       event.editor = accountAttributeSupplier(ev.getWho());
       event.hashtags = hashtagArray(ev.getHashtags());
       event.added = hashtagArray(ev.getAddedHashtags());
@@ -402,7 +405,7 @@
       PatchSet ps = getPatchSet(notes, ev.getRevision());
       CommentAddedEvent event = new CommentAddedEvent(change);
 
-      event.change = changeAttributeSupplier(change);
+      event.change = changeAttributeSupplier(change, notes);
       event.author = accountAttributeSupplier(ev.getWho());
       event.patchSet = patchSetAttributeSupplier(change, ps);
       event.comment = ev.getComment();
@@ -421,7 +424,7 @@
       Change change = notes.getChange();
       ChangeRestoredEvent event = new ChangeRestoredEvent(change);
 
-      event.change = changeAttributeSupplier(change);
+      event.change = changeAttributeSupplier(change, notes);
       event.restorer = accountAttributeSupplier(ev.getWho());
       event.patchSet = patchSetAttributeSupplier(change, psUtil.current(db.get(), notes));
       event.reason = ev.getReason();
@@ -439,7 +442,7 @@
       Change change = notes.getChange();
       ChangeMergedEvent event = new ChangeMergedEvent(change);
 
-      event.change = changeAttributeSupplier(change);
+      event.change = changeAttributeSupplier(change, notes);
       event.submitter = accountAttributeSupplier(ev.getWho());
       event.patchSet = patchSetAttributeSupplier(change, psUtil.current(db.get(), notes));
       event.newRev = ev.getNewRevisionId();
@@ -457,7 +460,7 @@
       Change change = notes.getChange();
       ChangeAbandonedEvent event = new ChangeAbandonedEvent(change);
 
-      event.change = changeAttributeSupplier(change);
+      event.change = changeAttributeSupplier(change, notes);
       event.abandoner = accountAttributeSupplier(ev.getWho());
       event.patchSet = patchSetAttributeSupplier(change, psUtil.current(db.get(), notes));
       event.reason = ev.getReason();
@@ -471,10 +474,11 @@
   @Override
   public void onWorkInProgressStateChanged(WorkInProgressStateChangedListener.Event ev) {
     try {
-      Change change = getChange(ev.getChange());
+      ChangeNotes notes = getNotes(ev.getChange());
+      Change change = notes.getChange();
       WorkInProgressStateChangedEvent event = new WorkInProgressStateChangedEvent(change);
 
-      event.change = changeAttributeSupplier(change);
+      event.change = changeAttributeSupplier(change, notes);
       event.changer = accountAttributeSupplier(ev.getWho());
 
       dispatcher.get().postEvent(change, event);
@@ -486,10 +490,11 @@
   @Override
   public void onPrivateStateChanged(PrivateStateChangedListener.Event ev) {
     try {
-      Change change = getChange(ev.getChange());
+      ChangeNotes notes = getNotes(ev.getChange());
+      Change change = notes.getChange();
       PrivateStateChangedEvent event = new PrivateStateChangedEvent(change);
 
-      event.change = changeAttributeSupplier(change);
+      event.change = changeAttributeSupplier(change, notes);
       event.changer = accountAttributeSupplier(ev.getWho());
 
       dispatcher.get().postEvent(change, event);
@@ -505,7 +510,7 @@
       Change change = notes.getChange();
       VoteDeletedEvent event = new VoteDeletedEvent(change);
 
-      event.change = changeAttributeSupplier(change);
+      event.change = changeAttributeSupplier(change, notes);
       event.patchSet = patchSetAttributeSupplier(change, psUtil.current(db.get(), notes));
       event.comment = ev.getMessage();
       event.reviewer = accountAttributeSupplier(ev.getReviewer());
diff --git a/java/com/google/gerrit/server/util/HostPlatform.java b/java/com/google/gerrit/server/ioutil/HostPlatform.java
similarity index 96%
rename from java/com/google/gerrit/server/util/HostPlatform.java
rename to java/com/google/gerrit/server/ioutil/HostPlatform.java
index 066bd4b..5afda3c 100644
--- a/java/com/google/gerrit/server/util/HostPlatform.java
+++ b/java/com/google/gerrit/server/ioutil/HostPlatform.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.util;
+package com.google.gerrit.server.ioutil;
 
 import java.security.AccessController;
 import java.security.PrivilegedAction;
diff --git a/java/com/google/gerrit/server/mime/MimeUtil2Module.java b/java/com/google/gerrit/server/mime/MimeUtil2Module.java
index 387482a..7fdc4fb 100644
--- a/java/com/google/gerrit/server/mime/MimeUtil2Module.java
+++ b/java/com/google/gerrit/server/mime/MimeUtil2Module.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.mime;
 
-import com.google.gerrit.server.util.HostPlatform;
+import com.google.gerrit.server.ioutil.HostPlatform;
 import com.google.inject.AbstractModule;
 import com.google.inject.Provides;
 import com.google.inject.Singleton;
diff --git a/java/com/google/gerrit/server/permissions/DefaultRefFilter.java b/java/com/google/gerrit/server/permissions/DefaultRefFilter.java
index 1e5b3c8..2bc40c1 100644
--- a/java/com/google/gerrit/server/permissions/DefaultRefFilter.java
+++ b/java/com/google/gerrit/server/permissions/DefaultRefFilter.java
@@ -15,13 +15,14 @@
 package com.google.gerrit.server.permissions;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.ImmutableList.toImmutableList;
 import static com.google.gerrit.reviewdb.client.RefNames.REFS_CACHE_AUTOMERGE;
 import static com.google.gerrit.reviewdb.client.RefNames.REFS_CHANGES;
 import static com.google.gerrit.reviewdb.client.RefNames.REFS_CONFIG;
 import static com.google.gerrit.reviewdb.client.RefNames.REFS_USERS_SELF;
-import static java.util.stream.Collectors.toMap;
 
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
 import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.extensions.restapi.AuthException;
@@ -39,7 +40,6 @@
 import com.google.gerrit.server.git.TagCache;
 import com.google.gerrit.server.git.TagMatcher;
 import com.google.gerrit.server.group.InternalGroup;
-import com.google.gerrit.server.notedb.AbstractChangeNotes;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.notedb.ChangeNotes.Factory.ChangeNotesResult;
 import com.google.gerrit.server.permissions.PermissionBackend.RefFilterOptions;
@@ -55,7 +55,6 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 import java.util.stream.Stream;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.Ref;
@@ -105,16 +104,15 @@
         permissionBackend.user(user).database(db).project(projectState.getNameKey());
   }
 
-  Map<String, Ref> filter(Map<String, Ref> refs, Repository repo, RefFilterOptions opts) {
+  Map<String, Ref> filter(Map<String, Ref> refs, Repository repo, RefFilterOptions opts)
+      throws PermissionBackendException {
     if (projectState.isAllUsers()) {
       refs = addUsersSelfSymref(refs);
     }
 
-    PermissionBackend.WithUser withUser = permissionBackend.user(user);
-    PermissionBackend.ForProject forProject = withUser.project(projectState.getNameKey());
     if (!projectState.isAllUsers()) {
       if (projectState.statePermitsRead()
-          && checkProjectPermission(forProject, ProjectPermission.READ)) {
+          && checkProjectPermission(permissionBackendForProject, ProjectPermission.READ)) {
         return refs;
       } else if (projectControl.allRefsAreVisible(ImmutableSet.of(RefNames.REFS_CONFIG))) {
         return fastHideRefsMetaConfig(refs);
@@ -125,6 +123,7 @@
     boolean isAdmin;
     Account.Id userId;
     IdentifiedUser identifiedUser;
+    PermissionBackend.WithUser withUser = permissionBackend.user(user);
     if (user.isIdentifiedUser()) {
       viewMetadata = withUser.testOrFalse(GlobalPermission.ACCESS_DATABASE);
       isAdmin = withUser.testOrFalse(GlobalPermission.ADMINISTRATE_SERVER);
@@ -229,7 +228,8 @@
     return result;
   }
 
-  private Map<String, Ref> fastHideRefsMetaConfig(Map<String, Ref> refs) {
+  private Map<String, Ref> fastHideRefsMetaConfig(Map<String, Ref> refs)
+      throws PermissionBackendException {
     if (refs.containsKey(REFS_CONFIG) && !canReadRef(REFS_CONFIG)) {
       Map<String, Ref> r = new HashMap<>(refs);
       r.remove(REFS_CONFIG);
@@ -250,7 +250,7 @@
     return refs;
   }
 
-  private boolean visible(Repository repo, Change.Id changeId) {
+  private boolean visible(Repository repo, Change.Id changeId) throws PermissionBackendException {
     if (visibleChanges == null) {
       if (changeCache == null) {
         visibleChanges = visibleChangesByScan(repo);
@@ -261,7 +261,7 @@
     return visibleChanges.containsKey(changeId);
   }
 
-  private boolean visibleEdit(Repository repo, String name) {
+  private boolean visibleEdit(Repository repo, String name) throws PermissionBackendException {
     Change.Id id = Change.Id.fromEditRefPart(name);
     // Initialize if it wasn't yet
     if (visibleChanges == null) {
@@ -284,16 +284,13 @@
         return true;
       } catch (AuthException e) {
         return false;
-      } catch (PermissionBackendException e) {
-        logger.atSevere().withCause(e).log(
-            "Failed to check permission for %s in %s", id, projectState.getName());
-        return false;
       }
     }
     return false;
   }
 
-  private Map<Change.Id, Branch.NameKey> visibleChangesBySearch() {
+  private Map<Change.Id, Branch.NameKey> visibleChangesBySearch()
+      throws PermissionBackendException {
     Project.NameKey project = projectState.getNameKey();
     try {
       Map<Change.Id, Branch.NameKey> visibleChanges = new HashMap<>();
@@ -310,14 +307,15 @@
         }
       }
       return visibleChanges;
-    } catch (OrmException | PermissionBackendException e) {
+    } catch (OrmException e) {
       logger.atSevere().withCause(e).log(
           "Cannot load changes for project %s, assuming no changes are visible", project);
       return Collections.emptyMap();
     }
   }
 
-  private Map<Change.Id, Branch.NameKey> visibleChangesByScan(Repository repo) {
+  private Map<Change.Id, Branch.NameKey> visibleChangesByScan(Repository repo)
+      throws PermissionBackendException {
     Project.NameKey p = projectState.getNameKey();
     Stream<ChangeNotesResult> s;
     try {
@@ -327,13 +325,19 @@
           "Cannot load changes for project %s, assuming no changes are visible", p);
       return Collections.emptyMap();
     }
-    return s.map(this::toNotes)
-        .filter(Objects::nonNull)
-        .collect(toMap(AbstractChangeNotes::getChangeId, n -> n.getChange().getDest()));
+
+    Map<Change.Id, Branch.NameKey> result = Maps.newHashMapWithExpectedSize((int) s.count());
+    for (ChangeNotesResult notesResult : s.collect(toImmutableList())) {
+      ChangeNotes notes = toNotes(notesResult);
+      if (notes != null) {
+        result.put(notes.getChangeId(), notes.getChange().getDest());
+      }
+    }
+    return result;
   }
 
   @Nullable
-  private ChangeNotes toNotes(ChangeNotesResult r) {
+  private ChangeNotes toNotes(ChangeNotesResult r) throws PermissionBackendException {
     if (r.error().isPresent()) {
       logger.atWarning().withCause(r.error().get()).log(
           "Failed to load change %s in %s", r.id(), projectState.getName());
@@ -349,9 +353,6 @@
       return r.notes();
     } catch (AuthException e) {
       // Skip.
-    } catch (PermissionBackendException e) {
-      logger.atSevere().withCause(e).log(
-          "Failed to check permission for %s in %s", r.id(), projectState.getName());
     }
     return null;
   }
@@ -368,28 +369,22 @@
     return ref.getName().startsWith(REFS_USERS_SELF);
   }
 
-  private boolean canReadRef(String ref) {
+  private boolean canReadRef(String ref) throws PermissionBackendException {
     try {
       permissionBackendForProject.ref(ref).check(RefPermission.READ);
     } catch (AuthException e) {
       return false;
-    } catch (PermissionBackendException e) {
-      logger.atSevere().withCause(e).log("unable to check permissions");
-      return false;
     }
     return projectState.statePermitsRead();
   }
 
   private boolean checkProjectPermission(
-      PermissionBackend.ForProject forProject, ProjectPermission perm) {
+      PermissionBackend.ForProject forProject, ProjectPermission perm)
+      throws PermissionBackendException {
     try {
       forProject.check(perm);
     } catch (AuthException e) {
       return false;
-    } catch (PermissionBackendException e) {
-      logger.atSevere().withCause(e).log(
-          "Can't check permission for user %s on project %s", user, projectState.getName());
-      return false;
     }
     return true;
   }
diff --git a/java/com/google/gerrit/server/query/change/OutputStreamQuery.java b/java/com/google/gerrit/server/query/change/OutputStreamQuery.java
index dc57a9b..dbbf367 100644
--- a/java/com/google/gerrit/server/query/change/OutputStreamQuery.java
+++ b/java/com/google/gerrit/server/query/change/OutputStreamQuery.java
@@ -237,7 +237,7 @@
       ChangeData d, Map<Project.NameKey, Repository> repos, Map<Project.NameKey, RevWalk> revWalks)
       throws OrmException, IOException {
     LabelTypes labelTypes = d.getLabelTypes();
-    ChangeAttribute c = eventFactory.asChangeAttribute(db, d.change());
+    ChangeAttribute c = eventFactory.asChangeAttribute(db, d.change(), d.notes());
     eventFactory.extend(c, d.change());
 
     if (!trackingFooters.isEmpty()) {
diff --git a/javatests/com/google/gerrit/acceptance/rest/account/ImpersonationIT.java b/javatests/com/google/gerrit/acceptance/rest/account/ImpersonationIT.java
index eb80092..65c95f8 100644
--- a/javatests/com/google/gerrit/acceptance/rest/account/ImpersonationIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/account/ImpersonationIT.java
@@ -472,7 +472,7 @@
     in.drafts = DraftHandling.PUBLISH;
     RestResponse res =
         adminRestSession.postWithHeader(
-            "/changes/" + r.getChangeId() + "/revisions/current/review", in, runAsHeader(user.id));
+            "/changes/" + r.getChangeId() + "/revisions/current/review", runAsHeader(user.id), in);
     res.assertOK();
 
     ChangeMessageInfo m = Iterables.getLast(gApi.changes().id(r.getChangeId()).get().messages);
@@ -504,13 +504,13 @@
     in.message = "Message on behalf of";
 
     String endpoint = "/changes/" + r.getChangeId() + "/revisions/current/review";
-    RestResponse res = adminRestSession.postWithHeader(endpoint, in, runAsHeader(user2.id));
+    RestResponse res = adminRestSession.postWithHeader(endpoint, runAsHeader(user2.id), in);
     res.assertForbidden();
     assertThat(res.getEntityContent())
         .isEqualTo("label required to post review on behalf of \"" + in.onBehalfOf + '"');
 
     in.label("Code-Review", 1);
-    adminRestSession.postWithHeader(endpoint, in, runAsHeader(user2.id)).assertOK();
+    adminRestSession.postWithHeader(endpoint, runAsHeader(user2.id), in).assertOK();
 
     PatchSetApproval psa = Iterables.getOnlyElement(r.getChange().approvals().values());
     assertThat(psa.getPatchSetId().get()).isEqualTo(1);
diff --git a/javatests/com/google/gerrit/acceptance/server/notedb/ChangeRebuilderIT.java b/javatests/com/google/gerrit/acceptance/server/notedb/ChangeRebuilderIT.java
index ffff121..1ab0407 100644
--- a/javatests/com/google/gerrit/acceptance/server/notedb/ChangeRebuilderIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/notedb/ChangeRebuilderIT.java
@@ -1097,7 +1097,7 @@
       ci.message = "comment with impersonation";
       ri.message = "message with impersonation";
       ri.label("Code-Review", 1);
-      adminRestSession.postWithHeader(prefix + "review", ri, runAs).assertOK();
+      adminRestSession.postWithHeader(prefix + "review", runAs, ri).assertOK();
 
       di.message = "draft with impersonation";
       adminRestSession.putWithHeader(prefix + "drafts", runAs, di).assertCreated();
diff --git a/javatests/com/google/gerrit/server/BUILD b/javatests/com/google/gerrit/server/BUILD
index 569b0b9..18d9c71 100644
--- a/javatests/com/google/gerrit/server/BUILD
+++ b/javatests/com/google/gerrit/server/BUILD
@@ -47,6 +47,7 @@
         "//java/com/google/gerrit/server",
         "//java/com/google/gerrit/server/cache/testing",
         "//java/com/google/gerrit/server/group/testing",
+        "//java/com/google/gerrit/server/ioutil",
         "//java/com/google/gerrit/server/project/testing:project-test-util",
         "//java/com/google/gerrit/server/restapi",
         "//java/com/google/gerrit/server/schema",
diff --git a/javatests/com/google/gerrit/server/config/SitePathsTest.java b/javatests/com/google/gerrit/server/config/SitePathsTest.java
index 853db27..b4cde14 100644
--- a/javatests/com/google/gerrit/server/config/SitePathsTest.java
+++ b/javatests/com/google/gerrit/server/config/SitePathsTest.java
@@ -17,7 +17,7 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth8.assertThat;
 
-import com.google.gerrit.server.util.HostPlatform;
+import com.google.gerrit.server.ioutil.HostPlatform;
 import com.google.gerrit.testing.GerritBaseTests;
 import java.io.IOException;
 import java.nio.file.Files;
diff --git a/javatests/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java b/javatests/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java
index aaad2a6..4e0cb0c 100644
--- a/javatests/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java
+++ b/javatests/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java
@@ -19,7 +19,7 @@
 
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.config.SitePaths;
-import com.google.gerrit.server.util.HostPlatform;
+import com.google.gerrit.server.ioutil.HostPlatform;
 import com.google.gerrit.testing.TempFileUtil;
 import com.google.gwtorm.client.KeyUtil;
 import com.google.gwtorm.server.StandardKeyEncoder;
diff --git a/javatests/com/google/gerrit/server/tools/hooks/CommitMsgHookTest.java b/javatests/com/google/gerrit/server/tools/hooks/CommitMsgHookTest.java
index bd54ddc..339a46d 100644
--- a/javatests/com/google/gerrit/server/tools/hooks/CommitMsgHookTest.java
+++ b/javatests/com/google/gerrit/server/tools/hooks/CommitMsgHookTest.java
@@ -19,7 +19,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import com.google.gerrit.server.util.HostPlatform;
+import com.google.gerrit.server.ioutil.HostPlatform;
 import java.io.File;
 import java.io.IOException;
 import java.util.Date;