Convert Project.NameKey to an immutable type

Follows the pattern of other key type refactorings, adding a static
factory method. However, unlike the other key types, this one can't be
an @AutoValue, because it has other subclasses and specific requirements
around the implementation of equals. So we're stuck with boilerplate; at
least it's only one field.

See I6982fb24 for context.

Change-Id: Ic46c4a357f4ee77f18e54e87ca97af6e834834b6
diff --git a/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
index 8c4f30b..6358794 100644
--- a/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
+++ b/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -433,7 +433,7 @@
     atrScope.set(ctx);
     ProjectInput in = projectInput(description);
     gApi.projects().create(in);
-    project = new Project.NameKey(in.name);
+    project = Project.nameKey(in.name);
     if (!classDesc.skipProjectClone()) {
       testRepo = cloneProject(project, getCloneAsAccount(description));
     }
@@ -532,7 +532,7 @@
     in.submitType = submitType;
     in.createEmptyCommit = createEmptyCommit;
     gApi.projects().create(in);
-    return new Project.NameKey(in.name);
+    return Project.nameKey(in.name);
   }
 
   protected TestRepository<InMemoryRepository> cloneProject(Project.NameKey p) throws Exception {
@@ -1170,7 +1170,7 @@
         int len = bundleName.length();
         assertThat(bundleName).endsWith(".git");
         String repoName = bundleName.substring(0, len - 4);
-        Project.NameKey proj = new Project.NameKey(repoName);
+        Project.NameKey proj = Project.nameKey(repoName);
         TestRepository<?> localRepo = cloneProject(proj);
 
         try (InputStream bundleStream = Files.newInputStream(p);
diff --git a/java/com/google/gerrit/acceptance/testsuite/project/ProjectOperationsImpl.java b/java/com/google/gerrit/acceptance/testsuite/project/ProjectOperationsImpl.java
index 28be3f3..09066e7 100644
--- a/java/com/google/gerrit/acceptance/testsuite/project/ProjectOperationsImpl.java
+++ b/java/com/google/gerrit/acceptance/testsuite/project/ProjectOperationsImpl.java
@@ -58,7 +58,7 @@
     args.ownerIds = new ArrayList<>();
     projectCreation.submitType().ifPresent(st -> args.submitType = st);
     projectCreator.createProject(args);
-    return new Project.NameKey(name);
+    return Project.nameKey(name);
   }
 
   @Override
diff --git a/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java b/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
index dfd345a..f7edac2 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
@@ -208,7 +208,7 @@
       int id = source.get(ChangeField.LEGACY_ID.getName()).getAsInt();
       // IndexUtils#changeFields ensures either CHANGE or PROJECT is always present.
       String projectName = requireNonNull(source.get(ChangeField.PROJECT.getName()).getAsString());
-      return changeDataFactory.create(new Project.NameKey(projectName), new Change.Id(id));
+      return changeDataFactory.create(Project.nameKey(projectName), new Change.Id(id));
     }
 
     ChangeData cd =
diff --git a/java/com/google/gerrit/elasticsearch/ElasticProjectIndex.java b/java/com/google/gerrit/elasticsearch/ElasticProjectIndex.java
index daf3702..cb97032 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticProjectIndex.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticProjectIndex.java
@@ -117,8 +117,7 @@
     }
 
     Project.NameKey nameKey =
-        new Project.NameKey(
-            source.getAsJsonObject().get(ProjectField.NAME.getName()).getAsString());
+        Project.nameKey(source.getAsJsonObject().get(ProjectField.NAME.getName()).getAsString());
     return projectCache.get().get(nameKey).toProjectData();
   }
 }
diff --git a/java/com/google/gerrit/httpd/DirectChangeByCommit.java b/java/com/google/gerrit/httpd/DirectChangeByCommit.java
index 152a83d..448d97b 100644
--- a/java/com/google/gerrit/httpd/DirectChangeByCommit.java
+++ b/java/com/google/gerrit/httpd/DirectChangeByCommit.java
@@ -47,7 +47,7 @@
       // If exactly one change matches, link to that change.
       // TODO Link to a specific patch set, if one matched.
       ChangeInfo ci = results.iterator().next();
-      token = PageLinks.toChange(new Project.NameKey(ci.project), new Change.Id(ci._number));
+      token = PageLinks.toChange(Project.nameKey(ci.project), new Change.Id(ci._number));
     } else {
       // Otherwise, link to the query page.
       token = PageLinks.toChangeQuery(query);
diff --git a/java/com/google/gerrit/httpd/GitOverHttpServlet.java b/java/com/google/gerrit/httpd/GitOverHttpServlet.java
index c97ee10..23afbd3 100644
--- a/java/com/google/gerrit/httpd/GitOverHttpServlet.java
+++ b/java/com/google/gerrit/httpd/GitOverHttpServlet.java
@@ -279,7 +279,7 @@
       user.setAccessPath(AccessPath.GIT);
 
       try {
-        Project.NameKey nameKey = new Project.NameKey(projectName);
+        Project.NameKey nameKey = Project.nameKey(projectName);
         ProjectState state = projectCache.checkedGet(nameKey);
         if (state == null || !state.statePermitsRead()) {
           throw new RepositoryNotFoundException(nameKey.get());
diff --git a/java/com/google/gerrit/httpd/UrlModule.java b/java/com/google/gerrit/httpd/UrlModule.java
index 993a042..fe7d72d 100644
--- a/java/com/google/gerrit/httpd/UrlModule.java
+++ b/java/com/google/gerrit/httpd/UrlModule.java
@@ -147,7 +147,7 @@
             while (name.endsWith("/")) {
               name = name.substring(0, name.length() - 1);
             }
-            Project.NameKey project = new Project.NameKey(name);
+            Project.NameKey project = Project.nameKey(name);
             toGerrit(
                 PageLinks.toChangeQuery(PageLinks.projectQuery(project, Change.Status.NEW)),
                 req,
diff --git a/java/com/google/gerrit/httpd/gitweb/GitwebServlet.java b/java/com/google/gerrit/httpd/gitweb/GitwebServlet.java
index 6cb094f..3bacd1c 100644
--- a/java/com/google/gerrit/httpd/gitweb/GitwebServlet.java
+++ b/java/com/google/gerrit/httpd/gitweb/GitwebServlet.java
@@ -414,7 +414,7 @@
       name = name.substring(0, name.length() - 4);
     }
 
-    Project.NameKey nameKey = new Project.NameKey(name);
+    Project.NameKey nameKey = Project.nameKey(name);
     ProjectState projectState;
     try {
       projectState = projectCache.checkedGet(nameKey);
diff --git a/java/com/google/gerrit/index/RefState.java b/java/com/google/gerrit/index/RefState.java
index f0e465d..8ffaa36 100644
--- a/java/com/google/gerrit/index/RefState.java
+++ b/java/com/google/gerrit/index/RefState.java
@@ -42,7 +42,7 @@
       String s = new String(b, UTF_8);
       List<String> parts = Splitter.on(':').splitToList(s);
       RefState.check(parts.size() == 3 && !parts.get(0).isEmpty() && !parts.get(1).isEmpty(), s);
-      result.put(new Project.NameKey(parts.get(0)), RefState.create(parts.get(1), parts.get(2)));
+      result.put(Project.nameKey(parts.get(0)), RefState.create(parts.get(1), parts.get(2)));
     }
     return result;
   }
diff --git a/java/com/google/gerrit/lucene/LuceneChangeIndex.java b/java/com/google/gerrit/lucene/LuceneChangeIndex.java
index 07246ab..6cccf96 100644
--- a/java/com/google/gerrit/lucene/LuceneChangeIndex.java
+++ b/java/com/google/gerrit/lucene/LuceneChangeIndex.java
@@ -453,7 +453,7 @@
       Change.Id id = new Change.Id(f.numericValue().intValue());
       // IndexUtils#changeFields ensures either CHANGE or PROJECT is always present.
       IndexableField project = doc.get(PROJECT.getName()).iterator().next();
-      cd = changeDataFactory.create(new Project.NameKey(project.stringValue()), id);
+      cd = changeDataFactory.create(Project.nameKey(project.stringValue()), id);
     }
 
     // Any decoding that is done here must also be done in {@link ElasticChangeIndex}.
diff --git a/java/com/google/gerrit/lucene/LuceneProjectIndex.java b/java/com/google/gerrit/lucene/LuceneProjectIndex.java
index 950e206..44d7610 100644
--- a/java/com/google/gerrit/lucene/LuceneProjectIndex.java
+++ b/java/com/google/gerrit/lucene/LuceneProjectIndex.java
@@ -139,7 +139,7 @@
 
   @Override
   protected ProjectData fromDocument(Document doc) {
-    Project.NameKey nameKey = new Project.NameKey(doc.getField(NAME.getName()).stringValue());
+    Project.NameKey nameKey = Project.nameKey(doc.getField(NAME.getName()).stringValue());
     ProjectState projectState = projectCache.get().get(nameKey);
     return projectState == null ? null : projectState.toProjectData();
   }
diff --git a/java/com/google/gerrit/pgm/Rulec.java b/java/com/google/gerrit/pgm/Rulec.java
index aa72ae0..1592d0e 100644
--- a/java/com/google/gerrit/pgm/Rulec.java
+++ b/java/com/google/gerrit/pgm/Rulec.java
@@ -73,7 +73,7 @@
 
     LinkedHashSet<Project.NameKey> names = new LinkedHashSet<>();
     for (String name : projectNames) {
-      names.add(new Project.NameKey(name));
+      names.add(Project.nameKey(name));
     }
     if (all) {
       names.addAll(gitManager.list());
diff --git a/java/com/google/gerrit/pgm/init/api/AllProjectsConfig.java b/java/com/google/gerrit/pgm/init/api/AllProjectsConfig.java
index 20e7ba2..c90124d 100644
--- a/java/com/google/gerrit/pgm/init/api/AllProjectsConfig.java
+++ b/java/com/google/gerrit/pgm/init/api/AllProjectsConfig.java
@@ -43,7 +43,7 @@
     super(flags, site, allProjects.get(), RefNames.REFS_CONFIG);
     this.baseConfig =
         ProjectConfig.Factory.getBaseConfig(
-            site, new AllProjectsName(allProjects.get()), new Project.NameKey(allProjects.get()));
+            site, new AllProjectsName(allProjects.get()), Project.nameKey(allProjects.get()));
   }
 
   public Config getConfig() {
@@ -71,7 +71,7 @@
 
   private GroupList readGroupList() throws IOException {
     return GroupList.parse(
-        new Project.NameKey(project),
+        Project.nameKey(project),
         readUTF8(GroupList.FILE_NAME),
         error ->
             logger.atSevere().log(
diff --git a/java/com/google/gerrit/pgm/init/api/SequencesOnInit.java b/java/com/google/gerrit/pgm/init/api/SequencesOnInit.java
index d3d22cb..71753c7 100644
--- a/java/com/google/gerrit/pgm/init/api/SequencesOnInit.java
+++ b/java/com/google/gerrit/pgm/init/api/SequencesOnInit.java
@@ -38,7 +38,7 @@
         new RepoSequence(
             repoManager,
             GitReferenceUpdated.DISABLED,
-            new Project.NameKey(allUsersName.get()),
+            Project.nameKey(allUsersName.get()),
             Sequences.NAME_ACCOUNTS,
             () -> Sequences.FIRST_ACCOUNT_ID,
             1);
diff --git a/java/com/google/gerrit/pgm/init/api/VersionedMetaDataOnInit.java b/java/com/google/gerrit/pgm/init/api/VersionedMetaDataOnInit.java
index 738cafd..d4af255 100644
--- a/java/com/google/gerrit/pgm/init/api/VersionedMetaDataOnInit.java
+++ b/java/com/google/gerrit/pgm/init/api/VersionedMetaDataOnInit.java
@@ -58,7 +58,7 @@
     File path = getPath();
     if (path != null) {
       try (Repository repo = new FileRepository(path)) {
-        load(new Project.NameKey(project), repo);
+        load(Project.nameKey(project), repo);
       }
     }
     return this;
diff --git a/java/com/google/gerrit/reviewdb/client/Branch.java b/java/com/google/gerrit/reviewdb/client/Branch.java
index 48bb4d8..b4c635d 100644
--- a/java/com/google/gerrit/reviewdb/client/Branch.java
+++ b/java/com/google/gerrit/reviewdb/client/Branch.java
@@ -24,7 +24,7 @@
   }
 
   public static NameKey nameKey(String projectName, String branchName) {
-    return nameKey(new Project.NameKey(projectName), branchName);
+    return nameKey(Project.nameKey(projectName), branchName);
   }
 
   /** Branch name key */
diff --git a/java/com/google/gerrit/reviewdb/client/Project.java b/java/com/google/gerrit/reviewdb/client/Project.java
index fd427f7..8fca2ec 100644
--- a/java/com/google/gerrit/reviewdb/client/Project.java
+++ b/java/com/google/gerrit/reviewdb/client/Project.java
@@ -14,10 +14,12 @@
 
 package com.google.gerrit.reviewdb.client;
 
+import static java.util.Objects.requireNonNull;
+
 import com.google.gerrit.extensions.client.InheritableBoolean;
 import com.google.gerrit.extensions.client.ProjectState;
 import com.google.gerrit.extensions.client.SubmitType;
-import com.google.gwtorm.client.StringKey;
+import com.google.gwtorm.client.StandardKeyEncoder;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
@@ -30,35 +32,42 @@
   /** Default submit type for root project (All-Projects). */
   public static final SubmitType DEFAULT_ALL_PROJECTS_SUBMIT_TYPE = SubmitType.MERGE_IF_NECESSARY;
 
+  public static NameKey nameKey(String name) {
+    return new NameKey(name);
+  }
+
   /**
    * Project name key.
    *
    * <p>This class has subclasses such as {@code AllProjectsName}, which make Guice injection more
    * convenient. Subclasses must compare equal if they have the same name, regardless of the
    * specific class. This implies that subclasses may not add additional fields.
+   *
+   * <p>Because of this unusual subclassing behavior, this class is not an {@code @AutoValue},
+   * unlike other key types in this package. However, this is strictly an implementation detail; its
+   * interface and semantics are otherwise analogous to the {@code @AutoValue} types.
    */
-  public static class NameKey extends StringKey<com.google.gwtorm.client.Key<?>> {
-    private static final long serialVersionUID = 1L;
-
-    protected String name;
-
-    protected NameKey() {}
-
-    public NameKey(String n) {
-      name = n;
+  public static class NameKey implements Comparable<NameKey> {
+    /** Parse a Project.NameKey out of a string representation. */
+    public static NameKey parse(String str) {
+      return nameKey(new StandardKeyEncoder().decode(str));
     }
 
-    @Override
+    public static String asStringOrNull(NameKey key) {
+      return key == null ? null : key.get();
+    }
+
+    private final String name;
+
+    protected NameKey(String name) {
+      this.name = requireNonNull(name);
+    }
+
     public String get() {
       return name;
     }
 
     @Override
-    protected void set(String newValue) {
-      name = newValue;
-    }
-
-    @Override
     public final int hashCode() {
       return get().hashCode();
     }
@@ -71,15 +80,14 @@
       return false;
     }
 
-    /** Parse a Project.NameKey out of a string representation. */
-    public static NameKey parse(String str) {
-      final NameKey r = new NameKey();
-      r.fromString(str);
-      return r;
+    @Override
+    public final int compareTo(NameKey o) {
+      return get().compareTo(o.get());
     }
 
-    public static String asStringOrNull(NameKey key) {
-      return key == null ? null : key.get();
+    @Override
+    public final String toString() {
+      return new StandardKeyEncoder().encode(get());
     }
   }
 
@@ -221,7 +229,7 @@
   }
 
   public void setParentName(String n) {
-    parent = n != null ? new NameKey(n) : null;
+    parent = n != null ? nameKey(n) : null;
   }
 
   public void setParentName(NameKey n) {
diff --git a/java/com/google/gerrit/reviewdb/converter/ProjectNameKeyProtoConverter.java b/java/com/google/gerrit/reviewdb/converter/ProjectNameKeyProtoConverter.java
index f7d809e..74849af 100644
--- a/java/com/google/gerrit/reviewdb/converter/ProjectNameKeyProtoConverter.java
+++ b/java/com/google/gerrit/reviewdb/converter/ProjectNameKeyProtoConverter.java
@@ -29,7 +29,7 @@
 
   @Override
   public Project.NameKey fromProto(Entities.Project_NameKey proto) {
-    return new Project.NameKey(proto.getName());
+    return Project.nameKey(proto.getName());
   }
 
   @Override
diff --git a/java/com/google/gerrit/server/account/DestinationList.java b/java/com/google/gerrit/server/account/DestinationList.java
index b5cda2f..1b32362 100644
--- a/java/com/google/gerrit/server/account/DestinationList.java
+++ b/java/com/google/gerrit/server/account/DestinationList.java
@@ -54,7 +54,7 @@
   private static Set<Branch.NameKey> toSet(List<Row> destRows) {
     Set<Branch.NameKey> dests = Sets.newHashSetWithExpectedSize(destRows.size());
     for (Row row : destRows) {
-      dests.add(Branch.nameKey(new Project.NameKey(row.right), row.left));
+      dests.add(Branch.nameKey(Project.nameKey(row.right), row.left));
     }
     return dests;
   }
diff --git a/java/com/google/gerrit/server/account/ProjectWatches.java b/java/com/google/gerrit/server/account/ProjectWatches.java
index 8b3e1b3..594453b 100644
--- a/java/com/google/gerrit/server/account/ProjectWatches.java
+++ b/java/com/google/gerrit/server/account/ProjectWatches.java
@@ -168,7 +168,7 @@
         }
 
         ProjectWatchKey key =
-            ProjectWatchKey.create(new Project.NameKey(projectName), notifyValue.filter());
+            ProjectWatchKey.create(Project.nameKey(projectName), notifyValue.filter());
         if (!projectWatches.containsKey(key)) {
           projectWatches.put(key, EnumSet.noneOf(NotifyType.class));
         }
diff --git a/java/com/google/gerrit/server/args4j/ChangeIdHandler.java b/java/com/google/gerrit/server/args4j/ChangeIdHandler.java
index aae37aa..5410f25 100644
--- a/java/com/google/gerrit/server/args4j/ChangeIdHandler.java
+++ b/java/com/google/gerrit/server/args4j/ChangeIdHandler.java
@@ -59,7 +59,7 @@
 
     try {
       final Change.Key key = Change.Key.parse(tokens.get(2));
-      final Project.NameKey project = new Project.NameKey(tokens.get(0));
+      final Project.NameKey project = Project.nameKey(tokens.get(0));
       final Branch.NameKey branch = Branch.nameKey(project, tokens.get(1));
       for (ChangeData cd : queryProvider.get().byBranchKey(branch, key)) {
         setter.addValue(cd.getId());
diff --git a/java/com/google/gerrit/server/args4j/ProjectHandler.java b/java/com/google/gerrit/server/args4j/ProjectHandler.java
index f33a4ed..a4af62d 100644
--- a/java/com/google/gerrit/server/args4j/ProjectHandler.java
+++ b/java/com/google/gerrit/server/args4j/ProjectHandler.java
@@ -72,7 +72,7 @@
     }
 
     String nameWithoutSuffix = ProjectUtil.stripGitSuffix(projectName);
-    Project.NameKey nameKey = new Project.NameKey(nameWithoutSuffix);
+    Project.NameKey nameKey = Project.nameKey(nameWithoutSuffix);
 
     ProjectState state;
     try {
diff --git a/java/com/google/gerrit/server/change/ChangeTriplet.java b/java/com/google/gerrit/server/change/ChangeTriplet.java
index d15a95f..89232f6 100644
--- a/java/com/google/gerrit/server/change/ChangeTriplet.java
+++ b/java/com/google/gerrit/server/change/ChangeTriplet.java
@@ -53,7 +53,7 @@
     String changeId = Url.decode(triplet.substring(z + 1));
     return Optional.of(
         new AutoValue_ChangeTriplet(
-            Branch.nameKey(new Project.NameKey(project), branch), new Change.Key(changeId)));
+            Branch.nameKey(Project.nameKey(project), branch), new Change.Key(changeId)));
   }
 
   public final Project.NameKey project() {
diff --git a/java/com/google/gerrit/server/config/AllProjectsName.java b/java/com/google/gerrit/server/config/AllProjectsName.java
index 7719e38..06466c4 100644
--- a/java/com/google/gerrit/server/config/AllProjectsName.java
+++ b/java/com/google/gerrit/server/config/AllProjectsName.java
@@ -18,8 +18,6 @@
 
 /** Special name of the project that all projects derive from. */
 public class AllProjectsName extends Project.NameKey {
-  private static final long serialVersionUID = 1L;
-
   public AllProjectsName(String name) {
     super(name);
   }
diff --git a/java/com/google/gerrit/server/config/AllUsersName.java b/java/com/google/gerrit/server/config/AllUsersName.java
index 22d29a4..1b5028a 100644
--- a/java/com/google/gerrit/server/config/AllUsersName.java
+++ b/java/com/google/gerrit/server/config/AllUsersName.java
@@ -18,8 +18,6 @@
 
 /** Special name of the project in which meta data for all users is stored. */
 public class AllUsersName extends Project.NameKey {
-  private static final long serialVersionUID = 1L;
-
   public AllUsersName(String name) {
     super(name);
   }
diff --git a/java/com/google/gerrit/server/config/ProjectConfigEntry.java b/java/com/google/gerrit/server/config/ProjectConfigEntry.java
index 92ae10a..dfb5c7a 100644
--- a/java/com/google/gerrit/server/config/ProjectConfigEntry.java
+++ b/java/com/google/gerrit/server/config/ProjectConfigEntry.java
@@ -316,7 +316,7 @@
 
     @Override
     public void onGitReferenceUpdated(Event event) {
-      Project.NameKey p = new Project.NameKey(event.getProjectName());
+      Project.NameKey p = Project.nameKey(event.getProjectName());
       if (!event.getRefName().equals(RefNames.REFS_CONFIG)) {
         return;
       }
diff --git a/java/com/google/gerrit/server/events/ProjectCreatedEvent.java b/java/com/google/gerrit/server/events/ProjectCreatedEvent.java
index dc979ca..42b6676 100644
--- a/java/com/google/gerrit/server/events/ProjectCreatedEvent.java
+++ b/java/com/google/gerrit/server/events/ProjectCreatedEvent.java
@@ -27,7 +27,7 @@
 
   @Override
   public Project.NameKey getProjectNameKey() {
-    return new Project.NameKey(projectName);
+    return Project.nameKey(projectName);
   }
 
   public String getHeadName() {
diff --git a/java/com/google/gerrit/server/events/RefUpdatedEvent.java b/java/com/google/gerrit/server/events/RefUpdatedEvent.java
index d740543..fa16c4c 100644
--- a/java/com/google/gerrit/server/events/RefUpdatedEvent.java
+++ b/java/com/google/gerrit/server/events/RefUpdatedEvent.java
@@ -30,7 +30,7 @@
 
   @Override
   public Project.NameKey getProjectNameKey() {
-    return new Project.NameKey(refUpdate.get().project);
+    return Project.nameKey(refUpdate.get().project);
   }
 
   @Override
diff --git a/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java b/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
index 85822a8..9646fc7 100644
--- a/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
+++ b/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
@@ -254,7 +254,7 @@
       int newLen = projectName.length() - Constants.DOT_GIT_EXT.length();
       projectName = projectName.substring(0, newLen);
     }
-    return new Project.NameKey(projectName);
+    return Project.nameKey(projectName);
   }
 
   protected class ProjectVisitor extends SimpleFileVisitor<Path> {
diff --git a/java/com/google/gerrit/server/git/PureRevertCache.java b/java/com/google/gerrit/server/git/PureRevertCache.java
index 1daa1d5..a3b593c 100644
--- a/java/com/google/gerrit/server/git/PureRevertCache.java
+++ b/java/com/google/gerrit/server/git/PureRevertCache.java
@@ -154,7 +154,7 @@
           TraceContext.newTimer("Loading pure revert for %s", key)) {
         ObjectId original = ObjectIdConverter.create().fromByteString(key.getClaimedOriginal());
         ObjectId revert = ObjectIdConverter.create().fromByteString(key.getClaimedRevert());
-        Project.NameKey project = new Project.NameKey(key.getProject());
+        Project.NameKey project = Project.nameKey(key.getProject());
 
         try (Repository repo = repoManager.openRepository(project);
             ObjectInserter oi = repo.newObjectInserter();
diff --git a/java/com/google/gerrit/server/git/SearchingChangeCacheImpl.java b/java/com/google/gerrit/server/git/SearchingChangeCacheImpl.java
index d7f8982..fb7756f 100644
--- a/java/com/google/gerrit/server/git/SearchingChangeCacheImpl.java
+++ b/java/com/google/gerrit/server/git/SearchingChangeCacheImpl.java
@@ -136,7 +136,7 @@
   @Override
   public void onGitReferenceUpdated(GitReferenceUpdatedListener.Event event) {
     if (event.getRefName().startsWith(RefNames.REFS_CHANGES)) {
-      cache.invalidate(new Project.NameKey(event.getProjectName()));
+      cache.invalidate(Project.nameKey(event.getProjectName()));
     }
   }
 
diff --git a/java/com/google/gerrit/server/git/TagSet.java b/java/com/google/gerrit/server/git/TagSet.java
index 57637c89..860118c 100644
--- a/java/com/google/gerrit/server/git/TagSet.java
+++ b/java/com/google/gerrit/server/git/TagSet.java
@@ -232,7 +232,7 @@
                     new Tag(
                         idConverter.fromByteString(t.getId()),
                         BitSet.valueOf(t.getFlags().asReadOnlyByteBuffer()))));
-    return new TagSet(new Project.NameKey(proto.getProjectName()), refs, tags);
+    return new TagSet(Project.nameKey(proto.getProjectName()), refs, tags);
   }
 
   TagSetProto toProto() {
diff --git a/java/com/google/gerrit/server/git/TagSetHolder.java b/java/com/google/gerrit/server/git/TagSetHolder.java
index 194283e..d1e33ba 100644
--- a/java/com/google/gerrit/server/git/TagSetHolder.java
+++ b/java/com/google/gerrit/server/git/TagSetHolder.java
@@ -117,7 +117,7 @@
     @Override
     public TagSetHolder deserialize(byte[] in) {
       TagSetHolderProto proto = Protos.parseUnchecked(TagSetHolderProto.parser(), in);
-      TagSetHolder holder = new TagSetHolder(new Project.NameKey(proto.getProjectName()));
+      TagSetHolder holder = new TagSetHolder(Project.nameKey(proto.getProjectName()));
       if (proto.hasTags()) {
         holder.tags = TagSet.fromProto(proto.getTags());
       }
diff --git a/java/com/google/gerrit/server/index/change/ReindexAfterRefUpdate.java b/java/com/google/gerrit/server/index/change/ReindexAfterRefUpdate.java
index ad6edfd..955c3a0 100644
--- a/java/com/google/gerrit/server/index/change/ReindexAfterRefUpdate.java
+++ b/java/com/google/gerrit/server/index/change/ReindexAfterRefUpdate.java
@@ -149,7 +149,7 @@
     @Override
     protected List<Change> impl(RequestContext ctx) {
       String ref = event.getRefName();
-      Project.NameKey project = new Project.NameKey(event.getProjectName());
+      Project.NameKey project = Project.nameKey(event.getProjectName());
       if (ref.equals(RefNames.REFS_CONFIG)) {
         return asChanges(queryProvider.get().byProjectOpen(project));
       }
@@ -178,7 +178,7 @@
       // Reload change, as some time may have passed since GetChanges.
       try {
         Change c =
-            notesFactory.createChecked(new Project.NameKey(event.getProjectName()), id).getChange();
+            notesFactory.createChecked(Project.nameKey(event.getProjectName()), id).getChange();
         indexerFactory.create(executor, indexes).index(c);
       } catch (NoSuchChangeException e) {
         indexerFactory.create(executor, indexes).delete(id);
diff --git a/java/com/google/gerrit/server/index/change/StalenessChecker.java b/java/com/google/gerrit/server/index/change/StalenessChecker.java
index 338cf3d..fc5320c 100644
--- a/java/com/google/gerrit/server/index/change/StalenessChecker.java
+++ b/java/com/google/gerrit/server/index/change/StalenessChecker.java
@@ -131,8 +131,7 @@
       String s = new String(b, UTF_8);
       List<String> parts = Splitter.on(':').splitToList(s);
       RefStatePattern.check(parts.size() == 2, s);
-      result.put(
-          new Project.NameKey(Url.decode(parts.get(0))), RefStatePattern.create(parts.get(1)));
+      result.put(Project.nameKey(Url.decode(parts.get(0))), RefStatePattern.create(parts.get(1)));
     }
     return result;
   }
diff --git a/java/com/google/gerrit/server/notedb/ChangeNotesCache.java b/java/com/google/gerrit/server/notedb/ChangeNotesCache.java
index 1e48907..bd38166 100644
--- a/java/com/google/gerrit/server/notedb/ChangeNotesCache.java
+++ b/java/com/google/gerrit/server/notedb/ChangeNotesCache.java
@@ -98,7 +98,7 @@
       public Key deserialize(byte[] in) {
         ChangeNotesKeyProto proto = Protos.parseUnchecked(ChangeNotesKeyProto.parser(), in);
         return Key.create(
-            new Project.NameKey(proto.getProject()),
+            Project.nameKey(proto.getProject()),
             new Change.Id(proto.getChangeId()),
             ObjectIdConverter.create().fromByteString(proto.getId()));
       }
diff --git a/java/com/google/gerrit/server/project/CreateProjectArgs.java b/java/com/google/gerrit/server/project/CreateProjectArgs.java
index df31c19..7405df1 100644
--- a/java/com/google/gerrit/server/project/CreateProjectArgs.java
+++ b/java/com/google/gerrit/server/project/CreateProjectArgs.java
@@ -61,7 +61,7 @@
   }
 
   public void setProjectName(String n) {
-    projectName = n != null ? new Project.NameKey(n) : null;
+    projectName = n != null ? Project.nameKey(n) : null;
   }
 
   public void setProjectName(Project.NameKey n) {
diff --git a/java/com/google/gerrit/server/project/ProjectCacheImpl.java b/java/com/google/gerrit/server/project/ProjectCacheImpl.java
index 4a85554..3542187 100644
--- a/java/com/google/gerrit/server/project/ProjectCacheImpl.java
+++ b/java/com/google/gerrit/server/project/ProjectCacheImpl.java
@@ -262,8 +262,8 @@
 
   @Override
   public ImmutableSortedSet<Project.NameKey> byName(String pfx) {
-    Project.NameKey start = new Project.NameKey(pfx);
-    Project.NameKey end = new Project.NameKey(pfx + Character.MAX_VALUE);
+    Project.NameKey start = Project.nameKey(pfx);
+    Project.NameKey end = Project.nameKey(pfx + Character.MAX_VALUE);
     try {
       // Right endpoint is exclusive, but U+FFFF is a non-character so no project ends with it.
       return list.get(ListKey.ALL).subSet(start, end);
@@ -295,7 +295,7 @@
     public ProjectState load(String projectName) throws Exception {
       try (TraceTimer timer = TraceContext.newTimer("Loading project %s", projectName)) {
         long now = clock.read();
-        Project.NameKey key = new Project.NameKey(projectName);
+        Project.NameKey key = Project.nameKey(projectName);
         try (Repository git = mgr.openRepository(key)) {
           ProjectConfig cfg = projectConfigFactory.create(key);
           cfg.load(key, git);
diff --git a/java/com/google/gerrit/server/project/ProjectConfig.java b/java/com/google/gerrit/server/project/ProjectConfig.java
index b0fdd3c..5ef9651 100644
--- a/java/com/google/gerrit/server/project/ProjectConfig.java
+++ b/java/com/google/gerrit/server/project/ProjectConfig.java
@@ -1034,7 +1034,7 @@
     subscribeSections = new HashMap<>();
     try {
       for (String projectName : subsections) {
-        Project.NameKey p = new Project.NameKey(projectName);
+        Project.NameKey p = Project.nameKey(projectName);
         SubscribeSection ss = new SubscribeSection(p);
         for (String s :
             rc.getStringList(SUBSCRIBE_SECTION, projectName, SUBSCRIBE_MULTI_MATCH_REFS)) {
diff --git a/java/com/google/gerrit/server/project/RefValidationHelper.java b/java/com/google/gerrit/server/project/RefValidationHelper.java
index 0a5980c..67c0d03 100644
--- a/java/com/google/gerrit/server/project/RefValidationHelper.java
+++ b/java/com/google/gerrit/server/project/RefValidationHelper.java
@@ -43,7 +43,7 @@
       throws ResourceConflictException {
     RefOperationValidators refValidators =
         refValidatorsFactory.create(
-            new Project(new Project.NameKey(projectName)),
+            new Project(Project.nameKey(projectName)),
             user,
             RefOperationValidators.getCommand(update, operationType));
     try {
diff --git a/java/com/google/gerrit/server/query/change/ParentProjectPredicate.java b/java/com/google/gerrit/server/query/change/ParentProjectPredicate.java
index 17d6448..ec411ee 100644
--- a/java/com/google/gerrit/server/query/change/ParentProjectPredicate.java
+++ b/java/com/google/gerrit/server/query/change/ParentProjectPredicate.java
@@ -40,7 +40,7 @@
 
   protected static List<Predicate<ChangeData>> predicates(
       ProjectCache projectCache, ChildProjects childProjects, String value) {
-    ProjectState projectState = projectCache.get(new Project.NameKey(value));
+    ProjectState projectState = projectCache.get(Project.nameKey(value));
     if (projectState == null) {
       return Collections.emptyList();
     }
diff --git a/java/com/google/gerrit/server/query/change/ProjectPredicate.java b/java/com/google/gerrit/server/query/change/ProjectPredicate.java
index 664ffb1..c1cc999 100644
--- a/java/com/google/gerrit/server/query/change/ProjectPredicate.java
+++ b/java/com/google/gerrit/server/query/change/ProjectPredicate.java
@@ -24,7 +24,7 @@
   }
 
   protected Project.NameKey getValueKey() {
-    return new Project.NameKey(getValue());
+    return Project.nameKey(getValue());
   }
 
   @Override
diff --git a/java/com/google/gerrit/server/query/project/ProjectQueryBuilder.java b/java/com/google/gerrit/server/query/project/ProjectQueryBuilder.java
index 570da6b..6637c6f 100644
--- a/java/com/google/gerrit/server/query/project/ProjectQueryBuilder.java
+++ b/java/com/google/gerrit/server/query/project/ProjectQueryBuilder.java
@@ -41,12 +41,12 @@
 
   @Operator
   public Predicate<ProjectData> name(String name) {
-    return ProjectPredicates.name(new Project.NameKey(name));
+    return ProjectPredicates.name(Project.nameKey(name));
   }
 
   @Operator
   public Predicate<ProjectData> parent(String parentName) {
-    return ProjectPredicates.parent(new Project.NameKey(parentName));
+    return ProjectPredicates.parent(Project.nameKey(parentName));
   }
 
   @Operator
diff --git a/java/com/google/gerrit/server/restapi/access/ListAccess.java b/java/com/google/gerrit/server/restapi/access/ListAccess.java
index a3e9530..74c18e1 100644
--- a/java/com/google/gerrit/server/restapi/access/ListAccess.java
+++ b/java/com/google/gerrit/server/restapi/access/ListAccess.java
@@ -52,7 +52,7 @@
           PermissionBackendException {
     Map<String, ProjectAccessInfo> access = new TreeMap<>();
     for (String p : projects) {
-      access.put(p, getAccess.apply(new Project.NameKey(p)));
+      access.put(p, getAccess.apply(Project.nameKey(p)));
     }
     return access;
   }
diff --git a/java/com/google/gerrit/server/restapi/account/DeleteWatchedProjects.java b/java/com/google/gerrit/server/restapi/account/DeleteWatchedProjects.java
index 798aad1..666851b 100644
--- a/java/com/google/gerrit/server/restapi/account/DeleteWatchedProjects.java
+++ b/java/com/google/gerrit/server/restapi/account/DeleteWatchedProjects.java
@@ -77,7 +77,7 @@
                 u.deleteProjectWatches(
                     input.stream()
                         .filter(Objects::nonNull)
-                        .map(w -> ProjectWatchKey.create(new Project.NameKey(w.project), w.filter))
+                        .map(w -> ProjectWatchKey.create(Project.nameKey(w.project), w.filter))
                         .collect(toList())));
     return Response.none();
   }
diff --git a/java/com/google/gerrit/server/restapi/config/ListTasks.java b/java/com/google/gerrit/server/restapi/config/ListTasks.java
index 7402c15..6f18b24 100644
--- a/java/com/google/gerrit/server/restapi/config/ListTasks.java
+++ b/java/com/google/gerrit/server/restapi/config/ListTasks.java
@@ -83,7 +83,7 @@
       if (task.projectName != null) {
         Boolean visible = visibilityCache.get(task.projectName);
         if (visible == null) {
-          Project.NameKey nameKey = new Project.NameKey(task.projectName);
+          Project.NameKey nameKey = Project.nameKey(task.projectName);
           ProjectState state = projectCache.get(nameKey);
           if (state == null || !state.statePermitsRead()) {
             visible = false;
diff --git a/java/com/google/gerrit/server/restapi/project/CreateAccessChange.java b/java/com/google/gerrit/server/restapi/project/CreateAccessChange.java
index a81830b..7388587 100644
--- a/java/com/google/gerrit/server/restapi/project/CreateAccessChange.java
+++ b/java/com/google/gerrit/server/restapi/project/CreateAccessChange.java
@@ -112,7 +112,7 @@
     List<AccessSection> additions = setAccess.getAccessSections(input.add);
 
     Project.NameKey newParentProjectName =
-        input.parent == null ? null : new Project.NameKey(input.parent);
+        input.parent == null ? null : Project.nameKey(input.parent);
 
     try (MetaDataUpdate md = metaDataUpdateUser.create(rsrc.getNameKey())) {
       ProjectConfig config = projectConfigFactory.read(md);
diff --git a/java/com/google/gerrit/server/restapi/project/Index.java b/java/com/google/gerrit/server/restapi/project/Index.java
index bc58b23..6a95b62 100644
--- a/java/com/google/gerrit/server/restapi/project/Index.java
+++ b/java/com/google/gerrit/server/restapi/project/Index.java
@@ -60,7 +60,7 @@
     reindex(rsrc.getNameKey(), input.async);
     if (Boolean.TRUE.equals(input.indexChildren)) {
       for (ProjectInfo child : listChildProjectsProvider.get().withRecursive(true).apply(rsrc)) {
-        reindex(new Project.NameKey(child.name), input.async);
+        reindex(Project.nameKey(child.name), input.async);
       }
 
       response += " (indexing children recursively)";
diff --git a/java/com/google/gerrit/server/restapi/project/ListChildProjects.java b/java/com/google/gerrit/server/restapi/project/ListChildProjects.java
index 3879720..a846ef8 100644
--- a/java/com/google/gerrit/server/restapi/project/ListChildProjects.java
+++ b/java/com/google/gerrit/server/restapi/project/ListChildProjects.java
@@ -85,10 +85,7 @@
     PermissionBackend.WithUser currentUser = permissionBackend.currentUser();
     return queryProvider.get().withQuery("parent:" + parent.get()).withLimit(limit).apply().stream()
         .filter(
-            p ->
-                currentUser
-                    .project(new Project.NameKey(p.name))
-                    .testOrFalse(ProjectPermission.ACCESS))
+            p -> currentUser.project(Project.nameKey(p.name)).testOrFalse(ProjectPermission.ACCESS))
         .collect(toList());
   }
 }
diff --git a/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java b/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java
index 31c90e5..875dcfb 100644
--- a/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java
+++ b/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java
@@ -138,7 +138,7 @@
       throws IOException, PermissionBackendException, ResourceConflictException {
     id = ProjectUtil.sanitizeProjectName(id);
 
-    Project.NameKey nameKey = new Project.NameKey(id);
+    Project.NameKey nameKey = Project.nameKey(id);
     ProjectState state = projectCache.checkedGet(nameKey);
     if (state == null) {
       return null;
diff --git a/java/com/google/gerrit/server/restapi/project/SetAccess.java b/java/com/google/gerrit/server/restapi/project/SetAccess.java
index 5277cf8..1504d6c 100644
--- a/java/com/google/gerrit/server/restapi/project/SetAccess.java
+++ b/java/com/google/gerrit/server/restapi/project/SetAccess.java
@@ -117,7 +117,7 @@
           identifiedUser.get(),
           config,
           rsrc.getNameKey(),
-          input.parent == null ? null : new Project.NameKey(input.parent),
+          input.parent == null ? null : Project.nameKey(input.parent),
           !checkedAdmin);
 
       if (!Strings.isNullOrEmpty(input.message)) {
diff --git a/java/com/google/gerrit/server/restapi/project/SetParent.java b/java/com/google/gerrit/server/restapi/project/SetParent.java
index 12aaf76..e18066e 100644
--- a/java/com/google/gerrit/server/restapi/project/SetParent.java
+++ b/java/com/google/gerrit/server/restapi/project/SetParent.java
@@ -154,7 +154,7 @@
 
     newParent = Strings.emptyToNull(newParent);
     if (newParent != null) {
-      ProjectState parent = cache.get(new Project.NameKey(newParent));
+      ProjectState parent = cache.get(Project.nameKey(newParent));
       if (parent == null) {
         throw new UnprocessableEntityException("parent project " + newParent + " not found");
       }
diff --git a/java/com/google/gerrit/server/util/git/SubmoduleSectionParser.java b/java/com/google/gerrit/server/util/git/SubmoduleSectionParser.java
index 6833124f..85fd42a 100644
--- a/java/com/google/gerrit/server/util/git/SubmoduleSectionParser.java
+++ b/java/com/google/gerrit/server/util/git/SubmoduleSectionParser.java
@@ -133,7 +133,7 @@
                   0, //
                   project.length() - Constants.DOT_GIT_EXT.length());
         }
-        Project.NameKey projectKey = new Project.NameKey(project);
+        Project.NameKey projectKey = Project.nameKey(project);
         return new SubmoduleSubscription(
             superProjectBranch, Branch.nameKey(projectKey, branch), path);
       }
diff --git a/java/com/google/gerrit/sshd/commands/SetParentCommand.java b/java/com/google/gerrit/sshd/commands/SetParentCommand.java
index dfdf7f2..466db4c 100644
--- a/java/com/google/gerrit/sshd/commands/SetParentCommand.java
+++ b/java/com/google/gerrit/sshd/commands/SetParentCommand.java
@@ -160,7 +160,7 @@
       automaticallyExcluded.addAll(getAllParents(newParentKey));
     }
     for (ProjectInfo child : listChildProjects.apply(new ProjectResource(parent, user))) {
-      final Project.NameKey childName = new Project.NameKey(child.name);
+      final Project.NameKey childName = Project.nameKey(child.name);
       if (!excluded.contains(childName)) {
         if (!automaticallyExcluded.contains(childName)) {
           childProjects.add(childName);
diff --git a/java/com/google/gerrit/testing/InMemoryRepositoryManager.java b/java/com/google/gerrit/testing/InMemoryRepositoryManager.java
index e44d8d38..fd9818a 100644
--- a/java/com/google/gerrit/testing/InMemoryRepositoryManager.java
+++ b/java/com/google/gerrit/testing/InMemoryRepositoryManager.java
@@ -103,7 +103,7 @@
   public synchronized SortedSet<Project.NameKey> list() {
     SortedSet<Project.NameKey> names = Sets.newTreeSet();
     for (DfsRepository repo : repos.values()) {
-      names.add(new Project.NameKey(repo.getDescription().getRepositoryName()));
+      names.add(Project.nameKey(repo.getDescription().getRepositoryName()));
     }
     return ImmutableSortedSet.copyOf(names);
   }
diff --git a/javatests/com/google/gerrit/acceptance/ProjectResetterTest.java b/javatests/com/google/gerrit/acceptance/ProjectResetterTest.java
index 6a089e5..813c989 100644
--- a/javatests/com/google/gerrit/acceptance/ProjectResetterTest.java
+++ b/javatests/com/google/gerrit/acceptance/ProjectResetterTest.java
@@ -58,7 +58,7 @@
   @Before
   public void setUp() throws Exception {
     repoManager = new InMemoryRepositoryManager();
-    project = new Project.NameKey("foo");
+    project = Project.nameKey("foo");
     repo = repoManager.createRepository(project);
   }
 
@@ -135,7 +135,7 @@
 
   @Test
   public void onlyResetMatchingRefsMultipleProjects() throws Exception {
-    Project.NameKey project2 = new Project.NameKey("bar");
+    Project.NameKey project2 = Project.nameKey("bar");
     Repository repo2 = repoManager.createRepository(project2);
 
     Ref matchingRefProject1 = createRef("refs/foo/test");
@@ -170,7 +170,7 @@
 
   @Test
   public void onlyDeleteNewlyCreatedMatchingRefsMultipleProjects() throws Exception {
-    Project.NameKey project2 = new Project.NameKey("bar");
+    Project.NameKey project2 = Project.nameKey("bar");
     Repository repo2 = repoManager.createRepository(project2);
 
     Ref matchingRefProject1;
@@ -216,7 +216,7 @@
 
   @Test
   public void projectEvictionIfRefsMetaConfigIsReset() throws Exception {
-    Project.NameKey project2 = new Project.NameKey("bar");
+    Project.NameKey project2 = Project.nameKey("bar");
     Repository repo2 = repoManager.createRepository(project2);
     Ref metaConfig = createRef(repo2, RefNames.REFS_CONFIG);
 
@@ -239,7 +239,7 @@
 
   @Test
   public void projectEvictionIfRefsMetaConfigIsDeleted() throws Exception {
-    Project.NameKey project2 = new Project.NameKey("bar");
+    Project.NameKey project2 = Project.nameKey("bar");
     Repository repo2 = repoManager.createRepository(project2);
 
     ProjectCache projectCache = EasyMock.createNiceMock(ProjectCache.class);
@@ -260,7 +260,7 @@
   @Test
   public void accountEvictionIfUserBranchIsReset() throws Exception {
     Account.Id accountId = Account.id(1);
-    Project.NameKey allUsers = new Project.NameKey(AllUsersNameProvider.DEFAULT);
+    Project.NameKey allUsers = Project.nameKey(AllUsersNameProvider.DEFAULT);
     Repository allUsersRepo = repoManager.createRepository(allUsers);
     Ref userBranch = createRef(allUsersRepo, RefNames.refsUsers(accountId));
 
@@ -290,7 +290,7 @@
   @Test
   public void accountEvictionIfUserBranchIsDeleted() throws Exception {
     Account.Id accountId = Account.id(1);
-    Project.NameKey allUsers = new Project.NameKey(AllUsersNameProvider.DEFAULT);
+    Project.NameKey allUsers = Project.nameKey(AllUsersNameProvider.DEFAULT);
     Repository allUsersRepo = repoManager.createRepository(allUsers);
 
     AccountCache accountCache = EasyMock.createNiceMock(AccountCache.class);
@@ -318,7 +318,7 @@
   @Test
   public void accountEvictionIfExternalIdsBranchIsReset() throws Exception {
     Account.Id accountId = Account.id(1);
-    Project.NameKey allUsers = new Project.NameKey(AllUsersNameProvider.DEFAULT);
+    Project.NameKey allUsers = Project.nameKey(AllUsersNameProvider.DEFAULT);
     Repository allUsersRepo = repoManager.createRepository(allUsers);
     Ref externalIds = createRef(allUsersRepo, RefNames.REFS_EXTERNAL_IDS);
     createRef(allUsersRepo, RefNames.refsUsers(accountId));
@@ -356,7 +356,7 @@
   @Test
   public void accountEvictionIfExternalIdsBranchIsDeleted() throws Exception {
     Account.Id accountId = Account.id(1);
-    Project.NameKey allUsers = new Project.NameKey(AllUsersNameProvider.DEFAULT);
+    Project.NameKey allUsers = Project.nameKey(AllUsersNameProvider.DEFAULT);
     Repository allUsersRepo = repoManager.createRepository(allUsers);
     createRef(allUsersRepo, RefNames.refsUsers(accountId));
 
@@ -393,7 +393,7 @@
   @Test
   public void accountEvictionFromAccountCreatorIfUserBranchIsDeleted() throws Exception {
     Account.Id accountId = Account.id(1);
-    Project.NameKey allUsers = new Project.NameKey(AllUsersNameProvider.DEFAULT);
+    Project.NameKey allUsers = Project.nameKey(AllUsersNameProvider.DEFAULT);
     Repository allUsersRepo = repoManager.createRepository(allUsers);
 
     AccountCreator accountCreator = EasyMock.createNiceMock(AccountCreator.class);
@@ -415,7 +415,7 @@
     AccountGroup.UUID uuid1 = AccountGroup.uuid("abcd1");
     AccountGroup.UUID uuid2 = AccountGroup.uuid("abcd2");
     AccountGroup.UUID uuid3 = AccountGroup.uuid("abcd3");
-    Project.NameKey allUsers = new Project.NameKey(AllUsersNameProvider.DEFAULT);
+    Project.NameKey allUsers = Project.nameKey(AllUsersNameProvider.DEFAULT);
     Repository allUsersRepo = repoManager.createRepository(allUsers);
 
     GroupCache cache = EasyMock.createNiceMock(GroupCache.class);
diff --git a/javatests/com/google/gerrit/acceptance/api/change/AbandonIT.java b/javatests/com/google/gerrit/acceptance/api/change/AbandonIT.java
index 925c66a..27cb2e9 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/AbandonIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/AbandonIT.java
@@ -89,8 +89,8 @@
     String project2Name = name("Project2");
     gApi.projects().create(project1Name);
     gApi.projects().create(project2Name);
-    TestRepository<InMemoryRepository> project1 = cloneProject(new Project.NameKey(project1Name));
-    TestRepository<InMemoryRepository> project2 = cloneProject(new Project.NameKey(project2Name));
+    TestRepository<InMemoryRepository> project1 = cloneProject(Project.nameKey(project1Name));
+    TestRepository<InMemoryRepository> project2 = cloneProject(Project.nameKey(project2Name));
 
     CurrentUser user = atrScope.get().getUser();
     PushOneCommit.Result a = createChange(project1, "master", "x", "x", "x", "");
@@ -99,7 +99,7 @@
     exception.expect(ResourceConflictException.class);
     exception.expectMessage(
         String.format("Project name \"%s\" doesn't match \"%s\"", project2Name, project1Name));
-    batchAbandon.batchAbandon(batchUpdateFactory, new Project.NameKey(project1Name), user, list);
+    batchAbandon.batchAbandon(batchUpdateFactory, Project.nameKey(project1Name), user, list);
   }
 
   @Test
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
index 168b059..b4eb8c4 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -1035,7 +1035,7 @@
     in.createEmptyCommit = true;
     ProjectApi api = gApi.projects().create(in);
 
-    Project.NameKey nameKey = new Project.NameKey(api.get().name);
+    Project.NameKey nameKey = Project.nameKey(api.get().name);
 
     try (ProjectConfigUpdate u = updateProject(nameKey)) {
       Util.allow(u.getConfig(), Permission.DELETE_CHANGES, PROJECT_OWNERS, "refs/*");
diff --git a/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java b/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java
index 77350b0..1c38cdd 100644
--- a/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java
@@ -721,7 +721,7 @@
 
   @Nullable
   protected RevCommit getRemoteHead(String project, String branch) throws Exception {
-    return getRemoteHead(new Project.NameKey(project), branch);
+    return getRemoteHead(Project.nameKey(project), branch);
   }
 
   boolean hasHead(Project.NameKey k, String b) {
diff --git a/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsIT.java b/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsIT.java
index a04fe3c..2f551a5 100644
--- a/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsIT.java
+++ b/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsIT.java
@@ -108,7 +108,7 @@
   public void subscriptionWildcardACLForMissingProject() throws Exception {
 
     allowMatchingSubmoduleSubscription(
-        subKey, "refs/heads/*", new Project.NameKey("not-existing-super-project"), "refs/heads/*");
+        subKey, "refs/heads/*", Project.nameKey("not-existing-super-project"), "refs/heads/*");
     pushChangeTo(subRepo, "master");
   }
 
@@ -379,10 +379,7 @@
   @Test
   public void subscriptionFailOnWrongProjectACL() throws Exception {
     allowMatchingSubmoduleSubscription(
-        subKey,
-        "refs/heads/master",
-        new Project.NameKey("wrong-super-project"),
-        "refs/heads/master");
+        subKey, "refs/heads/master", Project.nameKey("wrong-super-project"), "refs/heads/master");
 
     pushChangeTo(subRepo, "master");
     createSubmoduleSubscription(superRepo, "master", subKey, "master");
diff --git a/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java b/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
index f09381d..8a86380 100644
--- a/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
+++ b/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
@@ -898,6 +898,6 @@
   }
 
   private Project.NameKey nameKey(String s) {
-    return new Project.NameKey(name(s));
+    return Project.nameKey(name(s));
   }
 }
diff --git a/javatests/com/google/gerrit/acceptance/pgm/AbstractReindexTests.java b/javatests/com/google/gerrit/acceptance/pgm/AbstractReindexTests.java
index c07d512..bed280d 100644
--- a/javatests/com/google/gerrit/acceptance/pgm/AbstractReindexTests.java
+++ b/javatests/com/google/gerrit/acceptance/pgm/AbstractReindexTests.java
@@ -223,7 +223,7 @@
   }
 
   private void setUpChange() throws Exception {
-    project = new Project.NameKey("reindex-project-test");
+    project = Project.nameKey("reindex-project-test");
     try (ServerContext ctx = startServer()) {
       configureIndex(ctx.getInjector());
       GerritApi gApi = ctx.getInjector().getInstance(GerritApi.class);
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java b/javatests/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java
index 32654bd..8331a73 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java
@@ -1211,7 +1211,7 @@
     ChangeInfo c = get(changeId, CURRENT_REVISION);
     assertThat(c.currentRevision).isEqualTo(expectedId.name());
     assertThat(c.revisions.get(expectedId.name())._number).isEqualTo(expectedNum);
-    try (Repository repo = repoManager.openRepository(new Project.NameKey(c.project))) {
+    try (Repository repo = repoManager.openRepository(Project.nameKey(c.project))) {
       String refName = PatchSet.id(new Change.Id(c._number), expectedNum).toRefName();
       Ref ref = repo.exactRef(refName);
       assertThat(ref).named(refName).isNotNull();
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/SubmitResolvingMergeCommitIT.java b/javatests/com/google/gerrit/acceptance/rest/change/SubmitResolvingMergeCommitIT.java
index 87fc9f6..78349f5 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/SubmitResolvingMergeCommitIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/SubmitResolvingMergeCommitIT.java
@@ -186,8 +186,8 @@
     String project2Name = name("Project2");
     gApi.projects().create(project1Name);
     gApi.projects().create(project2Name);
-    TestRepository<InMemoryRepository> project1 = cloneProject(new Project.NameKey(project1Name));
-    TestRepository<InMemoryRepository> project2 = cloneProject(new Project.NameKey(project2Name));
+    TestRepository<InMemoryRepository> project1 = cloneProject(Project.nameKey(project1Name));
+    TestRepository<InMemoryRepository> project2 = cloneProject(Project.nameKey(project2Name));
 
     PushOneCommit.Result a = createChange(project1, "A");
     PushOneCommit.Result b =
diff --git a/javatests/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java b/javatests/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
index 5993dad..e5bafc7 100644
--- a/javatests/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
@@ -86,7 +86,7 @@
     // for more extensive coverage of the LabelTypeInfo.
     assertThat(p.labels).hasSize(1);
 
-    ProjectState projectState = projectCache.get(new Project.NameKey(newProjectName));
+    ProjectState projectState = projectCache.get(Project.nameKey(newProjectName));
     assertThat(projectState).isNotNull();
     assertProjectInfo(projectState.getProject(), p);
     assertHead(newProjectName, "refs/heads/master");
@@ -162,7 +162,7 @@
     String newProjectName = name("newProject");
     ProjectInfo p = gApi.projects().create(newProjectName).get();
     assertThat(p.name).isEqualTo(newProjectName);
-    ProjectState projectState = projectCache.get(new Project.NameKey(newProjectName));
+    ProjectState projectState = projectCache.get(Project.nameKey(newProjectName));
     assertThat(projectState).isNotNull();
     assertProjectInfo(projectState.getProject(), p);
     assertHead(newProjectName, "refs/heads/master");
@@ -175,7 +175,7 @@
     String newProjectName = name("newProject");
     ProjectInfo p = gApi.projects().create(newProjectName + ".git").get();
     assertThat(p.name).isEqualTo(newProjectName);
-    ProjectState projectState = projectCache.get(new Project.NameKey(newProjectName));
+    ProjectState projectState = projectCache.get(Project.nameKey(newProjectName));
     assertThat(projectState).isNotNull();
     assertProjectInfo(projectState.getProject(), p);
     assertHead(newProjectName, "refs/heads/master");
@@ -186,7 +186,7 @@
     String newProjectName = name("newProject");
     ProjectInfo p = gApi.projects().create(newProjectName + "/").get();
     assertThat(p.name).isEqualTo(newProjectName);
-    ProjectState projectState = projectCache.get(new Project.NameKey(newProjectName));
+    ProjectState projectState = projectCache.get(Project.nameKey(newProjectName));
     assertThat(projectState).isNotNull();
     assertProjectInfo(projectState.getProject(), p);
     assertHead(newProjectName, "refs/heads/master");
@@ -197,7 +197,7 @@
     String newProjectName = name("newProject/newProject");
     ProjectInfo p = gApi.projects().create(newProjectName).get();
     assertThat(p.name).isEqualTo(newProjectName);
-    ProjectState projectState = projectCache.get(new Project.NameKey(newProjectName));
+    ProjectState projectState = projectCache.get(Project.nameKey(newProjectName));
     assertThat(projectState).isNotNull();
     assertProjectInfo(projectState.getProject(), p);
     assertHead(newProjectName, "refs/heads/master");
@@ -216,7 +216,7 @@
     in.requireChangeId = InheritableBoolean.TRUE;
     ProjectInfo p = gApi.projects().create(in).get();
     assertThat(p.name).isEqualTo(newProjectName);
-    Project project = projectCache.get(new Project.NameKey(newProjectName)).getProject();
+    Project project = projectCache.get(Project.nameKey(newProjectName)).getProject();
     assertProjectInfo(project, p);
     assertThat(project.getDescription()).isEqualTo(in.description);
     assertThat(project.getConfiguredSubmitType()).isEqualTo(in.submitType);
@@ -242,7 +242,7 @@
     in.name = childName;
     in.parent = parentName;
     gApi.projects().create(in);
-    Project project = projectCache.get(new Project.NameKey(childName)).getProject();
+    Project project = projectCache.get(Project.nameKey(childName)).getProject();
     assertThat(project.getParentName()).isEqualTo(in.parent);
   }
 
@@ -270,7 +270,7 @@
                 .getId()
                 .get())); // by ID
     gApi.projects().create(in);
-    ProjectState projectState = projectCache.get(new Project.NameKey(newProjectName));
+    ProjectState projectState = projectCache.get(Project.nameKey(newProjectName));
     Set<AccountGroup.UUID> expectedOwnerIds = Sets.newHashSetWithExpectedSize(3);
     expectedOwnerIds.add(SystemGroupBackend.ANONYMOUS_USERS);
     expectedOwnerIds.add(SystemGroupBackend.REGISTERED_USERS);
@@ -447,13 +447,13 @@
   }
 
   private void assertHead(String projectName, String expectedRef) throws Exception {
-    try (Repository repo = repoManager.openRepository(new Project.NameKey(projectName))) {
+    try (Repository repo = repoManager.openRepository(Project.nameKey(projectName))) {
       assertThat(repo.exactRef(Constants.HEAD).getTarget().getName()).isEqualTo(expectedRef);
     }
   }
 
   private void assertEmptyCommit(String projectName, String... refs) throws Exception {
-    Project.NameKey projectKey = new Project.NameKey(projectName);
+    Project.NameKey projectKey = Project.nameKey(projectName);
     try (Repository repo = repoManager.openRepository(projectKey);
         RevWalk rw = new RevWalk(repo);
         TreeWalk tw = new TreeWalk(rw.getObjectReader())) {
@@ -474,7 +474,7 @@
   }
 
   private Optional<String> readProjectConfig(String projectName) throws Exception {
-    try (Repository repo = repoManager.openRepository(new Project.NameKey(projectName))) {
+    try (Repository repo = repoManager.openRepository(Project.nameKey(projectName))) {
       TestRepository<?> tr = new TestRepository<>(repo);
       RevWalk rw = tr.getRevWalk();
       Ref ref = repo.exactRef(RefNames.REFS_CONFIG);
diff --git a/javatests/com/google/gerrit/acceptance/rest/project/ListProjectsIT.java b/javatests/com/google/gerrit/acceptance/rest/project/ListProjectsIT.java
index d9b8e03..f29069c 100644
--- a/javatests/com/google/gerrit/acceptance/rest/project/ListProjectsIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/project/ListProjectsIT.java
@@ -240,7 +240,7 @@
     int n = 5;
     assertThat(all).hasSize(n);
     assertThatNameList(gApi.projects().list().withPrefix(pre).withStart(n - 1).get())
-        .containsExactly(new Project.NameKey(Iterables.getLast(all).name));
+        .containsExactly(Project.nameKey(Iterables.getLast(all).name));
   }
 
   @Test
diff --git a/javatests/com/google/gerrit/acceptance/rest/project/ProjectAssert.java b/javatests/com/google/gerrit/acceptance/rest/project/ProjectAssert.java
index 3b5a3a4..45f59e9 100644
--- a/javatests/com/google/gerrit/acceptance/rest/project/ProjectAssert.java
+++ b/javatests/com/google/gerrit/acceptance/rest/project/ProjectAssert.java
@@ -38,7 +38,7 @@
           .that(Url.decode(info.id))
           .isEqualTo(info.name);
     }
-    return assertThat(Iterables.transform(actual, p -> new Project.NameKey(p.name)));
+    return assertThat(Iterables.transform(actual, p -> Project.nameKey(p.name)));
   }
 
   public static void assertProjectInfo(Project project, ProjectInfo info) {
@@ -47,7 +47,7 @@
       assertThat(info.name).isEqualTo(project.getName());
     }
     assertThat(Url.decode(info.id)).isEqualTo(project.getName());
-    Project.NameKey parentName = project.getParent(new Project.NameKey("All-Projects"));
+    Project.NameKey parentName = project.getParent(Project.nameKey("All-Projects"));
     if (parentName != null) {
       assertThat(info.parent).isEqualTo(parentName.get());
     } else {
diff --git a/javatests/com/google/gerrit/acceptance/server/project/ProjectWatchIT.java b/javatests/com/google/gerrit/acceptance/server/project/ProjectWatchIT.java
index 646cc07..f3b5009 100644
--- a/javatests/com/google/gerrit/acceptance/server/project/ProjectWatchIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/project/ProjectWatchIT.java
@@ -218,7 +218,7 @@
     // push a change to watched project -> should trigger email notification
     requestScopeOperations.setApiUser(admin.id());
     TestRepository<InMemoryRepository> watchedRepo =
-        cloneProject(new Project.NameKey(watchedProject), admin);
+        cloneProject(Project.nameKey(watchedProject), admin);
     PushOneCommit.Result r =
         pushFactory
             .create(admin.newIdent(), watchedRepo, "TRIGGER", "a", "a1")
@@ -229,7 +229,7 @@
     // notification
     String notWatchedProject = projectOperations.newProject().create().get();
     TestRepository<InMemoryRepository> notWatchedRepo =
-        cloneProject(new Project.NameKey(notWatchedProject), admin);
+        cloneProject(Project.nameKey(notWatchedProject), admin);
     r =
         pushFactory
             .create(admin.newIdent(), notWatchedRepo, "DONT_TRIGGER", "a", "a1")
@@ -261,7 +261,7 @@
     // user
     requestScopeOperations.setApiUser(admin.id());
     TestRepository<InMemoryRepository> watchedRepo =
-        cloneProject(new Project.NameKey(watchedProject), admin);
+        cloneProject(Project.nameKey(watchedProject), admin);
     PushOneCommit.Result r =
         pushFactory
             .create(admin.newIdent(), watchedRepo, "TRIGGER", "a.txt", "a1")
@@ -310,7 +310,7 @@
     // push a change with keyword -> should trigger email notification
     requestScopeOperations.setApiUser(admin.id());
     TestRepository<InMemoryRepository> watchedRepo =
-        cloneProject(new Project.NameKey(watchedProject), admin);
+        cloneProject(Project.nameKey(watchedProject), admin);
     PushOneCommit.Result r =
         pushFactory
             .create(admin.newIdent(), watchedRepo, "Document multimaster setup", "a.txt", "a1")
@@ -347,8 +347,7 @@
 
     // push a change to any project -> should trigger email notification
     requestScopeOperations.setApiUser(admin.id());
-    TestRepository<InMemoryRepository> anyRepo =
-        cloneProject(new Project.NameKey(anyProject), admin);
+    TestRepository<InMemoryRepository> anyRepo = cloneProject(Project.nameKey(anyProject), admin);
     PushOneCommit.Result r =
         pushFactory.create(admin.newIdent(), anyRepo, "TRIGGER", "a", "a1").to("refs/for/master");
     r.assertOkStatus();
@@ -374,8 +373,7 @@
     // push a change to watched file in any project -> should trigger email
     // notification for user
     requestScopeOperations.setApiUser(admin.id());
-    TestRepository<InMemoryRepository> anyRepo =
-        cloneProject(new Project.NameKey(anyProject), admin);
+    TestRepository<InMemoryRepository> anyRepo = cloneProject(Project.nameKey(anyProject), admin);
     PushOneCommit.Result r =
         pushFactory
             .create(admin.newIdent(), anyRepo, "TRIGGER", "a.txt", "a1")
@@ -424,8 +422,7 @@
     // push a change with keyword to any project -> should trigger email
     // notification
     requestScopeOperations.setApiUser(admin.id());
-    TestRepository<InMemoryRepository> anyRepo =
-        cloneProject(new Project.NameKey(anyProject), admin);
+    TestRepository<InMemoryRepository> anyRepo = cloneProject(Project.nameKey(anyProject), admin);
     PushOneCommit.Result r =
         pushFactory
             .create(admin.newIdent(), anyRepo, "Document multimaster setup", "a.txt", "a1")
@@ -463,7 +460,7 @@
     // push a change to watched project
     requestScopeOperations.setApiUser(admin.id());
     TestRepository<InMemoryRepository> watchedRepo =
-        cloneProject(new Project.NameKey(watchedProject), admin);
+        cloneProject(Project.nameKey(watchedProject), admin);
     PushOneCommit.Result r =
         pushFactory
             .create(admin.newIdent(), watchedRepo, "ignored change", "a", "a1")
@@ -496,7 +493,7 @@
     // push a private change to watched project -> should not trigger email notification
     requestScopeOperations.setApiUser(admin.id());
     TestRepository<InMemoryRepository> watchedRepo =
-        cloneProject(new Project.NameKey(watchedProject), admin);
+        cloneProject(Project.nameKey(watchedProject), admin);
     PushOneCommit.Result r =
         pushFactory
             .create(admin.newIdent(), watchedRepo, "private change", "a", "a1")
@@ -515,7 +512,7 @@
     GroupInfo groupThatCanViewPrivateChanges =
         gApi.groups().create("groupThatCanViewPrivateChanges").get();
     grant(
-        new Project.NameKey(watchedProject),
+        Project.nameKey(watchedProject),
         "refs/*",
         Permission.VIEW_PRIVATE_CHANGES,
         false,
@@ -536,7 +533,7 @@
     // userThatCanViewPrivateChanges, but not for user
     requestScopeOperations.setApiUser(admin.id());
     TestRepository<InMemoryRepository> watchedRepo =
-        cloneProject(new Project.NameKey(watchedProject), admin);
+        cloneProject(Project.nameKey(watchedProject), admin);
     PushOneCommit.Result r =
         pushFactory
             .create(admin.newIdent(), watchedRepo, "TRIGGER", "a", "a1")
diff --git a/javatests/com/google/gerrit/acceptance/ssh/CreateProjectIT.java b/javatests/com/google/gerrit/acceptance/ssh/CreateProjectIT.java
index 0ce05b0..007ad89 100644
--- a/javatests/com/google/gerrit/acceptance/ssh/CreateProjectIT.java
+++ b/javatests/com/google/gerrit/acceptance/ssh/CreateProjectIT.java
@@ -33,7 +33,7 @@
     adminSshSession.exec(
         "gerrit create-project --branch master --owner " + newGroupName + " " + newProjectName);
     adminSshSession.assertSuccess();
-    ProjectState projectState = projectCache.get(new Project.NameKey(newProjectName));
+    ProjectState projectState = projectCache.get(Project.nameKey(newProjectName));
     assertThat(projectState).isNotNull();
   }
 
@@ -46,7 +46,7 @@
     adminSshSession.exec(
         "gerrit create-project --branch master --owner " + wrongGroupName + " " + newProjectName);
     adminSshSession.assertFailure();
-    ProjectState projectState = projectCache.get(new Project.NameKey(newProjectName));
+    ProjectState projectState = projectCache.get(Project.nameKey(newProjectName));
     assertThat(projectState).isNull();
   }
 
@@ -62,7 +62,7 @@
             + newProjectName
             + ".git");
     adminSshSession.assertSuccess();
-    ProjectState projectState = projectCache.get(new Project.NameKey(newProjectName));
+    ProjectState projectState = projectCache.get(Project.nameKey(newProjectName));
     assertThat(projectState).isNotNull();
     assertThat(projectState.getName()).isEqualTo(newProjectName);
   }
@@ -79,7 +79,7 @@
             + newProjectName
             + "/");
     adminSshSession.assertSuccess();
-    ProjectState projectState = projectCache.get(new Project.NameKey(newProjectName));
+    ProjectState projectState = projectCache.get(Project.nameKey(newProjectName));
     assertThat(projectState).isNotNull();
     assertThat(projectState.getName()).isEqualTo(newProjectName);
   }
diff --git a/javatests/com/google/gerrit/reviewdb/client/ProjectTest.java b/javatests/com/google/gerrit/reviewdb/client/ProjectTest.java
index 537df5f..b97b0b8 100644
--- a/javatests/com/google/gerrit/reviewdb/client/ProjectTest.java
+++ b/javatests/com/google/gerrit/reviewdb/client/ProjectTest.java
@@ -31,10 +31,10 @@
 
   @Test
   public void idToString() {
-    assertThat(new Project.NameKey("foo").toString()).isEqualTo("foo");
-    assertThat(new Project.NameKey("foo bar").toString()).isEqualTo("foo+bar");
-    assertThat(new Project.NameKey("foo/bar").toString()).isEqualTo("foo/bar");
-    assertThat(new Project.NameKey("foo^bar").toString()).isEqualTo("foo%5Ebar");
-    assertThat(new Project.NameKey("foo%bar").toString()).isEqualTo("foo%25bar");
+    assertThat(Project.nameKey("foo").toString()).isEqualTo("foo");
+    assertThat(Project.nameKey("foo bar").toString()).isEqualTo("foo+bar");
+    assertThat(Project.nameKey("foo/bar").toString()).isEqualTo("foo/bar");
+    assertThat(Project.nameKey("foo^bar").toString()).isEqualTo("foo%5Ebar");
+    assertThat(Project.nameKey("foo%bar").toString()).isEqualTo("foo%25bar");
   }
 }
diff --git a/javatests/com/google/gerrit/reviewdb/converter/BranchNameKeyProtoConverterTest.java b/javatests/com/google/gerrit/reviewdb/converter/BranchNameKeyProtoConverterTest.java
index 1186d9b..0e62a6b 100644
--- a/javatests/com/google/gerrit/reviewdb/converter/BranchNameKeyProtoConverterTest.java
+++ b/javatests/com/google/gerrit/reviewdb/converter/BranchNameKeyProtoConverterTest.java
@@ -33,7 +33,7 @@
 
   @Test
   public void allValuesConvertedToProto() {
-    Branch.NameKey nameKey = Branch.nameKey(new Project.NameKey("project-13"), "branch-72");
+    Branch.NameKey nameKey = Branch.nameKey(Project.nameKey("project-13"), "branch-72");
 
     Entities.Branch_NameKey proto = branchNameKeyProtoConverter.toProto(nameKey);
 
@@ -47,7 +47,7 @@
 
   @Test
   public void allValuesConvertedToProtoAndBackAgain() {
-    Branch.NameKey nameKey = Branch.nameKey(new Project.NameKey("project-52"), "branch 14");
+    Branch.NameKey nameKey = Branch.nameKey(Project.nameKey("project-52"), "branch 14");
 
     Branch.NameKey convertedNameKey =
         branchNameKeyProtoConverter.fromProto(branchNameKeyProtoConverter.toProto(nameKey));
diff --git a/javatests/com/google/gerrit/reviewdb/converter/ChangeProtoConverterTest.java b/javatests/com/google/gerrit/reviewdb/converter/ChangeProtoConverterTest.java
index 7ab1aac..1d668f2 100644
--- a/javatests/com/google/gerrit/reviewdb/converter/ChangeProtoConverterTest.java
+++ b/javatests/com/google/gerrit/reviewdb/converter/ChangeProtoConverterTest.java
@@ -41,7 +41,7 @@
             new Change.Key("change 1"),
             new Change.Id(14),
             Account.id(35),
-            Branch.nameKey(new Project.NameKey("project 67"), "branch 74"),
+            Branch.nameKey(Project.nameKey("project 67"), "branch 74"),
             new Timestamp(987654L));
     change.setLastUpdatedOn(new Timestamp(1234567L));
     change.setStatus(Change.Status.MERGED);
@@ -91,7 +91,7 @@
             new Change.Key("change 1"),
             new Change.Id(14),
             Account.id(35),
-            Branch.nameKey(new Project.NameKey("project 67"), "branch-74"),
+            Branch.nameKey(Project.nameKey("project 67"), "branch-74"),
             new Timestamp(987654L));
 
     Entities.Change proto = changeProtoConverter.toProto(change);
@@ -127,7 +127,7 @@
             new Change.Key("change 1"),
             new Change.Id(14),
             Account.id(35),
-            Branch.nameKey(new Project.NameKey("project 67"), "branch-74"),
+            Branch.nameKey(Project.nameKey("project 67"), "branch-74"),
             new Timestamp(987654L));
     // O as ID actually means that no current patch set is present.
     change.setCurrentPatchSet(PatchSet.id(new Change.Id(14), 0), null, null);
@@ -165,7 +165,7 @@
             new Change.Key("change 1"),
             new Change.Id(14),
             Account.id(35),
-            Branch.nameKey(new Project.NameKey("project 67"), "branch-74"),
+            Branch.nameKey(Project.nameKey("project 67"), "branch-74"),
             new Timestamp(987654L));
     change.setCurrentPatchSet(PatchSet.id(new Change.Id(14), 23), "subject ABC", null);
 
@@ -202,7 +202,7 @@
             new Change.Key("change 1"),
             new Change.Id(14),
             Account.id(35),
-            Branch.nameKey(new Project.NameKey("project 67"), "branch-74"),
+            Branch.nameKey(Project.nameKey("project 67"), "branch-74"),
             new Timestamp(987654L));
     change.setLastUpdatedOn(new Timestamp(1234567L));
     change.setStatus(Change.Status.MERGED);
@@ -227,7 +227,7 @@
             new Change.Key("change 1"),
             new Change.Id(14),
             Account.id(35),
-            Branch.nameKey(new Project.NameKey("project 67"), "branch-74"),
+            Branch.nameKey(Project.nameKey("project 67"), "branch-74"),
             new Timestamp(987654L));
 
     Change convertedChange = changeProtoConverter.fromProto(changeProtoConverter.toProto(change));
diff --git a/javatests/com/google/gerrit/reviewdb/converter/ProjectNameKeyProtoConverterTest.java b/javatests/com/google/gerrit/reviewdb/converter/ProjectNameKeyProtoConverterTest.java
index 2ad6107..05e2893 100644
--- a/javatests/com/google/gerrit/reviewdb/converter/ProjectNameKeyProtoConverterTest.java
+++ b/javatests/com/google/gerrit/reviewdb/converter/ProjectNameKeyProtoConverterTest.java
@@ -31,7 +31,7 @@
 
   @Test
   public void allValuesConvertedToProto() {
-    Project.NameKey nameKey = new Project.NameKey("project-72");
+    Project.NameKey nameKey = Project.nameKey("project-72");
 
     Entities.Project_NameKey proto = projectNameKeyProtoConverter.toProto(nameKey);
 
@@ -42,7 +42,7 @@
 
   @Test
   public void allValuesConvertedToProtoAndBackAgain() {
-    Project.NameKey nameKey = new Project.NameKey("project-52");
+    Project.NameKey nameKey = Project.nameKey("project-52");
 
     Project.NameKey convertedNameKey =
         projectNameKeyProtoConverter.fromProto(projectNameKeyProtoConverter.toProto(nameKey));
diff --git a/javatests/com/google/gerrit/server/account/DestinationListTest.java b/javatests/com/google/gerrit/server/account/DestinationListTest.java
index fd8ca13..a216162 100644
--- a/javatests/com/google/gerrit/server/account/DestinationListTest.java
+++ b/javatests/com/google/gerrit/server/account/DestinationListTest.java
@@ -68,7 +68,7 @@
   }
 
   private static Branch.NameKey dest(String project, String ref) {
-    return Branch.nameKey(new Project.NameKey(project), ref);
+    return Branch.nameKey(Project.nameKey(project), ref);
   }
 
   @Test
diff --git a/javatests/com/google/gerrit/server/account/WatchConfigTest.java b/javatests/com/google/gerrit/server/account/WatchConfigTest.java
index 12aa807..24251cb 100644
--- a/javatests/com/google/gerrit/server/account/WatchConfigTest.java
+++ b/javatests/com/google/gerrit/server/account/WatchConfigTest.java
@@ -58,8 +58,8 @@
 
     assertThat(validationErrors).isEmpty();
 
-    Project.NameKey myProject = new Project.NameKey("myProject");
-    Project.NameKey otherProject = new Project.NameKey("otherProject");
+    Project.NameKey myProject = Project.nameKey("myProject");
+    Project.NameKey otherProject = Project.nameKey("otherProject");
     Map<ProjectWatchKey, Set<NotifyType>> expectedProjectWatches = new HashMap<>();
     expectedProjectWatches.put(
         ProjectWatchKey.create(myProject, null),
diff --git a/javatests/com/google/gerrit/server/change/WalkSorterTest.java b/javatests/com/google/gerrit/server/change/WalkSorterTest.java
index 96862ea..0a9220c 100644
--- a/javatests/com/google/gerrit/server/change/WalkSorterTest.java
+++ b/javatests/com/google/gerrit/server/change/WalkSorterTest.java
@@ -353,7 +353,7 @@
   }
 
   private TestRepository<Repo> newRepo(String name) throws Exception {
-    return new TestRepository<>(repoManager.createRepository(new Project.NameKey(name)));
+    return new TestRepository<>(repoManager.createRepository(Project.nameKey(name)));
   }
 
   private static PatchSetData patchSetData(ChangeData cd, RevCommit commit) throws Exception {
diff --git a/javatests/com/google/gerrit/server/config/AllProjectsNameTest.java b/javatests/com/google/gerrit/server/config/AllProjectsNameTest.java
index e996976..979967d 100644
--- a/javatests/com/google/gerrit/server/config/AllProjectsNameTest.java
+++ b/javatests/com/google/gerrit/server/config/AllProjectsNameTest.java
@@ -24,7 +24,7 @@
   public void equalToProjectNameKey() {
     String name = "a-project";
     AllProjectsName allProjectsName = new AllProjectsName(name);
-    Project.NameKey projectName = new Project.NameKey(name);
+    Project.NameKey projectName = Project.nameKey(name);
     assertThat(allProjectsName.get()).isEqualTo(projectName.get());
     assertThat(allProjectsName).isEqualTo(projectName);
   }
diff --git a/javatests/com/google/gerrit/server/config/AllUsersNameTest.java b/javatests/com/google/gerrit/server/config/AllUsersNameTest.java
index a4d56cd..4edc923 100644
--- a/javatests/com/google/gerrit/server/config/AllUsersNameTest.java
+++ b/javatests/com/google/gerrit/server/config/AllUsersNameTest.java
@@ -24,7 +24,7 @@
   public void equalToProjectNameKey() {
     String name = "a-project";
     AllUsersName allUsersName = new AllUsersName(name);
-    Project.NameKey projectName = new Project.NameKey(name);
+    Project.NameKey projectName = Project.nameKey(name);
     assertThat(allUsersName.get()).isEqualTo(projectName.get());
     assertThat(allUsersName).isEqualTo(projectName);
   }
diff --git a/javatests/com/google/gerrit/server/config/RepositoryConfigTest.java b/javatests/com/google/gerrit/server/config/RepositoryConfigTest.java
index 2a473f4..b62aeb6 100644
--- a/javatests/com/google/gerrit/server/config/RepositoryConfigTest.java
+++ b/javatests/com/google/gerrit/server/config/RepositoryConfigTest.java
@@ -42,35 +42,35 @@
   @Test
   public void defaultSubmitTypeWhenNotConfigured() {
     // Check expected value explicitly rather than depending on constant.
-    assertThat(repoCfg.getDefaultSubmitType(new Project.NameKey("someProject")))
+    assertThat(repoCfg.getDefaultSubmitType(Project.nameKey("someProject")))
         .isEqualTo(SubmitType.INHERIT);
   }
 
   @Test
   public void defaultSubmitTypeForStarFilter() {
     configureDefaultSubmitType("*", SubmitType.CHERRY_PICK);
-    assertThat(repoCfg.getDefaultSubmitType(new Project.NameKey("someProject")))
+    assertThat(repoCfg.getDefaultSubmitType(Project.nameKey("someProject")))
         .isEqualTo(SubmitType.CHERRY_PICK);
 
     configureDefaultSubmitType("*", SubmitType.FAST_FORWARD_ONLY);
-    assertThat(repoCfg.getDefaultSubmitType(new Project.NameKey("someProject")))
+    assertThat(repoCfg.getDefaultSubmitType(Project.nameKey("someProject")))
         .isEqualTo(SubmitType.FAST_FORWARD_ONLY);
 
     configureDefaultSubmitType("*", SubmitType.REBASE_IF_NECESSARY);
-    assertThat(repoCfg.getDefaultSubmitType(new Project.NameKey("someProject")))
+    assertThat(repoCfg.getDefaultSubmitType(Project.nameKey("someProject")))
         .isEqualTo(SubmitType.REBASE_IF_NECESSARY);
 
     configureDefaultSubmitType("*", SubmitType.REBASE_ALWAYS);
-    assertThat(repoCfg.getDefaultSubmitType(new Project.NameKey("someProject")))
+    assertThat(repoCfg.getDefaultSubmitType(Project.nameKey("someProject")))
         .isEqualTo(SubmitType.REBASE_ALWAYS);
   }
 
   @Test
   public void defaultSubmitTypeForSpecificFilter() {
     configureDefaultSubmitType("someProject", SubmitType.CHERRY_PICK);
-    assertThat(repoCfg.getDefaultSubmitType(new Project.NameKey("someOtherProject")))
+    assertThat(repoCfg.getDefaultSubmitType(Project.nameKey("someOtherProject")))
         .isEqualTo(RepositoryConfig.DEFAULT_SUBMIT_TYPE);
-    assertThat(repoCfg.getDefaultSubmitType(new Project.NameKey("someProject")))
+    assertThat(repoCfg.getDefaultSubmitType(Project.nameKey("someProject")))
         .isEqualTo(SubmitType.CHERRY_PICK);
   }
 
@@ -80,13 +80,13 @@
     configureDefaultSubmitType("somePath/*", SubmitType.CHERRY_PICK);
     configureDefaultSubmitType("*", SubmitType.MERGE_ALWAYS);
 
-    assertThat(repoCfg.getDefaultSubmitType(new Project.NameKey("someProject")))
+    assertThat(repoCfg.getDefaultSubmitType(Project.nameKey("someProject")))
         .isEqualTo(SubmitType.MERGE_ALWAYS);
 
-    assertThat(repoCfg.getDefaultSubmitType(new Project.NameKey("somePath/someProject")))
+    assertThat(repoCfg.getDefaultSubmitType(Project.nameKey("somePath/someProject")))
         .isEqualTo(SubmitType.CHERRY_PICK);
 
-    assertThat(repoCfg.getDefaultSubmitType(new Project.NameKey("somePath/somePath/someProject")))
+    assertThat(repoCfg.getDefaultSubmitType(Project.nameKey("somePath/somePath/someProject")))
         .isEqualTo(SubmitType.REBASE_IF_NECESSARY);
   }
 
@@ -100,14 +100,14 @@
 
   @Test
   public void ownerGroupsWhenNotConfigured() {
-    assertThat(repoCfg.getOwnerGroups(new Project.NameKey("someProject"))).isEmpty();
+    assertThat(repoCfg.getOwnerGroups(Project.nameKey("someProject"))).isEmpty();
   }
 
   @Test
   public void ownerGroupsForStarFilter() {
     ImmutableList<String> ownerGroups = ImmutableList.of("group1", "group2");
     configureOwnerGroups("*", ownerGroups);
-    assertThat(repoCfg.getOwnerGroups(new Project.NameKey("someProject")))
+    assertThat(repoCfg.getOwnerGroups(Project.nameKey("someProject")))
         .containsExactlyElementsIn(ownerGroups);
   }
 
@@ -115,8 +115,8 @@
   public void ownerGroupsForSpecificFilter() {
     ImmutableList<String> ownerGroups = ImmutableList.of("group1", "group2");
     configureOwnerGroups("someProject", ownerGroups);
-    assertThat(repoCfg.getOwnerGroups(new Project.NameKey("someOtherProject"))).isEmpty();
-    assertThat(repoCfg.getOwnerGroups(new Project.NameKey("someProject")))
+    assertThat(repoCfg.getOwnerGroups(Project.nameKey("someOtherProject"))).isEmpty();
+    assertThat(repoCfg.getOwnerGroups(Project.nameKey("someProject")))
         .containsExactlyElementsIn(ownerGroups);
   }
 
@@ -130,13 +130,13 @@
     configureOwnerGroups("somePath/*", ownerGroups2);
     configureOwnerGroups("somePath/somePath/*", ownerGroups3);
 
-    assertThat(repoCfg.getOwnerGroups(new Project.NameKey("someProject")))
+    assertThat(repoCfg.getOwnerGroups(Project.nameKey("someProject")))
         .containsExactlyElementsIn(ownerGroups1);
 
-    assertThat(repoCfg.getOwnerGroups(new Project.NameKey("somePath/someProject")))
+    assertThat(repoCfg.getOwnerGroups(Project.nameKey("somePath/someProject")))
         .containsExactlyElementsIn(ownerGroups2);
 
-    assertThat(repoCfg.getOwnerGroups(new Project.NameKey("somePath/somePath/someProject")))
+    assertThat(repoCfg.getOwnerGroups(Project.nameKey("somePath/somePath/someProject")))
         .containsExactlyElementsIn(ownerGroups3);
   }
 
@@ -150,24 +150,22 @@
 
   @Test
   public void basePathWhenNotConfigured() {
-    assertThat(repoCfg.getBasePath(new Project.NameKey("someProject"))).isNull();
+    assertThat(repoCfg.getBasePath(Project.nameKey("someProject"))).isNull();
   }
 
   @Test
   public void basePathForStarFilter() {
     String basePath = "/someAbsolutePath/someDirectory";
     configureBasePath("*", basePath);
-    assertThat(repoCfg.getBasePath(new Project.NameKey("someProject")).toString())
-        .isEqualTo(basePath);
+    assertThat(repoCfg.getBasePath(Project.nameKey("someProject")).toString()).isEqualTo(basePath);
   }
 
   @Test
   public void basePathForSpecificFilter() {
     String basePath = "/someAbsolutePath/someDirectory";
     configureBasePath("someProject", basePath);
-    assertThat(repoCfg.getBasePath(new Project.NameKey("someOtherProject"))).isNull();
-    assertThat(repoCfg.getBasePath(new Project.NameKey("someProject")).toString())
-        .isEqualTo(basePath);
+    assertThat(repoCfg.getBasePath(Project.nameKey("someOtherProject"))).isNull();
+    assertThat(repoCfg.getBasePath(Project.nameKey("someProject")).toString()).isEqualTo(basePath);
   }
 
   @Test
@@ -182,14 +180,12 @@
     configureBasePath("project/*", basePath3);
     configureBasePath("*", basePath4);
 
-    assertThat(repoCfg.getBasePath(new Project.NameKey("project1")).toString())
-        .isEqualTo(basePath1);
-    assertThat(repoCfg.getBasePath(new Project.NameKey("project/project/someProject")).toString())
+    assertThat(repoCfg.getBasePath(Project.nameKey("project1")).toString()).isEqualTo(basePath1);
+    assertThat(repoCfg.getBasePath(Project.nameKey("project/project/someProject")).toString())
         .isEqualTo(basePath2);
-    assertThat(repoCfg.getBasePath(new Project.NameKey("project/someProject")).toString())
+    assertThat(repoCfg.getBasePath(Project.nameKey("project/someProject")).toString())
         .isEqualTo(basePath3);
-    assertThat(repoCfg.getBasePath(new Project.NameKey("someProject")).toString())
-        .isEqualTo(basePath4);
+    assertThat(repoCfg.getBasePath(Project.nameKey("someProject")).toString()).isEqualTo(basePath4);
   }
 
   @Test
diff --git a/javatests/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java b/javatests/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java
index 821a6e6b..68afd78 100644
--- a/javatests/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java
+++ b/javatests/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java
@@ -59,7 +59,7 @@
 
   @Test
   public void projectCreation() throws Exception {
-    Project.NameKey projectA = new Project.NameKey("projectA");
+    Project.NameKey projectA = Project.nameKey("projectA");
     try (Repository repo = repoManager.createRepository(projectA)) {
       assertThat(repo).isNotNull();
     }
@@ -71,110 +71,110 @@
 
   @Test(expected = RepositoryNotFoundException.class)
   public void testProjectCreationWithEmptyName() throws Exception {
-    repoManager.createRepository(new Project.NameKey(""));
+    repoManager.createRepository(Project.nameKey(""));
   }
 
   @Test(expected = RepositoryNotFoundException.class)
   public void testProjectCreationWithTrailingSlash() throws Exception {
-    repoManager.createRepository(new Project.NameKey("projectA/"));
+    repoManager.createRepository(Project.nameKey("projectA/"));
   }
 
   @Test(expected = RepositoryNotFoundException.class)
   public void testProjectCreationWithBackSlash() throws Exception {
-    repoManager.createRepository(new Project.NameKey("a\\projectA"));
+    repoManager.createRepository(Project.nameKey("a\\projectA"));
   }
 
   @Test(expected = RepositoryNotFoundException.class)
   public void testProjectCreationAbsolutePath() throws Exception {
-    repoManager.createRepository(new Project.NameKey("/projectA"));
+    repoManager.createRepository(Project.nameKey("/projectA"));
   }
 
   @Test(expected = RepositoryNotFoundException.class)
   public void testProjectCreationStartingWithDotDot() throws Exception {
-    repoManager.createRepository(new Project.NameKey("../projectA"));
+    repoManager.createRepository(Project.nameKey("../projectA"));
   }
 
   @Test(expected = RepositoryNotFoundException.class)
   public void testProjectCreationContainsDotDot() throws Exception {
-    repoManager.createRepository(new Project.NameKey("a/../projectA"));
+    repoManager.createRepository(Project.nameKey("a/../projectA"));
   }
 
   @Test(expected = RepositoryNotFoundException.class)
   public void testProjectCreationDotPathSegment() throws Exception {
-    repoManager.createRepository(new Project.NameKey("a/./projectA"));
+    repoManager.createRepository(Project.nameKey("a/./projectA"));
   }
 
   @Test(expected = RepositoryNotFoundException.class)
   public void testProjectCreationWithTwoSlashes() throws Exception {
-    repoManager.createRepository(new Project.NameKey("a//projectA"));
+    repoManager.createRepository(Project.nameKey("a//projectA"));
   }
 
   @Test(expected = RepositoryNotFoundException.class)
   public void testProjectCreationWithPathSegmentEndingByDotGit() throws Exception {
-    repoManager.createRepository(new Project.NameKey("a/b.git/projectA"));
+    repoManager.createRepository(Project.nameKey("a/b.git/projectA"));
   }
 
   @Test(expected = RepositoryNotFoundException.class)
   public void testProjectCreationWithQuestionMark() throws Exception {
-    repoManager.createRepository(new Project.NameKey("project?A"));
+    repoManager.createRepository(Project.nameKey("project?A"));
   }
 
   @Test(expected = RepositoryNotFoundException.class)
   public void testProjectCreationWithPercentageSign() throws Exception {
-    repoManager.createRepository(new Project.NameKey("project%A"));
+    repoManager.createRepository(Project.nameKey("project%A"));
   }
 
   @Test(expected = RepositoryNotFoundException.class)
   public void testProjectCreationWithWidlcard() throws Exception {
-    repoManager.createRepository(new Project.NameKey("project*A"));
+    repoManager.createRepository(Project.nameKey("project*A"));
   }
 
   @Test(expected = RepositoryNotFoundException.class)
   public void testProjectCreationWithColon() throws Exception {
-    repoManager.createRepository(new Project.NameKey("project:A"));
+    repoManager.createRepository(Project.nameKey("project:A"));
   }
 
   @Test(expected = RepositoryNotFoundException.class)
   public void testProjectCreationWithLessThatSign() throws Exception {
-    repoManager.createRepository(new Project.NameKey("project<A"));
+    repoManager.createRepository(Project.nameKey("project<A"));
   }
 
   @Test(expected = RepositoryNotFoundException.class)
   public void testProjectCreationWithGreaterThatSign() throws Exception {
-    repoManager.createRepository(new Project.NameKey("project>A"));
+    repoManager.createRepository(Project.nameKey("project>A"));
   }
 
   @Test(expected = RepositoryNotFoundException.class)
   public void testProjectCreationWithPipe() throws Exception {
-    repoManager.createRepository(new Project.NameKey("project|A"));
+    repoManager.createRepository(Project.nameKey("project|A"));
   }
 
   @Test(expected = RepositoryNotFoundException.class)
   public void testProjectCreationWithDollarSign() throws Exception {
-    repoManager.createRepository(new Project.NameKey("project$A"));
+    repoManager.createRepository(Project.nameKey("project$A"));
   }
 
   @Test(expected = RepositoryNotFoundException.class)
   public void testProjectCreationWithCarriageReturn() throws Exception {
-    repoManager.createRepository(new Project.NameKey("project\\rA"));
+    repoManager.createRepository(Project.nameKey("project\\rA"));
   }
 
   @Test(expected = IllegalStateException.class)
   public void testProjectRecreation() throws Exception {
-    repoManager.createRepository(new Project.NameKey("a"));
-    repoManager.createRepository(new Project.NameKey("a"));
+    repoManager.createRepository(Project.nameKey("a"));
+    repoManager.createRepository(Project.nameKey("a"));
   }
 
   @Test(expected = IllegalStateException.class)
   public void testProjectRecreationAfterRestart() throws Exception {
-    repoManager.createRepository(new Project.NameKey("a"));
+    repoManager.createRepository(Project.nameKey("a"));
     LocalDiskRepositoryManager newRepoManager = new LocalDiskRepositoryManager(site, cfg);
-    newRepoManager.createRepository(new Project.NameKey("a"));
+    newRepoManager.createRepository(Project.nameKey("a"));
   }
 
   @Test
   public void openRepositoryCreatedDirectlyOnDisk() throws Exception {
-    Project.NameKey projectA = new Project.NameKey("projectA");
+    Project.NameKey projectA = Project.nameKey("projectA");
     createRepository(repoManager.getBasePath(projectA), projectA.get());
     try (Repository repo = repoManager.openRepository(projectA)) {
       assertThat(repo).isNotNull();
@@ -185,27 +185,27 @@
   @Test(expected = RepositoryCaseMismatchException.class)
   public void testNameCaseMismatch() throws Exception {
     assume().that(HostPlatform.isWin32() || HostPlatform.isMac()).isTrue();
-    repoManager.createRepository(new Project.NameKey("a"));
-    repoManager.createRepository(new Project.NameKey("A"));
+    repoManager.createRepository(Project.nameKey("a"));
+    repoManager.createRepository(Project.nameKey("A"));
   }
 
   @Test(expected = RepositoryCaseMismatchException.class)
   public void testNameCaseMismatchWithSymlink() throws Exception {
     assume().that(HostPlatform.isWin32() || HostPlatform.isMac()).isTrue();
-    Project.NameKey name = new Project.NameKey("a");
+    Project.NameKey name = Project.nameKey("a");
     repoManager.createRepository(name);
     createSymLink(name, "b.git");
-    repoManager.createRepository(new Project.NameKey("B"));
+    repoManager.createRepository(Project.nameKey("B"));
   }
 
   @Test(expected = RepositoryCaseMismatchException.class)
   public void testNameCaseMismatchAfterRestart() throws Exception {
     assume().that(HostPlatform.isWin32() || HostPlatform.isMac()).isTrue();
-    Project.NameKey name = new Project.NameKey("a");
+    Project.NameKey name = Project.nameKey("a");
     repoManager.createRepository(name);
 
     LocalDiskRepositoryManager newRepoManager = new LocalDiskRepositoryManager(site, cfg);
-    newRepoManager.createRepository(new Project.NameKey("A"));
+    newRepoManager.createRepository(Project.nameKey("A"));
   }
 
   private void createSymLink(Project.NameKey project, String link) throws IOException {
@@ -217,18 +217,18 @@
 
   @Test(expected = RepositoryNotFoundException.class)
   public void testOpenRepositoryInvalidName() throws Exception {
-    repoManager.openRepository(new Project.NameKey("project%?|<>A"));
+    repoManager.openRepository(Project.nameKey("project%?|<>A"));
   }
 
   @Test
   public void list() throws Exception {
-    Project.NameKey projectA = new Project.NameKey("projectA");
+    Project.NameKey projectA = Project.nameKey("projectA");
     createRepository(repoManager.getBasePath(projectA), projectA.get());
 
-    Project.NameKey projectB = new Project.NameKey("path/projectB");
+    Project.NameKey projectB = Project.nameKey("path/projectB");
     createRepository(repoManager.getBasePath(projectB), projectB.get());
 
-    Project.NameKey projectC = new Project.NameKey("anotherPath/path/projectC");
+    Project.NameKey projectC = Project.nameKey("anotherPath/path/projectC");
     createRepository(repoManager.getBasePath(projectC), projectC.get());
     // create an invalid git repo named only .git
     repoManager.getBasePath(null).resolve(".git").toFile().mkdir();
diff --git a/javatests/com/google/gerrit/server/git/MultiBaseLocalDiskRepositoryManagerTest.java b/javatests/com/google/gerrit/server/git/MultiBaseLocalDiskRepositoryManagerTest.java
index fc79a6d..550e379 100644
--- a/javatests/com/google/gerrit/server/git/MultiBaseLocalDiskRepositoryManagerTest.java
+++ b/javatests/com/google/gerrit/server/git/MultiBaseLocalDiskRepositoryManagerTest.java
@@ -64,7 +64,7 @@
   @Test
   public void defaultRepositoryLocation()
       throws RepositoryCaseMismatchException, RepositoryNotFoundException, IOException {
-    Project.NameKey someProjectKey = new Project.NameKey("someProject");
+    Project.NameKey someProjectKey = Project.nameKey("someProject");
     Repository repo = repoManager.createRepository(someProjectKey);
     assertThat(repo.getDirectory()).isNotNull();
     assertThat(repo.getDirectory().exists()).isTrue();
@@ -89,7 +89,7 @@
   @Test
   public void alternateRepositoryLocation() throws IOException {
     Path alternateBasePath = temporaryFolder.newFolder().toPath();
-    Project.NameKey someProjectKey = new Project.NameKey("someProject");
+    Project.NameKey someProjectKey = Project.nameKey("someProject");
     reset(configMock);
     expect(configMock.getBasePath(someProjectKey)).andReturn(alternateBasePath).anyTimes();
     expect(configMock.getAllBasePaths()).andReturn(ImmutableList.of(alternateBasePath)).anyTimes();
@@ -116,10 +116,10 @@
 
   @Test
   public void listReturnRepoFromProperLocation() throws IOException {
-    Project.NameKey basePathProject = new Project.NameKey("basePathProject");
-    Project.NameKey altPathProject = new Project.NameKey("altPathProject");
-    Project.NameKey misplacedProject1 = new Project.NameKey("misplacedProject1");
-    Project.NameKey misplacedProject2 = new Project.NameKey("misplacedProject2");
+    Project.NameKey basePathProject = Project.nameKey("basePathProject");
+    Project.NameKey altPathProject = Project.nameKey("altPathProject");
+    Project.NameKey misplacedProject1 = Project.nameKey("misplacedProject1");
+    Project.NameKey misplacedProject2 = Project.nameKey("misplacedProject2");
 
     Path alternateBasePath = temporaryFolder.newFolder().toPath();
 
diff --git a/javatests/com/google/gerrit/server/git/PureRevertCacheKeyTest.java b/javatests/com/google/gerrit/server/git/PureRevertCacheKeyTest.java
index 8c17075..29d89bc 100644
--- a/javatests/com/google/gerrit/server/git/PureRevertCacheKeyTest.java
+++ b/javatests/com/google/gerrit/server/git/PureRevertCacheKeyTest.java
@@ -36,8 +36,7 @@
             0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
             0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb);
 
-    Cache.PureRevertKeyProto key =
-        PureRevertCache.key(new Project.NameKey("test"), revert, original);
+    Cache.PureRevertKeyProto key = PureRevertCache.key(Project.nameKey("test"), revert, original);
     assertThat(key)
         .isEqualTo(
             Cache.PureRevertKeyProto.newBuilder()
diff --git a/javatests/com/google/gerrit/server/git/TagSetHolderTest.java b/javatests/com/google/gerrit/server/git/TagSetHolderTest.java
index 87ddc75..d3ddef0 100644
--- a/javatests/com/google/gerrit/server/git/TagSetHolderTest.java
+++ b/javatests/com/google/gerrit/server/git/TagSetHolderTest.java
@@ -27,7 +27,7 @@
 public class TagSetHolderTest extends GerritBaseTests {
   @Test
   public void serializerWithTagSet() throws Exception {
-    TagSetHolder holder = new TagSetHolder(new Project.NameKey("project"));
+    TagSetHolder holder = new TagSetHolder(Project.nameKey("project"));
     holder.setTagSet(new TagSet(holder.getProjectName()));
 
     byte[] serialized = TagSetHolder.Serializer.INSTANCE.serialize(holder);
@@ -46,7 +46,7 @@
 
   @Test
   public void serializerWithoutTagSet() throws Exception {
-    TagSetHolder holder = new TagSetHolder(new Project.NameKey("project"));
+    TagSetHolder holder = new TagSetHolder(Project.nameKey("project"));
 
     byte[] serialized = TagSetHolder.Serializer.INSTANCE.serialize(holder);
     assertThat(TagSetHolderProto.parseFrom(serialized))
diff --git a/javatests/com/google/gerrit/server/git/TagSetTest.java b/javatests/com/google/gerrit/server/git/TagSetTest.java
index 3ac72be..da5cabd 100644
--- a/javatests/com/google/gerrit/server/git/TagSetTest.java
+++ b/javatests/com/google/gerrit/server/git/TagSetTest.java
@@ -60,7 +60,7 @@
     tags.add(
         new Tag(
             ObjectId.fromString("dddddddddddddddddddddddddddddddddddddddd"), newBitSet(2, 4, 6)));
-    TagSet tagSet = new TagSet(new Project.NameKey("project"), refs, tags);
+    TagSet tagSet = new TagSet(Project.nameKey("project"), refs, tags);
 
     TagSetProto proto = tagSet.toProto();
     assertThat(proto)
diff --git a/javatests/com/google/gerrit/server/git/meta/VersionedMetaDataTest.java b/javatests/com/google/gerrit/server/git/meta/VersionedMetaDataTest.java
index dedccc2..3d41051 100644
--- a/javatests/com/google/gerrit/server/git/meta/VersionedMetaDataTest.java
+++ b/javatests/com/google/gerrit/server/git/meta/VersionedMetaDataTest.java
@@ -65,7 +65,7 @@
   @Before
   public void setUp() {
     TestTimeUtil.resetWithClockStep(1, TimeUnit.SECONDS);
-    project = new Project.NameKey("repo");
+    project = Project.nameKey("repo");
     repo = new InMemoryRepository(new DfsRepositoryDescription(project.get()));
   }
 
diff --git a/javatests/com/google/gerrit/server/group/db/GroupConfigTest.java b/javatests/com/google/gerrit/server/group/db/GroupConfigTest.java
index 4ce0d29..7be7f1c 100644
--- a/javatests/com/google/gerrit/server/group/db/GroupConfigTest.java
+++ b/javatests/com/google/gerrit/server/group/db/GroupConfigTest.java
@@ -68,7 +68,7 @@
 
   @Before
   public void setUp() throws Exception {
-    projectName = new Project.NameKey("Test Repository");
+    projectName = Project.nameKey("Test Repository");
     repository = new InMemoryRepository(new DfsRepositoryDescription("Test Repository"));
     testRepository = new TestRepository<>(repository);
   }
@@ -1556,7 +1556,7 @@
 
     MetaDataUpdate metaDataUpdate =
         new MetaDataUpdate(
-            GitReferenceUpdated.DISABLED, new Project.NameKey("Test Repository"), repository);
+            GitReferenceUpdated.DISABLED, Project.nameKey("Test Repository"), repository);
     metaDataUpdate.getCommitBuilder().setCommitter(serverIdent);
     metaDataUpdate.getCommitBuilder().setAuthor(serverIdent);
     return metaDataUpdate;
diff --git a/javatests/com/google/gerrit/server/group/db/GroupNameNotesTest.java b/javatests/com/google/gerrit/server/group/db/GroupNameNotesTest.java
index 0ca92fae..085e2ad 100644
--- a/javatests/com/google/gerrit/server/group/db/GroupNameNotesTest.java
+++ b/javatests/com/google/gerrit/server/group/db/GroupNameNotesTest.java
@@ -528,8 +528,7 @@
     PersonIdent serverIdent = newPersonIdent();
 
     MetaDataUpdate metaDataUpdate =
-        new MetaDataUpdate(
-            GitReferenceUpdated.DISABLED, new Project.NameKey("Test Repository"), repo);
+        new MetaDataUpdate(GitReferenceUpdated.DISABLED, Project.nameKey("Test Repository"), repo);
     metaDataUpdate.getCommitBuilder().setCommitter(serverIdent);
     metaDataUpdate.getCommitBuilder().setAuthor(serverIdent);
     return metaDataUpdate;
diff --git a/javatests/com/google/gerrit/server/index/change/StalenessCheckerTest.java b/javatests/com/google/gerrit/server/index/change/StalenessCheckerTest.java
index a38eabe..2df03d5 100644
--- a/javatests/com/google/gerrit/server/index/change/StalenessCheckerTest.java
+++ b/javatests/com/google/gerrit/server/index/change/StalenessCheckerTest.java
@@ -41,8 +41,8 @@
   private static final String SHA1 = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
   private static final String SHA2 = "badc0feebadc0feebadc0feebadc0feebadc0fee";
 
-  private static final Project.NameKey P1 = new Project.NameKey("project1");
-  private static final Project.NameKey P2 = new Project.NameKey("project2");
+  private static final Project.NameKey P1 = Project.nameKey("project1");
+  private static final Project.NameKey P2 = Project.nameKey("project2");
 
   private static final Change.Id C = new Change.Id(1234);
 
diff --git a/javatests/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java b/javatests/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java
index 4e9c2ca..de00ee9 100644
--- a/javatests/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java
+++ b/javatests/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java
@@ -110,7 +110,7 @@
     setTimeForTesting();
 
     serverIdent = new PersonIdent("Gerrit Server", "noreply@gerrit.com", TimeUtil.nowTs(), TZ);
-    project = new Project.NameKey("test-project");
+    project = Project.nameKey("test-project");
     repoManager = new InMemoryRepositoryManager();
     repo = repoManager.createRepository(project);
     tr = new TestRepository<>(repo);
diff --git a/javatests/com/google/gerrit/server/notedb/ChangeNotesCacheTest.java b/javatests/com/google/gerrit/server/notedb/ChangeNotesCacheTest.java
index b4d9738..e880968 100644
--- a/javatests/com/google/gerrit/server/notedb/ChangeNotesCacheTest.java
+++ b/javatests/com/google/gerrit/server/notedb/ChangeNotesCacheTest.java
@@ -31,7 +31,7 @@
   public void keySerializer() throws Exception {
     ChangeNotesCache.Key key =
         ChangeNotesCache.Key.create(
-            new Project.NameKey("project"),
+            Project.nameKey("project"),
             new Change.Id(1234),
             ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"));
     byte[] serialized = ChangeNotesCache.Key.Serializer.INSTANCE.serialize(key);
diff --git a/javatests/com/google/gerrit/server/notedb/IntBlobTest.java b/javatests/com/google/gerrit/server/notedb/IntBlobTest.java
index 1cbe61d..7ddc86f 100644
--- a/javatests/com/google/gerrit/server/notedb/IntBlobTest.java
+++ b/javatests/com/google/gerrit/server/notedb/IntBlobTest.java
@@ -44,7 +44,7 @@
 
   @Before
   public void setUp() throws Exception {
-    projectName = new Project.NameKey("repo");
+    projectName = Project.nameKey("repo");
     repo = new InMemoryRepository(new DfsRepositoryDescription(projectName.get()));
     tr = new TestRepository<>(repo);
     rw = tr.getRevWalk();
diff --git a/javatests/com/google/gerrit/server/notedb/RepoSequenceTest.java b/javatests/com/google/gerrit/server/notedb/RepoSequenceTest.java
index 263873d..28c1cd2 100644
--- a/javatests/com/google/gerrit/server/notedb/RepoSequenceTest.java
+++ b/javatests/com/google/gerrit/server/notedb/RepoSequenceTest.java
@@ -54,7 +54,7 @@
   @Before
   public void setUp() throws Exception {
     repoManager = new InMemoryRepositoryManager();
-    project = new Project.NameKey("project");
+    project = Project.nameKey("project");
     repoManager.createRepository(project);
   }
 
diff --git a/javatests/com/google/gerrit/server/permissions/RefControlTest.java b/javatests/com/google/gerrit/server/permissions/RefControlTest.java
index 05b9527..c366e7d 100644
--- a/javatests/com/google/gerrit/server/permissions/RefControlTest.java
+++ b/javatests/com/google/gerrit/server/permissions/RefControlTest.java
@@ -182,9 +182,9 @@
   private final AllUsersName allUsersName = new AllUsersName(AllUsersNameProvider.DEFAULT);
   private final AccountGroup.UUID fixers = AccountGroup.uuid("test.fixers");
   private final Map<Project.NameKey, ProjectState> all = new HashMap<>();
-  private Project.NameKey localKey = new Project.NameKey("local");
+  private Project.NameKey localKey = Project.nameKey("local");
   private ProjectConfig local;
-  private Project.NameKey parentKey = new Project.NameKey("parent");
+  private Project.NameKey parentKey = Project.nameKey("parent");
   private ProjectConfig parent;
   private InMemoryRepositoryManager repoManager;
   private ProjectCache projectCache;
@@ -269,7 +269,7 @@
     try {
       Repository repo = repoManager.createRepository(allProjectsName);
       ProjectConfig allProjects =
-          projectConfigFactory.create(new Project.NameKey(allProjectsName.get()));
+          projectConfigFactory.create(Project.nameKey(allProjectsName.get()));
       allProjects.load(repo);
       LabelType cr = Util.codeReview();
       allProjects.getLabelSections().put(cr.getName(), cr);
diff --git a/javatests/com/google/gerrit/server/project/CommitsCollectionTest.java b/javatests/com/google/gerrit/server/project/CommitsCollectionTest.java
index cf6d50f..e002d12 100644
--- a/javatests/com/google/gerrit/server/project/CommitsCollectionTest.java
+++ b/javatests/com/google/gerrit/server/project/CommitsCollectionTest.java
@@ -70,7 +70,7 @@
     Account.Id user = accountManager.authenticate(AuthRequest.forUser("user")).getAccountId();
     testEnvironment.setApiUser(user);
 
-    Project.NameKey name = new Project.NameKey("project");
+    Project.NameKey name = Project.nameKey("project");
     InMemoryRepository inMemoryRepo = repoManager.createRepository(name);
     project = projectConfigFactory.create(name);
     project.load(inMemoryRepo);
diff --git a/javatests/com/google/gerrit/server/project/GroupListTest.java b/javatests/com/google/gerrit/server/project/GroupListTest.java
index b936121..b83a10b 100644
--- a/javatests/com/google/gerrit/server/project/GroupListTest.java
+++ b/javatests/com/google/gerrit/server/project/GroupListTest.java
@@ -38,7 +38,7 @@
 import org.junit.Test;
 
 public class GroupListTest extends GerritBaseTests {
-  private static final Project.NameKey PROJECT = new Project.NameKey("project");
+  private static final Project.NameKey PROJECT = Project.nameKey("project");
   private static final String TEXT =
       "# UUID                                  \tGroup Name\n"
           + "#\n"
diff --git a/javatests/com/google/gerrit/server/project/ProjectConfigTest.java b/javatests/com/google/gerrit/server/project/ProjectConfigTest.java
index 17073cd..e227b597 100644
--- a/javatests/com/google/gerrit/server/project/ProjectConfigTest.java
+++ b/javatests/com/google/gerrit/server/project/ProjectConfigTest.java
@@ -422,7 +422,7 @@
 
   @Test
   public void readUnexistingPluginConfig() throws Exception {
-    ProjectConfig cfg = factory.create(new Project.NameKey("test"));
+    ProjectConfig cfg = factory.create(Project.nameKey("test"));
     cfg.load(db);
     PluginConfig pluginCfg = cfg.getPluginConfig("somePlugin");
     assertThat(pluginCfg.getNames()).isEmpty();
@@ -625,7 +625,7 @@
 
   @Test
   public void readOtherProjectIgnoresAllProjectsBaseConfig() throws Exception {
-    ProjectConfig cfg = factory.create(new Project.NameKey("test"));
+    ProjectConfig cfg = factory.create(Project.nameKey("test"));
     cfg.load(db);
     assertThat(cfg.getProject().getBooleanConfig(REQUIRE_CHANGE_ID))
         .isEqualTo(InheritableBoolean.INHERIT);
@@ -648,7 +648,7 @@
   }
 
   private ProjectConfig read(RevCommit rev) throws IOException, ConfigInvalidException {
-    ProjectConfig cfg = factory.create(new Project.NameKey("test"));
+    ProjectConfig cfg = factory.create(Project.nameKey("test"));
     cfg.load(db, rev);
     return cfg;
   }
diff --git a/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java b/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
index dad26e1..117d78b 100644
--- a/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
+++ b/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
@@ -695,7 +695,7 @@
     in.name = name;
     in.createEmptyCommit = true;
     gApi.projects().create(in);
-    return new Project.NameKey(name);
+    return Project.nameKey(name);
   }
 
   protected void blockRead(Project.NameKey project, GroupInfo group) throws RestApiException {
diff --git a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
index 7c7c75a..e7a97e8 100644
--- a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+++ b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
@@ -544,7 +544,7 @@
   public void restorePendingReviewers() throws Exception {
     assume().that(getSchemaVersion()).isAtLeast(44);
 
-    Project.NameKey project = new Project.NameKey("repo");
+    Project.NameKey project = Project.nameKey("repo");
     TestRepository<Repo> repo = createProject(project.get());
     ConfigInput conf = new ConfigInput();
     conf.enableReviewerByEmail = InheritableBoolean.TRUE;
@@ -1046,7 +1046,7 @@
   public void byLabelMulti() throws Exception {
     TestRepository<Repo> repo = createProject("repo");
     Project.NameKey project =
-        new Project.NameKey(repo.getRepository().getDescription().getRepositoryName());
+        Project.nameKey(repo.getRepository().getDescription().getRepositoryName());
     ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
 
     LabelType verified =
@@ -1935,7 +1935,7 @@
 
   @Test
   public void byDraftByExcludesZombieDrafts() throws Exception {
-    Project.NameKey project = new Project.NameKey("repo");
+    Project.NameKey project = Project.nameKey("repo");
     TestRepository<Repo> repo = createProject(project.get());
     Change change = insert(repo, newChange(repo));
     Change.Id id = change.getId();
@@ -2254,7 +2254,7 @@
 
   @Test
   public void reviewerAndCcByEmail() throws Exception {
-    Project.NameKey project = new Project.NameKey("repo");
+    Project.NameKey project = Project.nameKey("repo");
     TestRepository<Repo> repo = createProject(project.get());
     ConfigInput conf = new ConfigInput();
     conf.enableReviewerByEmail = InheritableBoolean.TRUE;
@@ -2300,7 +2300,7 @@
 
   @Test
   public void reviewerAndCcByEmailWithQueryForDifferentUser() throws Exception {
-    Project.NameKey project = new Project.NameKey("repo");
+    Project.NameKey project = Project.nameKey("repo");
     TestRepository<Repo> repo = createProject(project.get());
     ConfigInput conf = new ConfigInput();
     conf.enableReviewerByEmail = InheritableBoolean.TRUE;
@@ -2474,7 +2474,7 @@
   @Test
   public void reindexIfStale() throws Exception {
     Account.Id user = createAccount("user");
-    Project.NameKey project = new Project.NameKey("repo");
+    Project.NameKey project = Project.nameKey("repo");
     TestRepository<Repo> repo = createProject(project.get());
     Change change = insert(repo, newChange(repo));
     String changeId = change.getKey().get();
@@ -3235,7 +3235,7 @@
       Timestamp createdOn)
       throws Exception {
     Project.NameKey project =
-        new Project.NameKey(repo.getRepository().getDescription().getRepositoryName());
+        Project.nameKey(repo.getRepository().getDescription().getRepositoryName());
     Account.Id ownerId = owner != null ? owner : userId;
     IdentifiedUser user = userFactory.create(ownerId);
     try (BatchUpdate bu = updateFactory.create(project, user, createdOn)) {
@@ -3294,7 +3294,7 @@
 
   protected TestRepository<Repo> createProject(String name) throws Exception {
     gApi.projects().create(name).get();
-    return new TestRepository<>(repoManager.openRepository(new Project.NameKey(name)));
+    return new TestRepository<>(repoManager.openRepository(Project.nameKey(name)));
   }
 
   protected TestRepository<Repo> createProject(String name, String parent) throws Exception {
@@ -3302,7 +3302,7 @@
     input.name = name;
     input.parent = parent;
     gApi.projects().create(input).get();
-    return new TestRepository<>(repoManager.openRepository(new Project.NameKey(name)));
+    return new TestRepository<>(repoManager.openRepository(Project.nameKey(name)));
   }
 
   protected QueryRequest newQuery(Object query) {
@@ -3371,7 +3371,7 @@
           .append(c.changeId)
           .append("), ")
           .append("dest=")
-          .append(Branch.nameKey(new Project.NameKey(c.project), c.branch))
+          .append(Branch.nameKey(Project.nameKey(c.project), c.branch))
           .append(", ")
           .append("status=")
           .append(c.status)
diff --git a/javatests/com/google/gerrit/server/query/change/ChangeDataTest.java b/javatests/com/google/gerrit/server/query/change/ChangeDataTest.java
index 666b93f..46ebf9b 100644
--- a/javatests/com/google/gerrit/server/query/change/ChangeDataTest.java
+++ b/javatests/com/google/gerrit/server/query/change/ChangeDataTest.java
@@ -28,7 +28,7 @@
 public class ChangeDataTest extends GerritBaseTests {
   @Test
   public void setPatchSetsClearsCurrentPatchSet() throws Exception {
-    Project.NameKey project = new Project.NameKey("project");
+    Project.NameKey project = Project.nameKey("project");
     ChangeData cd = ChangeData.createForTest(project, new Change.Id(1), 1);
     cd.setChange(TestChanges.newChange(project, Account.id(1000)));
     PatchSet curr1 = cd.currentPatchSet();
diff --git a/javatests/com/google/gerrit/server/query/change/RegexPathPredicateTest.java b/javatests/com/google/gerrit/server/query/change/RegexPathPredicateTest.java
index 135e9c26..db91808 100644
--- a/javatests/com/google/gerrit/server/query/change/RegexPathPredicateTest.java
+++ b/javatests/com/google/gerrit/server/query/change/RegexPathPredicateTest.java
@@ -83,7 +83,7 @@
 
   private static ChangeData change(String... files) {
     Arrays.sort(files);
-    ChangeData cd = ChangeData.createForTest(new Project.NameKey("project"), new Change.Id(1), 1);
+    ChangeData cd = ChangeData.createForTest(Project.nameKey("project"), new Change.Id(1), 1);
     cd.setCurrentFilePaths(Arrays.asList(files));
     return cd;
   }
diff --git a/javatests/com/google/gerrit/server/schema/ProjectConfigSchemaUpdateTest.java b/javatests/com/google/gerrit/server/schema/ProjectConfigSchemaUpdateTest.java
index e4089c5..bc5109f 100644
--- a/javatests/com/google/gerrit/server/schema/ProjectConfigSchemaUpdateTest.java
+++ b/javatests/com/google/gerrit/server/schema/ProjectConfigSchemaUpdateTest.java
@@ -103,7 +103,7 @@
       return factory
           .read(
               new MetaDataUpdate(
-                  GitReferenceUpdated.DISABLED, new Project.NameKey(ALL_PROJECTS), repo, null))
+                  GitReferenceUpdated.DISABLED, Project.nameKey(ALL_PROJECTS), repo, null))
           .getConfig();
     }
   }
diff --git a/javatests/com/google/gerrit/server/update/BatchUpdateTest.java b/javatests/com/google/gerrit/server/update/BatchUpdateTest.java
index ffaf255..f3d2ac7 100644
--- a/javatests/com/google/gerrit/server/update/BatchUpdateTest.java
+++ b/javatests/com/google/gerrit/server/update/BatchUpdateTest.java
@@ -75,7 +75,7 @@
 
   @Before
   public void setUp() throws Exception {
-    project = new Project.NameKey("test");
+    project = Project.nameKey("test");
 
     Repository inMemoryRepo = repoManager.createRepository(project);
     repo = new TestRepository<>(inMemoryRepo);
diff --git a/javatests/com/google/gerrit/server/update/RepoViewTest.java b/javatests/com/google/gerrit/server/update/RepoViewTest.java
index b41c66c..4cd2185 100644
--- a/javatests/com/google/gerrit/server/update/RepoViewTest.java
+++ b/javatests/com/google/gerrit/server/update/RepoViewTest.java
@@ -42,7 +42,7 @@
   @Before
   public void setUp() throws Exception {
     InMemoryRepositoryManager repoManager = new InMemoryRepositoryManager();
-    Project.NameKey project = new Project.NameKey("project");
+    Project.NameKey project = Project.nameKey("project");
     repo = repoManager.createRepository(project);
     tr = new TestRepository<>(repo);
     tr.branch(MASTER).commit().create();
diff --git a/javatests/com/google/gerrit/server/util/git/SubmoduleSectionParserTest.java b/javatests/com/google/gerrit/server/util/git/SubmoduleSectionParserTest.java
index 1b6f8c6..bd66f26 100644
--- a/javatests/com/google/gerrit/server/util/git/SubmoduleSectionParserTest.java
+++ b/javatests/com/google/gerrit/server/util/git/SubmoduleSectionParserTest.java
@@ -30,7 +30,7 @@
 
   @Test
   public void followMasterBranch() throws Exception {
-    Project.NameKey p = new Project.NameKey("proj");
+    Project.NameKey p = Project.nameKey("proj");
     Config cfg = new Config();
     cfg.fromText(
         ""
@@ -40,7 +40,7 @@
             + p.get()
             + "\n"
             + "branch = master\n");
-    Branch.NameKey targetBranch = Branch.nameKey(new Project.NameKey("project"), "master");
+    Branch.NameKey targetBranch = Branch.nameKey(Project.nameKey("project"), "master");
 
     Set<SubmoduleSubscription> res =
         new SubmoduleSectionParser(cfg, THIS_SERVER, targetBranch).parseAllSections();
@@ -54,7 +54,7 @@
 
   @Test
   public void followMatchingBranch() throws Exception {
-    Project.NameKey p = new Project.NameKey("a");
+    Project.NameKey p = Project.nameKey("a");
     Config cfg = new Config();
     cfg.fromText(
         ""
@@ -65,7 +65,7 @@
             + "\n"
             + "branch = .\n");
 
-    Branch.NameKey targetBranch1 = Branch.nameKey(new Project.NameKey("project"), "master");
+    Branch.NameKey targetBranch1 = Branch.nameKey(Project.nameKey("project"), "master");
 
     Set<SubmoduleSubscription> res1 =
         new SubmoduleSectionParser(cfg, THIS_SERVER, targetBranch1).parseAllSections();
@@ -75,7 +75,7 @@
 
     assertThat(res1).containsExactlyElementsIn(expected1);
 
-    Branch.NameKey targetBranch2 = Branch.nameKey(new Project.NameKey("project"), "somebranch");
+    Branch.NameKey targetBranch2 = Branch.nameKey(Project.nameKey("project"), "somebranch");
 
     Set<SubmoduleSubscription> res2 =
         new SubmoduleSectionParser(cfg, THIS_SERVER, targetBranch2).parseAllSections();
@@ -89,7 +89,7 @@
 
   @Test
   public void followAnotherBranch() throws Exception {
-    Project.NameKey p = new Project.NameKey("a");
+    Project.NameKey p = Project.nameKey("a");
     Config cfg = new Config();
     cfg.fromText(
         ""
@@ -100,7 +100,7 @@
             + "\n"
             + "branch = anotherbranch\n");
 
-    Branch.NameKey targetBranch = Branch.nameKey(new Project.NameKey("project"), "master");
+    Branch.NameKey targetBranch = Branch.nameKey(Project.nameKey("project"), "master");
 
     Set<SubmoduleSubscription> res =
         new SubmoduleSectionParser(cfg, THIS_SERVER, targetBranch).parseAllSections();
@@ -114,7 +114,7 @@
 
   @Test
   public void withAnotherURI() throws Exception {
-    Project.NameKey p = new Project.NameKey("a");
+    Project.NameKey p = Project.nameKey("a");
     Config cfg = new Config();
     cfg.fromText(
         ""
@@ -125,7 +125,7 @@
             + "\n"
             + "branch = master\n");
 
-    Branch.NameKey targetBranch = Branch.nameKey(new Project.NameKey("project"), "master");
+    Branch.NameKey targetBranch = Branch.nameKey(Project.nameKey("project"), "master");
 
     Set<SubmoduleSubscription> res =
         new SubmoduleSectionParser(cfg, THIS_SERVER, targetBranch).parseAllSections();
@@ -138,7 +138,7 @@
 
   @Test
   public void withSlashesInProjectName() throws Exception {
-    Project.NameKey p = new Project.NameKey("project/with/slashes/a");
+    Project.NameKey p = Project.nameKey("project/with/slashes/a");
     Config cfg = new Config();
     cfg.fromText(
         ""
@@ -149,7 +149,7 @@
             + "\n"
             + "branch = master\n");
 
-    Branch.NameKey targetBranch = Branch.nameKey(new Project.NameKey("project"), "master");
+    Branch.NameKey targetBranch = Branch.nameKey(Project.nameKey("project"), "master");
 
     Set<SubmoduleSubscription> res =
         new SubmoduleSectionParser(cfg, THIS_SERVER, targetBranch).parseAllSections();
@@ -162,7 +162,7 @@
 
   @Test
   public void withSlashesInPath() throws Exception {
-    Project.NameKey p = new Project.NameKey("a");
+    Project.NameKey p = Project.nameKey("a");
     Config cfg = new Config();
     cfg.fromText(
         ""
@@ -173,7 +173,7 @@
             + "\n"
             + "branch = master\n");
 
-    Branch.NameKey targetBranch = Branch.nameKey(new Project.NameKey("project"), "master");
+    Branch.NameKey targetBranch = Branch.nameKey(Project.nameKey("project"), "master");
 
     Set<SubmoduleSubscription> res =
         new SubmoduleSectionParser(cfg, THIS_SERVER, targetBranch).parseAllSections();
@@ -187,8 +187,8 @@
 
   @Test
   public void withMoreSections() throws Exception {
-    Project.NameKey p1 = new Project.NameKey("a");
-    Project.NameKey p2 = new Project.NameKey("b");
+    Project.NameKey p1 = Project.nameKey("a");
+    Project.NameKey p2 = Project.nameKey("b");
     Config cfg = new Config();
     cfg.fromText(
         ""
@@ -205,7 +205,7 @@
             + "\n"
             + "		branch = master\n");
 
-    Branch.NameKey targetBranch = Branch.nameKey(new Project.NameKey("project"), "master");
+    Branch.NameKey targetBranch = Branch.nameKey(Project.nameKey("project"), "master");
 
     Set<SubmoduleSubscription> res =
         new SubmoduleSectionParser(cfg, THIS_SERVER, targetBranch).parseAllSections();
@@ -220,8 +220,8 @@
 
   @Test
   public void withSubProjectFound() throws Exception {
-    Project.NameKey p1 = new Project.NameKey("a/b");
-    Project.NameKey p2 = new Project.NameKey("b");
+    Project.NameKey p1 = Project.nameKey("a/b");
+    Project.NameKey p2 = Project.nameKey("b");
     Config cfg = new Config();
     cfg.fromText(
         "\n"
@@ -238,7 +238,7 @@
             + "\n"
             + "branch = .\n");
 
-    Branch.NameKey targetBranch = Branch.nameKey(new Project.NameKey("project"), "master");
+    Branch.NameKey targetBranch = Branch.nameKey(Project.nameKey("project"), "master");
 
     Set<SubmoduleSubscription> res =
         new SubmoduleSectionParser(cfg, THIS_SERVER, targetBranch).parseAllSections();
@@ -253,10 +253,10 @@
 
   @Test
   public void withAnInvalidSection() throws Exception {
-    Project.NameKey p1 = new Project.NameKey("a");
-    Project.NameKey p2 = new Project.NameKey("b");
-    Project.NameKey p3 = new Project.NameKey("d");
-    Project.NameKey p4 = new Project.NameKey("e");
+    Project.NameKey p1 = Project.nameKey("a");
+    Project.NameKey p2 = Project.nameKey("b");
+    Project.NameKey p3 = Project.nameKey("d");
+    Project.NameKey p4 = Project.nameKey("e");
     Config cfg = new Config();
     cfg.fromText(
         "\n"
@@ -289,7 +289,7 @@
             + "\n"
             + "    branch = refs/heads/master\n");
 
-    Branch.NameKey targetBranch = Branch.nameKey(new Project.NameKey("project"), "master");
+    Branch.NameKey targetBranch = Branch.nameKey(Project.nameKey("project"), "master");
 
     Set<SubmoduleSubscription> res =
         new SubmoduleSectionParser(cfg, THIS_SERVER, targetBranch).parseAllSections();
@@ -313,7 +313,7 @@
             // Project "a" doesn't exist
             + "branch = .\\n");
 
-    Branch.NameKey targetBranch = Branch.nameKey(new Project.NameKey("project"), "master");
+    Branch.NameKey targetBranch = Branch.nameKey(Project.nameKey("project"), "master");
 
     Set<SubmoduleSubscription> res =
         new SubmoduleSectionParser(cfg, THIS_SERVER, targetBranch).parseAllSections();
@@ -323,7 +323,7 @@
 
   @Test
   public void withSectionToOtherServer() throws Exception {
-    Project.NameKey p1 = new Project.NameKey("a");
+    Project.NameKey p1 = Project.nameKey("a");
     Config cfg = new Config();
     cfg.fromText(
         ""
@@ -334,7 +334,7 @@
             + "\n"
             + "branch = .");
 
-    Branch.NameKey targetBranch = Branch.nameKey(new Project.NameKey("project"), "master");
+    Branch.NameKey targetBranch = Branch.nameKey(Project.nameKey("project"), "master");
 
     Set<SubmoduleSubscription> res =
         new SubmoduleSectionParser(cfg, THIS_SERVER, targetBranch).parseAllSections();
@@ -344,7 +344,7 @@
 
   @Test
   public void withRelativeURI() throws Exception {
-    Project.NameKey p1 = new Project.NameKey("a");
+    Project.NameKey p1 = Project.nameKey("a");
     Config cfg = new Config();
     cfg.fromText(
         ""
@@ -355,7 +355,7 @@
             + "\n"
             + "branch = master\n");
 
-    Branch.NameKey targetBranch = Branch.nameKey(new Project.NameKey("project"), "master");
+    Branch.NameKey targetBranch = Branch.nameKey(Project.nameKey("project"), "master");
 
     Set<SubmoduleSubscription> res =
         new SubmoduleSectionParser(cfg, THIS_SERVER, targetBranch).parseAllSections();
@@ -368,7 +368,7 @@
 
   @Test
   public void withDeepRelativeURI() throws Exception {
-    Project.NameKey p1 = new Project.NameKey("a");
+    Project.NameKey p1 = Project.nameKey("a");
     Config cfg = new Config();
     cfg.fromText(
         ""
@@ -379,7 +379,7 @@
             + "\n"
             + "branch = master\n");
 
-    Branch.NameKey targetBranch = Branch.nameKey(new Project.NameKey("nested/project"), "master");
+    Branch.NameKey targetBranch = Branch.nameKey(Project.nameKey("nested/project"), "master");
 
     Set<SubmoduleSubscription> res =
         new SubmoduleSectionParser(cfg, THIS_SERVER, targetBranch).parseAllSections();
@@ -392,7 +392,7 @@
 
   @Test
   public void withOverlyDeepRelativeURI() throws Exception {
-    Project.NameKey p1 = new Project.NameKey("nested/a");
+    Project.NameKey p1 = Project.nameKey("nested/a");
     Config cfg = new Config();
     cfg.fromText(
         ""
@@ -403,7 +403,7 @@
             + "\n"
             + "branch = master\n");
 
-    Branch.NameKey targetBranch = Branch.nameKey(new Project.NameKey("nested/project"), "master");
+    Branch.NameKey targetBranch = Branch.nameKey(Project.nameKey("nested/project"), "master");
 
     Set<SubmoduleSubscription> res =
         new SubmoduleSectionParser(cfg, THIS_SERVER, targetBranch).parseAllSections();
diff --git a/plugins/delete-project b/plugins/delete-project
index f6dfbc5..db2056b 160000
--- a/plugins/delete-project
+++ b/plugins/delete-project
@@ -1 +1 @@
-Subproject commit f6dfbc5371e7be3dcfe5b9b2834c10bf0d92a811
+Subproject commit db2056ba1c5b3548d78d1059bc4373a8fb867f9a
diff --git a/plugins/download-commands b/plugins/download-commands
index 697ca37..8914550 160000
--- a/plugins/download-commands
+++ b/plugins/download-commands
@@ -1 +1 @@
-Subproject commit 697ca3783add1c8fa406d60f7821ab6db7c1bfec
+Subproject commit 891455076417dd097fdfd63f4afc0d28a3e85aff
diff --git a/plugins/gitiles b/plugins/gitiles
index cd9cddd..461cb07 160000
--- a/plugins/gitiles
+++ b/plugins/gitiles
@@ -1 +1 @@
-Subproject commit cd9cdddfb0747065b532817f8eca27bb5ed04478
+Subproject commit 461cb074b936c264b02f030e616803e908a0dc56
diff --git a/plugins/hooks b/plugins/hooks
index 034b9a4..a108d1d 160000
--- a/plugins/hooks
+++ b/plugins/hooks
@@ -1 +1 @@
-Subproject commit 034b9a4d48b739eb4c5ffb66be7cb808579a7a48
+Subproject commit a108d1df76ee42dd20cc7c64ab166f6c05ee8283
diff --git a/plugins/replication b/plugins/replication
index fdf8449..7743523 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit fdf84493424a5df5f1906beaaa7da714f848ddae
+Subproject commit 774352392db33950f85ec8da5a75c29085e3bf56
diff --git a/plugins/reviewnotes b/plugins/reviewnotes
index f851afa..650e5eb 160000
--- a/plugins/reviewnotes
+++ b/plugins/reviewnotes
@@ -1 +1 @@
-Subproject commit f851afa24966cc4d1011d67b8089069665e9dc98
+Subproject commit 650e5eba44813061ed76a5fc00fbf0dabdd74057
diff --git a/plugins/webhooks b/plugins/webhooks
index 6200831..0402faa 160000
--- a/plugins/webhooks
+++ b/plugins/webhooks
@@ -1 +1 @@
-Subproject commit 62008312ac68eaf109bad1200371eb505ee5c511
+Subproject commit 0402faa6e0b00689f034d64d858b5c08febc6422