Merge "Improve tools/run_dev.sh to allow custom flags"
diff --git a/.bazelversion b/.bazelversion
index 0062ac9..91e4a9f 100644
--- a/.bazelversion
+++ b/.bazelversion
@@ -1 +1 @@
-5.0.0
+6.3.2
diff --git a/.zuul.yaml b/.zuul.yaml
new file mode 100644
index 0000000..0758980
--- /dev/null
+++ b/.zuul.yaml
@@ -0,0 +1,4 @@
+- project:
+    check:
+      jobs:
+        - gitiles-build
diff --git a/WORKSPACE b/WORKSPACE
index ff06b2b..0c55d21 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -38,6 +38,18 @@
 register_toolchains("//tools:error_prone_warnings_toolchain_java17_definition")
 
 maven_jar(
+    name = "error-prone-annotations",
+    artifact = "com.google.errorprone:error_prone_annotations:2.22.0",
+    sha1 = "bfb9e4281a4cea34f0ec85b3acd47621cfab35b4",
+)
+
+maven_jar(
+    name = "commons-codec",
+    artifact = "commons-codec:commons-codec:1.15",
+    sha1 = "49d94806b6e3dc933dacbd8acb0fdbab8ebd1e5d",
+)
+
+maven_jar(
     name = "commons-lang3",
     artifact = "org.apache.commons:commons-lang3:3.8.1",
     sha1 = "6505a72a097d9270f7a9e7bf42c4238283247755",
@@ -57,8 +69,8 @@
 
 maven_jar(
     name = "guava",
-    artifact = "com.google.guava:guava:30.1-jre",
-    sha1 = "00d0c3ce2311c9e36e73228da25a6e99b2ab826f",
+    artifact = "com.google.guava:guava:32.1.2-jre",
+    sha1 = "5e64ec7e056456bef3a4bc4c6fdaef71e8ab6318",
 )
 
 maven_jar(
@@ -128,8 +140,40 @@
 
 maven_jar(
     name = "soy",
-    artifact = "com.google.template:soy:2021-02-01",
-    sha1 = "8e833744832ba88059205a1e30e0898f925d8cb5",
+    artifact = "com.google.template:soy:2022-07-20",
+    sha1 = "f64eb90da6d91beddf11653865c90f26d26710cf",
+)
+
+FLOGGER_VERS = "0.7.4"
+
+maven_jar(
+    name = "log4j",
+    artifact = "ch.qos.reload4j:reload4j:1.2.18.0",
+    sha1 = "03b2b708403ab00eb0678bffdbbd567070bbdfab",
+)
+
+maven_jar(
+    name = "flogger",
+    artifact = "com.google.flogger:flogger:" + FLOGGER_VERS,
+    sha1 = "cec29ed8b58413c2e935d86b12d6b696dc285419",
+)
+
+maven_jar(
+    name = "flogger-log4j-backend",
+    artifact = "com.google.flogger:flogger-log4j-backend:" + FLOGGER_VERS,
+    sha1 = "7486b1c0138647cd7714eccb8ce37b5f2ae20a76",
+)
+
+maven_jar(
+    name = "flogger-google-extensions",
+    artifact = "com.google.flogger:google-extensions:" + FLOGGER_VERS,
+    sha1 = "c49493bd815e3842b8406e21117119d560399977",
+)
+
+maven_jar(
+    name = "flogger-system-backend",
+    artifact = "com.google.flogger:flogger-system-backend:" + FLOGGER_VERS,
+    sha1 = "4bee7ebbd97c63ca7fb17529aeb49a57b670d061",
 )
 
 maven_jar(
@@ -225,32 +269,6 @@
     sha1 = "a41f9cfe6faafb2eb83a1c7dd2d0dfd844e2a936",
 )
 
-GUICE_VERSION = "5.0.1"
-
-maven_jar(
-    name = "guice-library",
-    artifact = "com.google.inject:guice:" + GUICE_VERSION,
-    sha1 = "0dae7556b441cada2b4f0a2314eb68e1ff423429",
-)
-
-maven_jar(
-    name = "guice-assistedinject",
-    artifact = "com.google.inject.extensions:guice-assistedinject:" + GUICE_VERSION,
-    sha1 = "62e02f2aceb7d90ba354584dacc018c1e94ff01c",
-)
-
-maven_jar(
-    name = "aopalliance",
-    artifact = "aopalliance:aopalliance:1.0",
-    sha1 = "0235ba8b489512805ac13a8f9ea77a1ca5ebe3e8",
-)
-
-maven_jar(
-    name = "javax-inject",
-    artifact = "javax.inject:javax.inject:1",
-    sha1 = "6975da39a7040257bd51d21a231b76c915872d38",
-)
-
 JETTY_VERSION = "9.4.49.v20220914"
 
 maven_jar(
diff --git a/java/com/google/gitiles/AbstractHttpFilter.java b/java/com/google/gitiles/AbstractHttpFilter.java
index f1a7657..51035b7 100644
--- a/java/com/google/gitiles/AbstractHttpFilter.java
+++ b/java/com/google/gitiles/AbstractHttpFilter.java
@@ -42,7 +42,12 @@
     // Default implementation does nothing.
   }
 
-  /** @see #doFilter(ServletRequest, ServletResponse, FilterChain) */
+  /**
+   * The FilterChain passed in to this method allows the Filter to pass on the request and response
+   * to the next entity in the chain.
+   *
+   * @see #doFilter(ServletRequest, ServletResponse, FilterChain)
+   */
   public abstract void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
       throws IOException, ServletException;
 }
diff --git a/java/com/google/gitiles/BUILD b/java/com/google/gitiles/BUILD
index 4b0850a..58934c0 100644
--- a/java/com/google/gitiles/BUILD
+++ b/java/com/google/gitiles/BUILD
@@ -6,6 +6,7 @@
     "//lib:autolink",
     "//lib:commons-lang3",
     "//lib:commons-text",
+    "//lib:errorprone-annotations",
     "//lib:gson",
     "//lib:guava",
     "//lib:html-types",
@@ -18,13 +19,13 @@
     "//lib:jgit",
     "//lib:jgit-servlet",
     "//lib:slf4j-api",
-    "//lib/soy:soy",
+    "//lib/flogger",
+    "//lib/soy",
     "//java/com/google/gitiles/blame/cache",
 ]
 
 DEPS_ALL = DEPS + [
     "//lib:jgit-archive",
-    "//lib/guice:guice",
 ]
 
 java_library(
diff --git a/java/com/google/gitiles/BaseServlet.java b/java/com/google/gitiles/BaseServlet.java
index 860ffd8..2aea97d 100644
--- a/java/com/google/gitiles/BaseServlet.java
+++ b/java/com/google/gitiles/BaseServlet.java
@@ -133,6 +133,8 @@
   }
 
   /**
+   * Get default format
+   *
    * @param req in-progress request.
    * @return the default {@link FormatType} used when {@code ?format=} is not specified.
    */
@@ -294,8 +296,8 @@
    *
    * @param req in-progress request.
    * @param res in-progress response.
-   * @param src @see com.google.gson.Gson#toJson(Object, Type, Appendable)
-   * @param typeOfSrc @see com.google.gson.Gson#toJson(Object, Type, Appendable)
+   * @param src source, @see com.google.gson.Gson#toJson(Object, Type, Appendable)
+   * @param typeOfSrc type of source, @see com.google.gson.Gson#toJson(Object, Type, Appendable)
    */
   protected void renderJson(
       HttpServletRequest req, HttpServletResponse res, Object src, Type typeOfSrc)
@@ -317,6 +319,8 @@
   }
 
   /**
+   * Start to render text.
+   *
    * @see #startRenderText(HttpServletRequest, HttpServletResponse)
    * @param req in-progress request.
    * @param res in-progress response.
@@ -353,7 +357,7 @@
    * @param res in-progress response.
    * @param statusCode HTTP status code.
    * @param message full message text.
-   * @throws IOException
+   * @throws IOException if an IO error occurred.
    */
   protected void renderTextError(
       HttpServletRequest req, HttpServletResponse res, int statusCode, String message)
diff --git a/java/com/google/gitiles/BlobSoyData.java b/java/com/google/gitiles/BlobSoyData.java
index 7e96d65..a6879ae 100644
--- a/java/com/google/gitiles/BlobSoyData.java
+++ b/java/com/google/gitiles/BlobSoyData.java
@@ -28,6 +28,7 @@
 import java.io.IOException;
 import java.util.List;
 import java.util.Map;
+import javax.annotation.Nullable;
 import org.eclipse.jgit.diff.RawText;
 import org.eclipse.jgit.errors.LargeObjectException;
 import org.eclipse.jgit.errors.MissingObjectException;
@@ -194,7 +195,7 @@
     return n < end ? n : -1;
   }
 
-  private static String extension(String path, String content) {
+  private static @Nullable String extension(String path, String content) {
     if (content.startsWith("#!/bin/sh") || content.startsWith("#!/bin/bash")) {
       return "sh";
     } else if (content.startsWith("#!/usr/bin/perl")) {
diff --git a/java/com/google/gitiles/CommitJsonData.java b/java/com/google/gitiles/CommitJsonData.java
index 5f94a70..478d98f 100644
--- a/java/com/google/gitiles/CommitJsonData.java
+++ b/java/com/google/gitiles/CommitJsonData.java
@@ -64,7 +64,7 @@
     List<Diff> treeDiff;
   }
 
-  /** @see DiffEntry */
+  /** Diff @see DiffEntry */
   static class Diff {
     String type;
     String oldId;
@@ -108,7 +108,7 @@
     if (cd.message != null) {
       result.message = cd.message;
     }
-    if (cd.notes != null && !cd.notes.isEmpty()){
+    if (cd.notes != null && !cd.notes.isEmpty()) {
       result.notes = cd.notes;
     }
     if (cd.diffEntries != null) {
diff --git a/java/com/google/gitiles/CommitSoyData.java b/java/com/google/gitiles/CommitSoyData.java
index ac81f80..e3e5e2b 100644
--- a/java/com/google/gitiles/CommitSoyData.java
+++ b/java/com/google/gitiles/CommitSoyData.java
@@ -185,7 +185,7 @@
       if (parents.size() == 1) {
         parentName = view.getRevision().getName() + "^";
       } else {
-        parentName = view.getRevision().getName() + "^" + (i++);
+        parentName = view.getRevision().getName() + "^" + i++;
       }
       diff.setOldRevision(parentName, parent);
 
diff --git a/java/com/google/gitiles/DescribeServlet.java b/java/com/google/gitiles/DescribeServlet.java
index 545f3aa..c3b178e 100644
--- a/java/com/google/gitiles/DescribeServlet.java
+++ b/java/com/google/gitiles/DescribeServlet.java
@@ -22,6 +22,7 @@
 import java.io.Writer;
 import java.util.List;
 import java.util.Map;
+import javax.annotation.Nullable;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import org.eclipse.jgit.api.Git;
@@ -91,7 +92,7 @@
     }
   }
 
-  private String describe(Repository repo, GitilesView view, HttpServletRequest req)
+  private @Nullable String describe(Repository repo, GitilesView view, HttpServletRequest req)
       throws IOException {
     if (!getBooleanParam(view, CONTAINS_PARAM)) {
       throw new GitilesRequestFailureException(FailureReason.INCORECT_PARAMETER);
diff --git a/java/com/google/gitiles/DiffServlet.java b/java/com/google/gitiles/DiffServlet.java
index 03353ac..53552e9 100644
--- a/java/com/google/gitiles/DiffServlet.java
+++ b/java/com/google/gitiles/DiffServlet.java
@@ -26,6 +26,7 @@
 import java.util.Arrays;
 import java.util.Map;
 import java.util.Set;
+import javax.annotation.Nullable;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import org.eclipse.jgit.diff.DiffFormatter;
@@ -140,7 +141,7 @@
     }
   }
 
-  private static TreeWalk newTreeWalk(RevWalk walk, GitilesView view) throws IOException {
+  private static @Nullable TreeWalk newTreeWalk(RevWalk walk, GitilesView view) throws IOException {
     if (view.getPathPart().isEmpty()) {
       return null;
     }
diff --git a/java/com/google/gitiles/FormatType.java b/java/com/google/gitiles/FormatType.java
index 3a2579a..8751937 100644
--- a/java/com/google/gitiles/FormatType.java
+++ b/java/com/google/gitiles/FormatType.java
@@ -15,6 +15,7 @@
 package com.google.gitiles;
 
 import com.google.common.base.Enums;
+import com.google.common.base.Splitter;
 import com.google.common.base.Strings;
 import com.google.common.net.HttpHeaders;
 import java.util.Optional;
@@ -29,6 +30,8 @@
 
   private static final String FORMAT_TYPE_ATTRIBUTE = FormatType.class.getName();
 
+  private static final Splitter SPLITTER = Splitter.onPattern("[ ,;][ ,;]*");
+
   public static Optional<FormatType> getFormatType(HttpServletRequest req) {
     @SuppressWarnings("unchecked")
     Optional<FormatType> result = (Optional<FormatType>) req.getAttribute(FORMAT_TYPE_ATTRIBUTE);
@@ -47,7 +50,7 @@
       return set(req, Optional.of(DEFAULT));
     }
 
-    for (String p : accept.split("[ ,;][ ,;]*")) {
+    for (String p : SPLITTER.split(accept)) {
       for (FormatType type : FormatType.values()) {
         if (p.equals(type.mimeType)) {
           return set(req, Optional.of(type != HTML ? type : DEFAULT));
diff --git a/java/com/google/gitiles/GitilesAccess.java b/java/com/google/gitiles/GitilesAccess.java
index 505098a..55d6922 100644
--- a/java/com/google/gitiles/GitilesAccess.java
+++ b/java/com/google/gitiles/GitilesAccess.java
@@ -68,21 +68,31 @@
       throws ServiceNotEnabledException, ServiceNotAuthorizedException, IOException;
 
   /**
+   * Get user key.
+   *
    * @return an opaque object that uniquely identifies the end-user making the request, and supports
    *     {@link Object#equals(Object)} and {@link Object#hashCode()}. Never null.
    */
   Object getUserKey();
 
-  /** @return the repository name associated with the request. */
+  /**
+   * Get repository name.
+   *
+   * @return the repository name associated with the request.
+   */
   String getRepositoryName();
 
   /**
+   * Get repository description.
+   *
    * @return the description attached to the repository of this request.
    * @throws IOException an error occurred reading the description string from the repository.
    */
   RepositoryDescription getRepositoryDescription() throws IOException;
 
   /**
+   * Get configuration.
+   *
    * @return configuration to apply to the host/repository for this request.
    * @throws IOException an error occurred reading the configuration.
    */
diff --git a/java/com/google/gitiles/GitilesFilter.java b/java/com/google/gitiles/GitilesFilter.java
index da6044b..41c6ea4 100644
--- a/java/com/google/gitiles/GitilesFilter.java
+++ b/java/com/google/gitiles/GitilesFilter.java
@@ -229,10 +229,7 @@
     }
     root.through(dispatchFilter);
 
-    serveRegex(REPO_REGEX)
-        .through(repositoryFilter)
-        .through(viewFilter)
-        .through(dispatchFilter);
+    serveRegex(REPO_REGEX).through(repositoryFilter).through(viewFilter).through(dispatchFilter);
 
     serveRegex(REPO_PATH_REGEX)
         .through(repositoryFilter)
diff --git a/java/com/google/gitiles/GitilesRequestFailureException.java b/java/com/google/gitiles/GitilesRequestFailureException.java
index dd990a8..c4fd48a 100644
--- a/java/com/google/gitiles/GitilesRequestFailureException.java
+++ b/java/com/google/gitiles/GitilesRequestFailureException.java
@@ -20,6 +20,8 @@
 import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
 import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
 
+import com.google.errorprone.annotations.FormatMethod;
+import com.google.errorprone.annotations.FormatString;
 import java.util.Optional;
 import javax.annotation.Nullable;
 
@@ -102,7 +104,9 @@
     this.reason = reason;
   }
 
-  public GitilesRequestFailureException withPublicErrorMessage(String format, Object... params) {
+  @FormatMethod
+  public GitilesRequestFailureException withPublicErrorMessage(
+      @FormatString String format, Object... params) {
     this.publicErrorMessage = String.format(format, params);
     return this;
   }
diff --git a/java/com/google/gitiles/GitilesView.java b/java/com/google/gitiles/GitilesView.java
index e721c26..9bb43a9 100644
--- a/java/com/google/gitiles/GitilesView.java
+++ b/java/com/google/gitiles/GitilesView.java
@@ -39,6 +39,7 @@
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Map;
+import javax.annotation.Nullable;
 import javax.servlet.http.HttpServletRequest;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.revwalk.RevObject;
@@ -374,6 +375,7 @@
       return build().toUrl();
     }
 
+    @SuppressWarnings("AnnotateFormatMethod")
     private void checkView(boolean expr, String msg, Object... args) {
       if (!expr) {
         throw new InvalidViewException(String.format(msg, args));
@@ -560,7 +562,7 @@
     return oldRevision;
   }
 
-  public String getRevisionRange() {
+  public @Nullable String getRevisionRange() {
     if (Revision.isNull(oldRevision)) {
       if (type == Type.LOG || type == Type.DIFF) {
         // For types that require two revisions, NULL indicates the empty
@@ -617,7 +619,11 @@
     return b.toString();
   }
 
-  /** @return an escaped, relative URL representing this view. */
+  /**
+   * Create relative URL representing this view.
+   *
+   * @return an escaped, relative URL representing this view.
+   */
   public String toUrl() {
     StringBuilder url = new StringBuilder(servletPath).append('/');
     ListMultimap<String, String> params = this.params;
@@ -726,6 +732,8 @@
   }
 
   /**
+   * Get breadcrumbs.
+   *
    * @return a list of maps with "text" and "url" keys for all file paths leading up to the path
    *     represented by this view. All URLs allow auto-diving into one-entry subtrees; see also
    *     {@link #getBreadcrumbs(List)}.
@@ -737,6 +745,8 @@
   private static final EnumSet<Type> NON_HTML_TYPES = EnumSet.of(Type.DESCRIBE, Type.ARCHIVE);
 
   /**
+   * Get breadcrumbs.
+   *
    * @param hasSingleTree list of booleans, one per path entry in this view's path excluding the
    *     leaf. True entries indicate the tree at that path only has a single entry that is another
    *     tree.
diff --git a/java/com/google/gitiles/GitwebRedirectFilter.java b/java/com/google/gitiles/GitwebRedirectFilter.java
index cc8bca0..52a6965 100644
--- a/java/com/google/gitiles/GitwebRedirectFilter.java
+++ b/java/com/google/gitiles/GitwebRedirectFilter.java
@@ -32,6 +32,7 @@
 import java.net.URLDecoder;
 import java.util.List;
 import java.util.regex.Pattern;
+import javax.annotation.Nullable;
 import javax.servlet.FilterChain;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
@@ -146,7 +147,7 @@
     return Iterables.getFirst(params.get(checkNotNull(name)), null);
   }
 
-  private static Revision toRevision(String rev) {
+  private static @Nullable Revision toRevision(String rev) {
     if (Strings.isNullOrEmpty(rev)) {
       return null;
     } else if ("HEAD".equals(rev) || rev.startsWith("refs/")) {
diff --git a/java/com/google/gitiles/IdentRevFilter.java b/java/com/google/gitiles/IdentRevFilter.java
index ef3ddf8..bc29373 100644
--- a/java/com/google/gitiles/IdentRevFilter.java
+++ b/java/com/google/gitiles/IdentRevFilter.java
@@ -51,7 +51,11 @@
     return this;
   }
 
-  /** @return whether the given person matches the author filter. */
+  /**
+   * Whether the given person matches the author filter.
+   *
+   * @return whether the given person matches the author filter.
+   */
   @VisibleForTesting
   boolean matchesPerson(PersonIdent person) {
     // Equivalent to --fixed-strings, to avoid pathological performance of Java
diff --git a/java/com/google/gitiles/LogServlet.java b/java/com/google/gitiles/LogServlet.java
index 51ab68d..9a66ef8 100644
--- a/java/com/google/gitiles/LogServlet.java
+++ b/java/com/google/gitiles/LogServlet.java
@@ -36,6 +36,7 @@
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
+import javax.annotation.Nullable;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import org.eclipse.jgit.diff.DiffConfig;
@@ -178,7 +179,8 @@
     }
   }
 
-  private static GitilesView getView(HttpServletRequest req, Repository repo) throws IOException {
+  private static @Nullable GitilesView getView(HttpServletRequest req, Repository repo)
+      throws IOException {
     GitilesView view = ViewFilter.getView(req);
     if (!Revision.isNull(view.getRevision())) {
       return view;
@@ -225,7 +227,7 @@
     }
   }
 
-  private static RevWalk newWalk(Repository repo, GitilesView view, GitilesAccess access)
+  private static @Nullable RevWalk newWalk(Repository repo, GitilesView view, GitilesAccess access)
       throws MissingObjectException, IOException {
     RevWalk walk = new RevWalk(repo);
     if (isTrue(view, FIRST_PARENT_PARAM)) {
@@ -307,8 +309,8 @@
     return Boolean.TRUE.equals(StringUtils.toBooleanOrNull(v));
   }
 
-  private static Paginator newPaginator(Repository repo, GitilesView view, GitilesAccess access)
-      throws IOException {
+  private static @Nullable Paginator newPaginator(
+      Repository repo, GitilesView view, GitilesAccess access) throws IOException {
     if (view == null) {
       return null;
     }
diff --git a/java/com/google/gitiles/LogSoyData.java b/java/com/google/gitiles/LogSoyData.java
index 34b290f..061ce23 100644
--- a/java/com/google/gitiles/LogSoyData.java
+++ b/java/com/google/gitiles/LogSoyData.java
@@ -144,7 +144,7 @@
         "entry", entry);
   }
 
-  private Map<String, Object> toRenameSoyData(DiffEntry entry) {
+  private @Nullable Map<String, Object> toRenameSoyData(DiffEntry entry) {
     if (entry == null) {
       return null;
     }
diff --git a/java/com/google/gitiles/Paginator.java b/java/com/google/gitiles/Paginator.java
index 3060e45..eed7b75 100644
--- a/java/com/google/gitiles/Paginator.java
+++ b/java/com/google/gitiles/Paginator.java
@@ -121,7 +121,8 @@
    * @throws IncorrectObjectTypeException See {@link RevWalk#next()}.
    * @throws IOException See {@link RevWalk#next()}.
    */
-  public RevCommit next() throws MissingObjectException, IncorrectObjectTypeException, IOException {
+  public @Nullable RevCommit next()
+      throws MissingObjectException, IncorrectObjectTypeException, IOException {
     if (done) {
       return null;
     }
@@ -160,6 +161,8 @@
   }
 
   /**
+   * Get previous start.
+   *
    * @return the ID at the start of the page of results preceding this one, or null if this is the
    *     first page.
    */
@@ -168,6 +171,8 @@
   }
 
   /**
+   * Get next start.
+   *
    * @return the ID at the start of the page of results after this one, or null if this is the last
    *     page.
    */
@@ -176,12 +181,18 @@
     return nextStart;
   }
 
-  /** @return entry corresponding to a rename or copy at the given commit. */
-  public DiffEntry getRename(ObjectId commitId) {
+  /**
+   * Get rename.
+   *
+   * @return entry corresponding to a rename or copy at the given commit.
+   */
+  public @Nullable DiffEntry getRename(ObjectId commitId) {
     return renamed != null ? renamed.get(commitId) : null;
   }
 
   /**
+   * Get iterator over the commits in this walk.
+   *
    * @return an iterator over the commits in this walk.
    * @throws RevWalkException if an error occurred, wrapping the checked exception from {@link
    *     #next()}.
diff --git a/java/com/google/gitiles/PathServlet.java b/java/com/google/gitiles/PathServlet.java
index 9475ae7..87d2680 100644
--- a/java/com/google/gitiles/PathServlet.java
+++ b/java/com/google/gitiles/PathServlet.java
@@ -34,6 +34,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.regex.Pattern;
+import javax.annotation.Nullable;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import org.eclipse.jgit.errors.ConfigInvalidException;
@@ -103,7 +104,7 @@
       this.mode = mode;
     }
 
-    static FileType forEntry(TreeWalk tw) {
+    static @Nullable FileType forEntry(TreeWalk tw) {
       int mode = tw.getRawMode(0);
       for (FileType type : values()) {
         if (type.mode.equals(mode)) {
@@ -296,7 +297,7 @@
     }
   }
 
-  private static RevTree getRoot(GitilesView view, RevWalk rw) throws IOException {
+  private static @Nullable RevTree getRoot(GitilesView view, RevWalk rw) throws IOException {
     RevObject obj = rw.peel(rw.parseAny(view.getRevision().getId()));
     switch (obj.getType()) {
       case OBJ_COMMIT:
@@ -380,7 +381,8 @@
    * to help the auto-dive routine as well.
    */
   private static class WalkResult implements AutoCloseable {
-    private static WalkResult recursivePath(RevWalk rw, GitilesView view) throws IOException {
+    private static @Nullable WalkResult recursivePath(RevWalk rw, GitilesView view)
+        throws IOException {
       RevTree root = getRoot(view, rw);
       String path = view.getPathPart();
 
@@ -410,7 +412,7 @@
       return new WalkResult(tw, path, root, root, FileType.TREE, ImmutableList.<Boolean>of());
     }
 
-    private static WalkResult forPath(RevWalk rw, GitilesView view, boolean recursive)
+    private static @Nullable WalkResult forPath(RevWalk rw, GitilesView view, boolean recursive)
         throws IOException {
       if (recursive) {
         return recursivePath(rw, view);
@@ -520,8 +522,8 @@
                     .toSoyData(wr.id, wr.tw)));
   }
 
-  private CanonicalTreeParser getOnlyChildSubtree(ObjectReader reader, ObjectId id, byte[] prefix)
-      throws IOException {
+  private @Nullable CanonicalTreeParser getOnlyChildSubtree(
+      ObjectReader reader, ObjectId id, byte[] prefix) throws IOException {
     CanonicalTreeParser p = new CanonicalTreeParser(prefix, reader, id);
     if (p.eof() || p.getEntryFileMode() != FileMode.TREE) {
       return null;
@@ -655,7 +657,7 @@
     return remoteUrl != null ? remoteUrl : modulesUrl;
   }
 
-  private static String resolveHttpUrl(String remoteUrl) {
+  private static @Nullable String resolveHttpUrl(String remoteUrl) {
     if (remoteUrl == null) {
       return null;
     }
diff --git a/java/com/google/gitiles/PathUtil.java b/java/com/google/gitiles/PathUtil.java
index 2df8cdc..7d230f2 100644
--- a/java/com/google/gitiles/PathUtil.java
+++ b/java/com/google/gitiles/PathUtil.java
@@ -19,13 +19,14 @@
 import com.google.common.base.Strings;
 import com.google.common.io.Files;
 import java.util.StringTokenizer;
+import javax.annotation.Nullable;
 
 /** Static utilities for dealing with pathnames. */
 class PathUtil {
   private static final CharMatcher MATCHER = CharMatcher.is('/');
   static final Splitter SPLITTER = Splitter.on(MATCHER);
 
-  static String simplifyPathUpToRoot(String path, String root) {
+  static @Nullable String simplifyPathUpToRoot(String path, String root) {
     if (path.startsWith("/")) {
       return null;
     }
diff --git a/java/com/google/gitiles/ReadmeHelper.java b/java/com/google/gitiles/ReadmeHelper.java
index a01c7f0..389c73c 100644
--- a/java/com/google/gitiles/ReadmeHelper.java
+++ b/java/com/google/gitiles/ReadmeHelper.java
@@ -19,6 +19,7 @@
 import com.google.gitiles.doc.MarkdownConfig;
 import com.google.gitiles.doc.MarkdownToHtml;
 import java.io.IOException;
+import javax.annotation.Nullable;
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
@@ -87,6 +88,7 @@
     return readmePath;
   }
 
+  @Nullable
   SafeHtml render() {
     try {
       byte[] raw = reader.open(readmeId, Constants.OBJ_BLOB).getCachedBytes(config.inputLimit);
diff --git a/java/com/google/gitiles/Renderer.java b/java/com/google/gitiles/Renderer.java
index 3bf9754..dd08353 100644
--- a/java/com/google/gitiles/Renderer.java
+++ b/java/com/google/gitiles/Renderer.java
@@ -237,7 +237,7 @@
             .put("staticUrls", staticUrls.build())
             .put("SITE_TITLE", siteTitle);
     Optional<String> nonce = req.map((r) -> (String) r.getAttribute("nonce"));
-    if (nonce.isPresent() && nonce.get() != null) {
+    if (nonce.isPresent()) {
       ij.put("csp_nonce", nonce.get());
     }
     return getSauce().renderTemplate(templateName).setIj(ij.build());
diff --git a/java/com/google/gitiles/RepositoryIndexServlet.java b/java/com/google/gitiles/RepositoryIndexServlet.java
index 0360588..a491976 100644
--- a/java/com/google/gitiles/RepositoryIndexServlet.java
+++ b/java/com/google/gitiles/RepositoryIndexServlet.java
@@ -31,6 +31,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import javax.annotation.Nullable;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@@ -154,7 +155,7 @@
     return list.size() > REF_LIMIT ? list.subList(0, REF_LIMIT) : list;
   }
 
-  private static Map<String, Object> renderReadme(
+  private static @Nullable Map<String, Object> renderReadme(
       HttpServletRequest req, RevWalk walk, GitilesView view, Config cfg, RevObject head)
       throws IOException {
     RevTree rootTree;
diff --git a/java/com/google/gitiles/RevisionParser.java b/java/com/google/gitiles/RevisionParser.java
index 8196267..7fbf86c 100644
--- a/java/com/google/gitiles/RevisionParser.java
+++ b/java/com/google/gitiles/RevisionParser.java
@@ -27,6 +27,7 @@
 import java.util.Optional;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import javax.annotation.Nullable;
 import org.eclipse.jgit.errors.AmbiguousObjectException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.errors.RevisionSyntaxException;
@@ -114,6 +115,7 @@
     this.branchRedirect = checkNotNull(branchRedirect, "branchRedirect");
   }
 
+  @Nullable
   Result parse(String path) throws IOException {
     if (path.startsWith("/")) {
       path = path.substring(1);
@@ -231,7 +233,7 @@
     }
   }
 
-  private RevObject resolve(String name, RevWalk walk) throws IOException {
+  private @Nullable RevObject resolve(String name, RevWalk walk) throws IOException {
     try {
       ObjectId id = repo.resolve(name);
       return id != null ? walk.parseAny(id) : null;
diff --git a/java/com/google/gitiles/TimeCache.java b/java/com/google/gitiles/TimeCache.java
index e1e55ce..4350d5c 100644
--- a/java/com/google/gitiles/TimeCache.java
+++ b/java/com/google/gitiles/TimeCache.java
@@ -65,7 +65,7 @@
               RevTag tag = (RevTag) o;
               PersonIdent ident = tag.getTaggerIdent();
               if (ident != null) {
-                return ident.getWhen().getTime() / 1000;
+                return ident.getWhenAsInstant().toEpochMilli() / 1000;
               }
               o = tag.getObject();
               walk.parseHeaders(o);
diff --git a/java/com/google/gitiles/TreeSoyData.java b/java/com/google/gitiles/TreeSoyData.java
index 985edfa..4e2a579 100644
--- a/java/com/google/gitiles/TreeSoyData.java
+++ b/java/com/google/gitiles/TreeSoyData.java
@@ -26,6 +26,7 @@
 import java.io.IOException;
 import java.util.List;
 import java.util.Map;
+import javax.annotation.Nullable;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.ObjectId;
@@ -55,7 +56,7 @@
    */
   static final int MAX_SYMLINK_SIZE = 16 << 10;
 
-  static String resolveTargetUrl(GitilesView view, String target) {
+  static @Nullable String resolveTargetUrl(GitilesView view, String target) {
     String resolved = PathUtil.simplifyPathUpToRoot(target, view.getPathPart());
     if (resolved == null) {
       return null;
diff --git a/java/com/google/gitiles/ViewFilter.java b/java/com/google/gitiles/ViewFilter.java
index dd3d54a..6f124e5 100644
--- a/java/com/google/gitiles/ViewFilter.java
+++ b/java/com/google/gitiles/ViewFilter.java
@@ -22,6 +22,7 @@
 import com.google.gitiles.GitilesRequestFailureException.FailureReason;
 import java.io.IOException;
 import java.util.Map;
+import javax.annotation.Nullable;
 import javax.servlet.FilterChain;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
@@ -135,7 +136,7 @@
     return false;
   }
 
-  private GitilesView.Builder parse(HttpServletRequest req) throws IOException {
+  private @Nullable GitilesView.Builder parse(HttpServletRequest req) throws IOException {
     String repoName = trimLeadingSlash(getRegexGroup(req, 1));
     if (repoName.isEmpty()) {
       return GitilesView.hostIndex();
@@ -179,7 +180,7 @@
     return GitilesView.repositoryIndex().setRepositoryName(repoName);
   }
 
-  private GitilesView.Builder parseArchiveCommand(
+  private @Nullable GitilesView.Builder parseArchiveCommand(
       HttpServletRequest req, String repoName, String path) throws IOException {
     String ext = null;
     for (String e : ArchiveFormat.allExtensions()) {
@@ -203,8 +204,8 @@
         .setExtension(ext);
   }
 
-  private GitilesView.Builder parseAutoCommand(HttpServletRequest req, String repoName, String path)
-      throws IOException {
+  private @Nullable GitilesView.Builder parseAutoCommand(
+      HttpServletRequest req, String repoName, String path) throws IOException {
     // Note: if you change the mapping for +, make sure to change
     // GitilesView.toUrl() correspondingly.
     if (path.isEmpty()) {
@@ -227,7 +228,7 @@
     return b;
   }
 
-  private GitilesView.Builder parseBlameCommand(
+  private @Nullable GitilesView.Builder parseBlameCommand(
       HttpServletRequest req, String repoName, String path) throws IOException {
     if (path.isEmpty()) {
       return null;
@@ -242,7 +243,7 @@
         .setPathPart(result.getPath());
   }
 
-  private GitilesView.Builder parseDescribeCommand(String repoName, String path) {
+  private @Nullable GitilesView.Builder parseDescribeCommand(String repoName, String path) {
     if (isEmptyOrSlash(path)) {
       return null;
     }
@@ -254,7 +255,8 @@
     return parseDiffCommand(repoName, parseRevision(req, path));
   }
 
-  private GitilesView.Builder parseDiffCommand(String repoName, RevisionParser.Result result) {
+  private @Nullable GitilesView.Builder parseDiffCommand(
+      String repoName, RevisionParser.Result result) {
     if (result == null) {
       return null;
     }
@@ -265,8 +267,8 @@
         .setPathPart(result.getPath());
   }
 
-  private GitilesView.Builder parseLogCommand(HttpServletRequest req, String repoName, String path)
-      throws IOException {
+  private @Nullable GitilesView.Builder parseLogCommand(
+      HttpServletRequest req, String repoName, String path) throws IOException {
     if (isEmptyOrSlash(path)) {
       return GitilesView.log().setRepositoryName(repoName);
     }
@@ -290,7 +292,8 @@
     return parseShowCommand(repoName, parseRevision(req, path));
   }
 
-  private GitilesView.Builder parseShowCommand(String repoName, RevisionParser.Result result) {
+  private @Nullable GitilesView.Builder parseShowCommand(
+      String repoName, RevisionParser.Result result) {
     if (result == null || result.getOldRevision() != null) {
       return null;
     }
@@ -308,7 +311,8 @@
     return parseDocCommand(repoName, parseRevision(req, path));
   }
 
-  private GitilesView.Builder parseDocCommand(String repoName, RevisionParser.Result result) {
+  private @Nullable GitilesView.Builder parseDocCommand(
+      String repoName, RevisionParser.Result result) {
     if (result == null || result.getOldRevision() != null) {
       return null;
     }
diff --git a/java/com/google/gitiles/blame/BlameServlet.java b/java/com/google/gitiles/blame/BlameServlet.java
index 9dd5e91..179b5d6 100644
--- a/java/com/google/gitiles/blame/BlameServlet.java
+++ b/java/com/google/gitiles/blame/BlameServlet.java
@@ -39,6 +39,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import javax.annotation.Nullable;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@@ -183,7 +184,7 @@
     return new RegionResult(regions, lastCommitBlobId);
   }
 
-  private static ObjectId resolveBlob(GitilesView view, RevWalk rw, ObjectId commitId)
+  private static @Nullable ObjectId resolveBlob(GitilesView view, RevWalk rw, ObjectId commitId)
       throws IOException {
     try {
       if (commitId == null || Strings.isNullOrEmpty(view.getPathPart())) {
diff --git a/java/com/google/gitiles/blame/cache/BlameCache.java b/java/com/google/gitiles/blame/cache/BlameCache.java
index e7f9fca..57a9166 100644
--- a/java/com/google/gitiles/blame/cache/BlameCache.java
+++ b/java/com/google/gitiles/blame/cache/BlameCache.java
@@ -20,9 +20,17 @@
 import org.eclipse.jgit.lib.Repository;
 
 public interface BlameCache {
-  /** @return the blame of a path at a given commit. */
+  /**
+   * Gets the blame of a path at a given commit.
+   *
+   * @return the blame of a path at a given commit.
+   */
   List<Region> get(Repository repo, ObjectId commitId, String path) throws IOException;
 
-  /** @return the last commit that modified a path, starting at the given commit. */
+  /**
+   * Gets the last commit that modified a path.
+   *
+   * @return the last commit that modified a path, starting at the given commit.
+   */
   ObjectId findLastCommit(Repository repo, ObjectId commitId, String path) throws IOException;
 }
diff --git a/java/com/google/gitiles/doc/DocServlet.java b/java/com/google/gitiles/doc/DocServlet.java
index 4def176..d2ae028 100644
--- a/java/com/google/gitiles/doc/DocServlet.java
+++ b/java/com/google/gitiles/doc/DocServlet.java
@@ -158,7 +158,8 @@
     return h.hash().toString();
   }
 
-  private MarkdownFile findNavbar(RevWalk rw, RevTree root, String path) throws IOException {
+  private @Nullable MarkdownFile findNavbar(RevWalk rw, RevTree root, String path)
+      throws IOException {
     if (!Strings.isNullOrEmpty(path)) {
       // Traverse up the path until we find a NAVBAR_MD.
       StringBuilder pathRemaining = new StringBuilder(path);
@@ -229,8 +230,8 @@
     return MoreObjects.firstNonNull(title, srcFile.path);
   }
 
-  @Nullable
-  private static MarkdownFile findFile(RevWalk rw, RevTree root, String path) throws IOException {
+  private static @Nullable MarkdownFile findFile(RevWalk rw, RevTree root, String path)
+      throws IOException {
     if (Strings.isNullOrEmpty(path)) {
       path = INDEX_MD;
     }
diff --git a/java/com/google/gitiles/doc/GitilesHtmlExtension.java b/java/com/google/gitiles/doc/GitilesHtmlExtension.java
index 2a325b1..a8fc04f 100644
--- a/java/com/google/gitiles/doc/GitilesHtmlExtension.java
+++ b/java/com/google/gitiles/doc/GitilesHtmlExtension.java
@@ -17,6 +17,7 @@
 import com.google.gitiles.doc.html.HtmlBuilder;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import javax.annotation.Nullable;
 import org.commonmark.Extension;
 import org.commonmark.node.AbstractVisitor;
 import org.commonmark.node.HardLineBreak;
@@ -145,7 +146,7 @@
     }
   }
 
-  private static IframeBlock iframe(String html) {
+  private static @Nullable IframeBlock iframe(String html) {
     IframeBlock iframe = new IframeBlock();
     Matcher m = ATTR.matcher(html);
     while (m.find()) {
diff --git a/java/com/google/gitiles/doc/ImageLoader.java b/java/com/google/gitiles/doc/ImageLoader.java
index 81724b6..0a1cc3d 100644
--- a/java/com/google/gitiles/doc/ImageLoader.java
+++ b/java/com/google/gitiles/doc/ImageLoader.java
@@ -57,7 +57,7 @@
     return SoyConstants.IMAGE_URI_INNOCUOUS_OUTPUT;
   }
 
-  private String inlineMaybe(@Nullable String markdownPath, String imagePath) {
+  private @Nullable String inlineMaybe(@Nullable String markdownPath, String imagePath) {
     if (config.imageLimit <= 0) {
       return null;
     }
diff --git a/java/com/google/gitiles/doc/MarkdownToHtml.java b/java/com/google/gitiles/doc/MarkdownToHtml.java
index a2d5752..cb8afae 100644
--- a/java/com/google/gitiles/doc/MarkdownToHtml.java
+++ b/java/com/google/gitiles/doc/MarkdownToHtml.java
@@ -149,7 +149,7 @@
     return html;
   }
 
-  private static ImageLoader newImageLoader(Builder b) {
+  private static @Nullable ImageLoader newImageLoader(Builder b) {
     if (b.reader != null && b.view != null && b.config != null && b.root != null) {
       return new ImageLoader(b.reader, b.view, b.config, b.root);
     }
@@ -170,7 +170,7 @@
   }
 
   /** Render the document AST to sanitized HTML. */
-  public SafeHtml toSoyHtml(Node node) {
+  public @Nullable SafeHtml toSoyHtml(Node node) {
     if (node != null) {
       SoyHtmlBuilder out = new SoyHtmlBuilder();
       renderToHtml(out, node);
diff --git a/java/com/google/gitiles/doc/MarkdownUtil.java b/java/com/google/gitiles/doc/MarkdownUtil.java
index 9a6bb82..b3ce433 100644
--- a/java/com/google/gitiles/doc/MarkdownUtil.java
+++ b/java/com/google/gitiles/doc/MarkdownUtil.java
@@ -16,13 +16,14 @@
 
 import com.google.common.base.CharMatcher;
 import com.google.common.base.Strings;
+import javax.annotation.Nullable;
 import org.commonmark.node.Heading;
 import org.commonmark.node.Node;
 import org.commonmark.node.Text;
 
 class MarkdownUtil {
   /** Combine child nodes as string; this must be escaped for HTML. */
-  static String getInnerText(Node node) {
+  static @Nullable String getInnerText(Node node) {
     if (node == null || node.getFirstChild() == null) {
       return null;
     }
@@ -42,7 +43,7 @@
     }
   }
 
-  static String getTitle(Node node) {
+  static @Nullable String getTitle(Node node) {
     if (node instanceof Heading) {
       if (((Heading) node).getLevel() == 1) {
         return getInnerText(node);
diff --git a/java/com/google/gitiles/doc/Navbar.java b/java/com/google/gitiles/doc/Navbar.java
index 0fc2758..60d1059 100644
--- a/java/com/google/gitiles/doc/Navbar.java
+++ b/java/com/google/gitiles/doc/Navbar.java
@@ -25,6 +25,7 @@
 import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import javax.annotation.Nullable;
 import org.commonmark.node.Heading;
 import org.commonmark.node.Node;
 import org.eclipse.jgit.util.RawParseUtils;
@@ -75,7 +76,7 @@
     return data;
   }
 
-  private Object logo() {
+  private @Nullable Object logo() {
     if (logoUrl == null) {
       return null;
     }
diff --git a/java/com/google/gitiles/doc/SmartQuotedExtension.java b/java/com/google/gitiles/doc/SmartQuotedExtension.java
index f1b8c02..a8e7f13 100644
--- a/java/com/google/gitiles/doc/SmartQuotedExtension.java
+++ b/java/com/google/gitiles/doc/SmartQuotedExtension.java
@@ -17,7 +17,6 @@
 import static com.google.gitiles.doc.SmartQuoted.Type.DOUBLE;
 import static com.google.gitiles.doc.SmartQuoted.Type.SINGLE;
 
-import com.google.gitiles.doc.SmartQuoted.Type;
 import org.commonmark.Extension;
 import org.commonmark.node.Node;
 import org.commonmark.node.Text;
@@ -40,7 +39,7 @@
     builder.customDelimiterProcessor(new QuotedProcessor(DOUBLE, '"'));
   }
 
-  private static void quote(Type type, Text opener, Text closer) {
+  private static void quote(SmartQuoted.Type type, Text opener, Text closer) {
     SmartQuoted quote = new SmartQuoted();
     quote.setType(type);
     for (Node t = opener.getNext(); t != null && t != closer; ) {
diff --git a/java/com/google/gitiles/doc/TocFormatter.java b/java/com/google/gitiles/doc/TocFormatter.java
index 6f25f58..e45f37f 100644
--- a/java/com/google/gitiles/doc/TocFormatter.java
+++ b/java/com/google/gitiles/doc/TocFormatter.java
@@ -25,6 +25,7 @@
 import java.util.Deque;
 import java.util.List;
 import java.util.Map;
+import javax.annotation.Nullable;
 import org.apache.commons.lang3.StringUtils;
 import org.commonmark.node.Heading;
 import org.commonmark.node.Node;
@@ -149,7 +150,7 @@
     }
   }
 
-  private static NamedAnchor findAnchor(Node node) {
+  private static @Nullable NamedAnchor findAnchor(Node node) {
     for (Node c = node.getFirstChild(); c != null; c = c.getNext()) {
       if (c instanceof NamedAnchor) {
         return (NamedAnchor) c;
@@ -202,7 +203,7 @@
       } else {
         int i = 1;
         for (TocEntry entry : headers) {
-          ids.put(entry.header, entry.id + "-" + (i++));
+          ids.put(entry.header, entry.id + "-" + i++);
         }
       }
     }
diff --git a/java/com/google/gitiles/doc/html/HtmlBuilder.java b/java/com/google/gitiles/doc/html/HtmlBuilder.java
index 59604c2..4caf519 100644
--- a/java/com/google/gitiles/doc/html/HtmlBuilder.java
+++ b/java/com/google/gitiles/doc/html/HtmlBuilder.java
@@ -251,7 +251,7 @@
 
   private static final Pattern HTML_ENTITY = Pattern.compile("&[a-z]+;");
 
-  /** Append constant entity reference like {@code &nbsp;}. */
+  /** Append constant entity reference like <code>&amp;nbsp&#59;</code>. */
   public void entity(String entity) {
     checkArgument(HTML_ENTITY.matcher(entity).matches(), "invalid entity %s", entity);
     finishActiveTag();
diff --git a/javatests/com/google/gitiles/BUILD b/javatests/com/google/gitiles/BUILD
index 8e90e16..cf5572f 100644
--- a/javatests/com/google/gitiles/BUILD
+++ b/javatests/com/google/gitiles/BUILD
@@ -7,7 +7,8 @@
     "//lib:guava-failureaccess",
     "//lib:jgit",
     "//lib:jgit-servlet",
-    "//lib/soy:soy",
+    "//lib/flogger",
+    "//lib/soy",
 ]
 
 java_library(
diff --git a/javatests/com/google/gitiles/DiffServletTest.java b/javatests/com/google/gitiles/DiffServletTest.java
index 7a2d201..529c349 100644
--- a/javatests/com/google/gitiles/DiffServletTest.java
+++ b/javatests/com/google/gitiles/DiffServletTest.java
@@ -24,7 +24,6 @@
 import org.eclipse.jgit.diff.DiffEntry.ChangeType;
 import org.eclipse.jgit.diff.DiffEntry.Side;
 import org.eclipse.jgit.diff.Edit;
-import org.eclipse.jgit.diff.Edit.Type;
 import org.eclipse.jgit.diff.RawText;
 import org.eclipse.jgit.patch.FileHeader;
 import org.eclipse.jgit.patch.Patch;
@@ -66,7 +65,7 @@
 
     RawText rt = new RawText(contents.getBytes(UTF_8));
     Edit e = getOnlyElement(getOnlyElement(f.getHunks()).toEditList());
-    assertThat(e.getType()).isEqualTo(Type.INSERT);
+    assertThat(e.getType()).isEqualTo(Edit.Type.INSERT);
     assertThat(rt.getString(e.getBeginB(), e.getEndB(), false)).isEqualTo(contents);
   }
 
@@ -87,7 +86,7 @@
 
     RawText rt2 = new RawText(contents2.getBytes(UTF_8));
     Edit e = getOnlyElement(getOnlyElement(f.getHunks()).toEditList());
-    assertThat(e.getType()).isEqualTo(Type.INSERT);
+    assertThat(e.getType()).isEqualTo(Edit.Type.INSERT);
     assertThat(rt2.getString(e.getBeginB(), e.getEndB(), false)).isEqualTo("contents\n");
   }
 
diff --git a/javatests/com/google/gitiles/GitilesViewTest.java b/javatests/com/google/gitiles/GitilesViewTest.java
index 7cce3ef..275e982 100644
--- a/javatests/com/google/gitiles/GitilesViewTest.java
+++ b/javatests/com/google/gitiles/GitilesViewTest.java
@@ -19,7 +19,6 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableListMultimap;
 import com.google.common.collect.ImmutableMap;
-import com.google.gitiles.GitilesView.Type;
 import org.eclipse.jgit.lib.ObjectId;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -35,7 +34,7 @@
   public void emptyServletPath() throws Exception {
     GitilesView view = GitilesView.hostIndex().setServletPath("").setHostName("host").build();
     assertThat(view.getServletPath()).isEqualTo("");
-    assertThat(view.getType()).isEqualTo(Type.HOST_INDEX);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.HOST_INDEX);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isNull();
     assertThat(view.getRevision()).isEqualTo(Revision.NULL);
@@ -49,7 +48,7 @@
   @Test
   public void hostIndex() throws Exception {
     assertThat(HOST.getServletPath()).isEqualTo("/b");
-    assertThat(HOST.getType()).isEqualTo(Type.HOST_INDEX);
+    assertThat(HOST.getType()).isEqualTo(GitilesView.Type.HOST_INDEX);
     assertThat(HOST.getHostName()).isEqualTo("host");
     assertThat(HOST.getRepositoryName()).isNull();
     assertThat(HOST.getRevision()).isEqualTo(Revision.NULL);
@@ -96,7 +95,7 @@
             .build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.LOG);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.LOG);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("repo");
     assertThat(view.getRevision()).isEqualTo(Revision.named("master"));
@@ -137,7 +136,7 @@
         GitilesView.repositoryIndex().copyFrom(HOST).setRepositoryName("foo/bar").build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.REPOSITORY_INDEX);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.REPOSITORY_INDEX);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision()).isEqualTo(Revision.NULL);
@@ -158,7 +157,7 @@
     GitilesView view = GitilesView.refs().copyFrom(HOST).setRepositoryName("foo/bar").build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.REFS);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.REFS);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision()).isEqualTo(Revision.NULL);
@@ -185,7 +184,7 @@
             .build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.REVISION);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.REVISION);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision().getId()).isEqualTo(id);
@@ -213,7 +212,7 @@
             .build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.DESCRIBE);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DESCRIBE);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision()).isEqualTo(Revision.NULL);
@@ -233,7 +232,7 @@
             .build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.PATH);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.PATH);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision().getId()).isEqualTo(id);
@@ -264,7 +263,7 @@
             .build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.PATH);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.PATH);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision().getId()).isEqualTo(id);
@@ -296,7 +295,7 @@
             .build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.DOC);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DOC);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision().getId()).isEqualTo(id);
@@ -318,7 +317,7 @@
             .build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.DOC);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DOC);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision().getId()).isEqualTo(id);
@@ -340,7 +339,7 @@
             .build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.SHOW);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.SHOW);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision().getId()).isEqualTo(id);
@@ -361,7 +360,7 @@
             .build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.ROOTED_DOC);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.ROOTED_DOC);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRevision().getId()).isEqualTo(id);
     assertThat(view.getRevision().getName()).isEqualTo("master");
@@ -382,7 +381,7 @@
             .build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.PATH);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.PATH);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision().getId()).isEqualTo(id);
@@ -419,7 +418,7 @@
             .build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.DIFF);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DIFF);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision().getId()).isEqualTo(id);
@@ -455,7 +454,7 @@
             .build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.DIFF);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DIFF);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision().getId()).isEqualTo(id);
@@ -493,7 +492,7 @@
             .build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.DIFF);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DIFF);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision().getId()).isEqualTo(id);
@@ -528,7 +527,7 @@
             .build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.LOG);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.LOG);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision().getId()).isEqualTo(id);
@@ -558,7 +557,7 @@
             .build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.LOG);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.LOG);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision().getId()).isEqualTo(id);
@@ -589,7 +588,7 @@
             .build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.LOG);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.LOG);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision().getId()).isEqualTo(id);
@@ -626,7 +625,7 @@
             .build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.LOG);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.LOG);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision().getId()).isEqualTo(id);
@@ -654,7 +653,7 @@
     GitilesView view = GitilesView.log().copyFrom(HOST).setRepositoryName("foo/bar").build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.LOG);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.LOG);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision()).isEqualTo(Revision.NULL);
@@ -683,7 +682,7 @@
             .build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.ARCHIVE);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.ARCHIVE);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision().getId()).isEqualTo(id);
@@ -707,7 +706,7 @@
             .build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.ARCHIVE);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.ARCHIVE);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision().getId()).isEqualTo(id);
@@ -730,7 +729,7 @@
             .build();
 
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.BLAME);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.BLAME);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo/bar");
     assertThat(view.getRevision().getId()).isEqualTo(id);
@@ -769,7 +768,7 @@
 
     // Fields returned by getters are not escaped.
     assertThat(view.getServletPath()).isEqualTo("/b");
-    assertThat(view.getType()).isEqualTo(Type.LOG);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.LOG);
     assertThat(view.getHostName()).isEqualTo("host");
     assertThat(view.getRepositoryName()).isEqualTo("foo?bar");
     assertThat(view.getRevision().getId()).isEqualTo(id);
diff --git a/javatests/com/google/gitiles/LinkifierTest.java b/javatests/com/google/gitiles/LinkifierTest.java
index baa9727..bcd82a4 100644
--- a/javatests/com/google/gitiles/LinkifierTest.java
+++ b/javatests/com/google/gitiles/LinkifierTest.java
@@ -17,6 +17,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.collect.ImmutableMap;
+import javax.annotation.Nullable;
 import javax.servlet.http.HttpServletRequest;
 import org.eclipse.jgit.lib.Config;
 import org.junit.Test;
@@ -68,6 +69,7 @@
     Linkifier l =
         new Linkifier(
             new GitilesUrls() {
+              @Nullable
               @Override
               public String getBaseGerritUrl(HttpServletRequest req) {
                 return null;
diff --git a/javatests/com/google/gitiles/PathServletTest.java b/javatests/com/google/gitiles/PathServletTest.java
index ad9d43e..5002948 100644
--- a/javatests/com/google/gitiles/PathServletTest.java
+++ b/javatests/com/google/gitiles/PathServletTest.java
@@ -38,7 +38,7 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-/** Tests for {@PathServlet}. */
+/** Tests for {@link PathServlet}. */
 @SuppressWarnings("unchecked")
 @RunWith(JUnit4.class)
 public class PathServletTest extends ServletTest {
diff --git a/javatests/com/google/gitiles/TestGitilesServlet.java b/javatests/com/google/gitiles/TestGitilesServlet.java
index 036707c..b68ea87 100644
--- a/javatests/com/google/gitiles/TestGitilesServlet.java
+++ b/javatests/com/google/gitiles/TestGitilesServlet.java
@@ -18,6 +18,7 @@
 import java.net.URL;
 import java.util.Collections;
 import java.util.Enumeration;
+import javax.annotation.Nullable;
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
@@ -31,13 +32,13 @@
 
 /** Static utility methods for creating {@link GitilesServlet}s for testing. */
 public class TestGitilesServlet {
-  /** @see #create(TestRepository,GitwebRedirectFilter, BranchRedirect) */
+  /** Create GitilesServlet, @see #create(TestRepository,GitwebRedirectFilter, BranchRedirect) */
   public static GitilesServlet create(final TestRepository<DfsRepository> repo)
       throws ServletException {
     return create(repo, new GitwebRedirectFilter(), new BranchRedirect());
   }
 
-  /** @see #create(TestRepository,GitwebRedirectFilter, BranchRedirect) */
+  /** Create GitilesServlet, @see #create(TestRepository,GitwebRedirectFilter, BranchRedirect) */
   public static GitilesServlet create(
       final TestRepository<DfsRepository> repo, GitwebRedirectFilter gitwebRedirect)
       throws ServletException {
@@ -90,7 +91,7 @@
     servlet.init(
         new ServletConfig() {
           @Override
-          public String getInitParameter(String name) {
+          public @Nullable String getInitParameter(String name) {
             return null;
           }
 
@@ -100,7 +101,7 @@
           }
 
           @Override
-          public ServletContext getServletContext() {
+          public @Nullable ServletContext getServletContext() {
             return null;
           }
 
diff --git a/javatests/com/google/gitiles/TimeCacheTest.java b/javatests/com/google/gitiles/TimeCacheTest.java
index 8fe900a..2540c56 100644
--- a/javatests/com/google/gitiles/TimeCacheTest.java
+++ b/javatests/com/google/gitiles/TimeCacheTest.java
@@ -53,7 +53,7 @@
     repo = new TestRepository<>(new InMemoryRepository(new DfsRepositoryDescription("test")));
     walk = new RevWalk(repo.getRepository());
     cache = new TimeCache();
-    start = repo.getDate().getTime() / 1000;
+    start = repo.getInstant().toEpochMilli() / 1000;
   }
 
   private long getTime(ObjectId id) throws IOException {
diff --git a/javatests/com/google/gitiles/ViewFilterTest.java b/javatests/com/google/gitiles/ViewFilterTest.java
index fb001cd..79b0b09 100644
--- a/javatests/com/google/gitiles/ViewFilterTest.java
+++ b/javatests/com/google/gitiles/ViewFilterTest.java
@@ -19,7 +19,6 @@
 import static com.google.gitiles.MoreAssert.assertThrows;
 
 import com.google.common.net.HttpHeaders;
-import com.google.gitiles.GitilesView.Type;
 import java.io.IOException;
 import java.util.Optional;
 import javax.servlet.ServletException;
@@ -47,8 +46,8 @@
 
   @Test
   public void noCommand() throws Exception {
-    assertThat(getView("/").getType()).isEqualTo(Type.HOST_INDEX);
-    assertThat(getView("/repo").getType()).isEqualTo(Type.REPOSITORY_INDEX);
+    assertThat(getView("/").getType()).isEqualTo(GitilesView.Type.HOST_INDEX);
+    assertThat(getView("/repo").getType()).isEqualTo(GitilesView.Type.REPOSITORY_INDEX);
     assertThrows(GitilesRequestFailureException.class, () -> getView("/repo/+"));
     assertThrows(GitilesRequestFailureException.class, () -> getView("/repo/+/"));
   }
@@ -61,24 +60,25 @@
     String hexBranch = hex.substring(0, 10);
     repo.branch(hexBranch).commit().create();
 
-    assertThat(getView("/repo/+/master").getType()).isEqualTo(Type.REVISION);
-    assertThat(getView("/repo/+/" + hexBranch).getType()).isEqualTo(Type.REVISION);
-    assertThat(getView("/repo/+/" + hex).getType()).isEqualTo(Type.REVISION);
-    assertThat(getView("/repo/+/" + hex.substring(0, 7)).getType()).isEqualTo(Type.REVISION);
-    assertThat(getView("/repo/+/master/").getType()).isEqualTo(Type.PATH);
-    assertThat(getView("/repo/+/" + hex + "/").getType()).isEqualTo(Type.PATH);
-    assertThat(getView("/repo/+/" + hex + "/index.c").getType()).isEqualTo(Type.PATH);
-    assertThat(getView("/repo/+/" + hex + "/index.md").getType()).isEqualTo(Type.DOC);
-    assertThat(getView("/repo/+/master^..master").getType()).isEqualTo(Type.DIFF);
-    assertThat(getView("/repo/+/master^..master/").getType()).isEqualTo(Type.DIFF);
+    assertThat(getView("/repo/+/master").getType()).isEqualTo(GitilesView.Type.REVISION);
+    assertThat(getView("/repo/+/" + hexBranch).getType()).isEqualTo(GitilesView.Type.REVISION);
+    assertThat(getView("/repo/+/" + hex).getType()).isEqualTo(GitilesView.Type.REVISION);
+    assertThat(getView("/repo/+/" + hex.substring(0, 7)).getType())
+        .isEqualTo(GitilesView.Type.REVISION);
+    assertThat(getView("/repo/+/master/").getType()).isEqualTo(GitilesView.Type.PATH);
+    assertThat(getView("/repo/+/" + hex + "/").getType()).isEqualTo(GitilesView.Type.PATH);
+    assertThat(getView("/repo/+/" + hex + "/index.c").getType()).isEqualTo(GitilesView.Type.PATH);
+    assertThat(getView("/repo/+/" + hex + "/index.md").getType()).isEqualTo(GitilesView.Type.DOC);
+    assertThat(getView("/repo/+/master^..master").getType()).isEqualTo(GitilesView.Type.DIFF);
+    assertThat(getView("/repo/+/master^..master/").getType()).isEqualTo(GitilesView.Type.DIFF);
     assertThat(getView("/repo/+/" + parent.name() + ".." + hex + "/").getType())
-        .isEqualTo(Type.DIFF);
+        .isEqualTo(GitilesView.Type.DIFF);
   }
 
   @Test
   public void hostIndex() throws Exception {
     GitilesView view = getView("/");
-    assertThat(view.getType()).isEqualTo(Type.HOST_INDEX);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.HOST_INDEX);
     assertThat(view.getHostName()).isEqualTo("test-host");
     assertThat(view.getRepositoryName()).isNull();
     assertThat(view.getRevision()).isEqualTo(Revision.NULL);
@@ -89,7 +89,7 @@
   @Test
   public void repositoryIndex() throws Exception {
     GitilesView view = getView("/repo");
-    assertThat(view.getType()).isEqualTo(Type.REPOSITORY_INDEX);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.REPOSITORY_INDEX);
     assertThat(view.getRepositoryName()).isEqualTo("repo");
     assertThat(view.getRevision()).isEqualTo(Revision.NULL);
     assertThat(view.getOldRevision()).isEqualTo(Revision.NULL);
@@ -101,35 +101,35 @@
     GitilesView view;
 
     view = getView("/repo/+refs");
-    assertThat(view.getType()).isEqualTo(Type.REFS);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.REFS);
     assertThat(view.getRepositoryName()).isEqualTo("repo");
     assertThat(view.getRevision()).isEqualTo(Revision.NULL);
     assertThat(view.getOldRevision()).isEqualTo(Revision.NULL);
     assertThat(view.getPathPart()).isEqualTo("");
 
     view = getView("/repo/+refs/");
-    assertThat(view.getType()).isEqualTo(Type.REFS);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.REFS);
     assertThat(view.getRepositoryName()).isEqualTo("repo");
     assertThat(view.getRevision()).isEqualTo(Revision.NULL);
     assertThat(view.getOldRevision()).isEqualTo(Revision.NULL);
     assertThat(view.getPathPart()).isEqualTo("");
 
     view = getView("/repo/+refs/heads");
-    assertThat(view.getType()).isEqualTo(Type.REFS);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.REFS);
     assertThat(view.getRepositoryName()).isEqualTo("repo");
     assertThat(view.getRevision()).isEqualTo(Revision.NULL);
     assertThat(view.getOldRevision()).isEqualTo(Revision.NULL);
     assertThat(view.getPathPart()).isEqualTo("heads");
 
     view = getView("/repo/+refs/heads/");
-    assertThat(view.getType()).isEqualTo(Type.REFS);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.REFS);
     assertThat(view.getRepositoryName()).isEqualTo("repo");
     assertThat(view.getRevision()).isEqualTo(Revision.NULL);
     assertThat(view.getOldRevision()).isEqualTo(Revision.NULL);
     assertThat(view.getPathPart()).isEqualTo("heads");
 
     view = getView("/repo/+refs/heads/master");
-    assertThat(view.getType()).isEqualTo(Type.REFS);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.REFS);
     assertThat(view.getRepositoryName()).isEqualTo("repo");
     assertThat(view.getRevision()).isEqualTo(Revision.NULL);
     assertThat(view.getOldRevision()).isEqualTo(Revision.NULL);
@@ -144,14 +144,14 @@
     assertThrows(GitilesRequestFailureException.class, () -> getView("/repo/+describe/"));
 
     view = getView("/repo/+describe/deadbeef");
-    assertThat(view.getType()).isEqualTo(Type.DESCRIBE);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DESCRIBE);
     assertThat(view.getRepositoryName()).isEqualTo("repo");
     assertThat(view.getRevision()).isEqualTo(Revision.NULL);
     assertThat(view.getOldRevision()).isEqualTo(Revision.NULL);
     assertThat(view.getPathPart()).isEqualTo("deadbeef");
 
     view = getView("/repo/+describe/refs/heads/master~3^~2");
-    assertThat(view.getType()).isEqualTo(Type.DESCRIBE);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DESCRIBE);
     assertThat(view.getRepositoryName()).isEqualTo("repo");
     assertThat(view.getRevision()).isEqualTo(Revision.NULL);
     assertThat(view.getOldRevision()).isEqualTo(Revision.NULL);
@@ -165,25 +165,25 @@
     GitilesView view;
 
     view = getView("/repo/+show/master");
-    assertThat(view.getType()).isEqualTo(Type.REVISION);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.REVISION);
     assertThat(view.getRevision().getName()).isEqualTo("master");
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getPathPart()).isNull();
 
     view = getView("/repo/+show/heads/master");
-    assertThat(view.getType()).isEqualTo(Type.REVISION);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.REVISION);
     assertThat(view.getRevision().getName()).isEqualTo("heads/master");
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getPathPart()).isNull();
 
     view = getView("/repo/+show/refs/heads/master");
-    assertThat(view.getType()).isEqualTo(Type.REVISION);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.REVISION);
     assertThat(view.getRevision().getName()).isEqualTo(MASTER);
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getPathPart()).isNull();
 
     view = getView("/repo/+show/stable");
-    assertThat(view.getType()).isEqualTo(Type.REVISION);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.REVISION);
     assertThat(view.getRevision().getName()).isEqualTo("stable");
     assertThat(view.getRevision().getId()).isEqualTo(stable);
     assertThat(view.getPathPart()).isNull();
@@ -198,31 +198,31 @@
     GitilesView view;
 
     view = getView("/repo/+show/name");
-    assertThat(view.getType()).isEqualTo(Type.REVISION);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.REVISION);
     assertThat(view.getRevision().getName()).isEqualTo("name");
     assertThat(view.getRevision().getId()).isEqualTo(tag);
     assertThat(view.getPathPart()).isNull();
 
     view = getView("/repo/+show/heads/name");
-    assertThat(view.getType()).isEqualTo(Type.REVISION);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.REVISION);
     assertThat(view.getRevision().getName()).isEqualTo("heads/name");
     assertThat(view.getRevision().getId()).isEqualTo(branch);
     assertThat(view.getPathPart()).isNull();
 
     view = getView("/repo/+show/refs/heads/name");
-    assertThat(view.getType()).isEqualTo(Type.REVISION);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.REVISION);
     assertThat(view.getRevision().getName()).isEqualTo("refs/heads/name");
     assertThat(view.getRevision().getId()).isEqualTo(branch);
     assertThat(view.getPathPart()).isNull();
 
     view = getView("/repo/+show/tags/name");
-    assertThat(view.getType()).isEqualTo(Type.REVISION);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.REVISION);
     assertThat(view.getRevision().getName()).isEqualTo("tags/name");
     assertThat(view.getRevision().getId()).isEqualTo(tag);
     assertThat(view.getPathPart()).isNull();
 
     view = getView("/repo/+show/refs/tags/name");
-    assertThat(view.getType()).isEqualTo(Type.REVISION);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.REVISION);
     assertThat(view.getRevision().getName()).isEqualTo("refs/tags/name");
     assertThat(view.getRevision().getId()).isEqualTo(tag);
     assertThat(view.getPathPart()).isNull();
@@ -235,22 +235,22 @@
     GitilesView view;
 
     view = getView("/repo/+show/master/");
-    assertThat(view.getType()).isEqualTo(Type.PATH);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.PATH);
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getPathPart()).isEqualTo("");
 
     view = getView("/repo/+show/master/foo");
-    assertThat(view.getType()).isEqualTo(Type.PATH);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.PATH);
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getPathPart()).isEqualTo("foo");
 
     view = getView("/repo/+show/master/foo/");
-    assertThat(view.getType()).isEqualTo(Type.PATH);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.PATH);
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getPathPart()).isEqualTo("foo");
 
     view = getView("/repo/+show/master/foo/bar");
-    assertThat(view.getType()).isEqualTo(Type.PATH);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.PATH);
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getPathPart()).isEqualTo("foo/bar");
 
@@ -265,22 +265,22 @@
     GitilesView view;
 
     view = getView("/repo/+doc/master/");
-    assertThat(view.getType()).isEqualTo(Type.DOC);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DOC);
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getPathPart()).isEqualTo("");
 
     view = getView("/repo/+doc/master/index.md");
-    assertThat(view.getType()).isEqualTo(Type.DOC);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DOC);
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getPathPart()).isEqualTo("index.md");
 
     view = getView("/repo/+doc/master/foo/");
-    assertThat(view.getType()).isEqualTo(Type.DOC);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DOC);
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getPathPart()).isEqualTo("foo");
 
     view = getView("/repo/+doc/master/foo/bar.md");
-    assertThat(view.getType()).isEqualTo(Type.DOC);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DOC);
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getPathPart()).isEqualTo("foo/bar.md");
 
@@ -291,9 +291,9 @@
   @Test
   public void multipleSlashes() throws Exception {
     repo.branch(MASTER).commit().create();
-    assertThat(getView("//").getType()).isEqualTo(Type.HOST_INDEX);
-    assertThat(getView("//repo").getType()).isEqualTo(Type.REPOSITORY_INDEX);
-    assertThat(getView("//repo//").getType()).isEqualTo(Type.REPOSITORY_INDEX);
+    assertThat(getView("//").getType()).isEqualTo(GitilesView.Type.HOST_INDEX);
+    assertThat(getView("//repo").getType()).isEqualTo(GitilesView.Type.REPOSITORY_INDEX);
+    assertThat(getView("//repo//").getType()).isEqualTo(GitilesView.Type.REPOSITORY_INDEX);
     assertThrows(GitilesRequestFailureException.class, () -> getView("/repo/+//master"));
     assertThrows(
         GitilesRequestFailureException.class, () -> getView("/repo/+/refs//heads//master"));
@@ -308,7 +308,7 @@
     GitilesView view;
 
     view = getView("/repo/+diff/master^..master");
-    assertThat(view.getType()).isEqualTo(Type.DIFF);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DIFF);
     assertThat(view.getRevision().getName()).isEqualTo("master");
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getOldRevision().getName()).isEqualTo("master^");
@@ -316,7 +316,7 @@
     assertThat(view.getPathPart()).isEqualTo("");
 
     view = getView("/repo/+diff/master^..master/");
-    assertThat(view.getType()).isEqualTo(Type.DIFF);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DIFF);
     assertThat(view.getRevision().getName()).isEqualTo("master");
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getOldRevision().getName()).isEqualTo("master^");
@@ -324,7 +324,7 @@
     assertThat(view.getPathPart()).isEqualTo("");
 
     view = getView("/repo/+diff/master^..master/foo");
-    assertThat(view.getType()).isEqualTo(Type.DIFF);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DIFF);
     assertThat(view.getRevision().getName()).isEqualTo("master");
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getOldRevision().getName()).isEqualTo("master^");
@@ -332,7 +332,7 @@
     assertThat(view.getPathPart()).isEqualTo("foo");
 
     view = getView("/repo/+diff/refs/heads/master^..refs/heads/master");
-    assertThat(view.getType()).isEqualTo(Type.DIFF);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DIFF);
     assertThat(view.getRevision().getName()).isEqualTo(MASTER);
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getOldRevision().getName()).isEqualTo("refs/heads/master^");
@@ -344,7 +344,7 @@
   public void diffAgainstEmptyCommit() throws Exception {
     RevCommit master = repo.branch(MASTER).commit().create();
     GitilesView view = getView("/repo/+diff/master^!");
-    assertThat(view.getType()).isEqualTo(Type.DIFF);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DIFF);
     assertThat(view.getRevision().getName()).isEqualTo("master");
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getOldRevision()).isEqualTo(Revision.NULL);
@@ -358,38 +358,38 @@
     GitilesView view;
 
     view = getView("/repo/+log");
-    assertThat(view.getType()).isEqualTo(Type.LOG);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.LOG);
     assertThat(view.getRevision()).isEqualTo(Revision.NULL);
     assertThat(view.getPathPart()).isNull();
 
     view = getView("/repo/+log/");
-    assertThat(view.getType()).isEqualTo(Type.LOG);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.LOG);
     assertThat(view.getRevision()).isEqualTo(Revision.NULL);
     assertThat(view.getPathPart()).isNull();
 
     view = getView("/repo/+log/master");
-    assertThat(view.getType()).isEqualTo(Type.LOG);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.LOG);
     assertThat(view.getRevision().getName()).isEqualTo("master");
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getOldRevision()).isEqualTo(Revision.NULL);
     assertThat(view.getPathPart()).isEqualTo("");
 
     view = getView("/repo/+log/master/");
-    assertThat(view.getType()).isEqualTo(Type.LOG);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.LOG);
     assertThat(view.getRevision().getName()).isEqualTo("master");
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getOldRevision()).isEqualTo(Revision.NULL);
     assertThat(view.getPathPart()).isEqualTo("");
 
     view = getView("/repo/+log/master/foo");
-    assertThat(view.getType()).isEqualTo(Type.LOG);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.LOG);
     assertThat(view.getRevision().getName()).isEqualTo("master");
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getOldRevision()).isEqualTo(Revision.NULL);
     assertThat(view.getPathPart()).isEqualTo("foo");
 
     view = getView("/repo/+log/master^..master");
-    assertThat(view.getType()).isEqualTo(Type.LOG);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.LOG);
     assertThat(view.getRevision().getName()).isEqualTo("master");
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getOldRevision().getName()).isEqualTo("master^");
@@ -397,7 +397,7 @@
     assertThat(view.getPathPart()).isEqualTo("");
 
     view = getView("/repo/+log/master^..master/");
-    assertThat(view.getType()).isEqualTo(Type.LOG);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.LOG);
     assertThat(view.getRevision().getName()).isEqualTo("master");
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getOldRevision().getName()).isEqualTo("master^");
@@ -405,7 +405,7 @@
     assertThat(view.getPathPart()).isEqualTo("");
 
     view = getView("/repo/+log/master^..master/foo");
-    assertThat(view.getType()).isEqualTo(Type.LOG);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.LOG);
     assertThat(view.getRevision().getName()).isEqualTo("master");
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getOldRevision().getName()).isEqualTo("master^");
@@ -413,7 +413,7 @@
     assertThat(view.getPathPart()).isEqualTo("foo");
 
     view = getView("/repo/+log/refs/heads/master^..refs/heads/master");
-    assertThat(view.getType()).isEqualTo(Type.LOG);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.LOG);
     assertThat(view.getRevision().getName()).isEqualTo(MASTER);
     assertThat(view.getRevision().getId()).isEqualTo(master);
     assertThat(view.getOldRevision().getName()).isEqualTo("refs/heads/master^");
@@ -439,7 +439,7 @@
         GitilesRequestFailureException.class, () -> getView("/repo/+archive/master/foo/.tar.gz"));
 
     view = getView("/repo/+archive/master.tar.gz");
-    assertThat(view.getType()).isEqualTo(Type.ARCHIVE);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.ARCHIVE);
     assertThat(view.getRepositoryName()).isEqualTo("repo");
     assertThat(view.getRevision().getName()).isEqualTo("master");
     assertThat(view.getRevision().getId()).isEqualTo(master);
@@ -448,7 +448,7 @@
     assertThat(view.getPathPart()).isNull();
 
     view = getView("/repo/+archive/master.tar.bz2");
-    assertThat(view.getType()).isEqualTo(Type.ARCHIVE);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.ARCHIVE);
     assertThat(view.getRepositoryName()).isEqualTo("repo");
     assertThat(view.getRevision().getName()).isEqualTo("master");
     assertThat(view.getRevision().getId()).isEqualTo(master);
@@ -457,7 +457,7 @@
     assertThat(view.getPathPart()).isNull();
 
     view = getView("/repo/+archive/master/foo/bar.tar.gz");
-    assertThat(view.getType()).isEqualTo(Type.ARCHIVE);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.ARCHIVE);
     assertThat(view.getRepositoryName()).isEqualTo("repo");
     assertThat(view.getRevision().getName()).isEqualTo("master");
     assertThat(view.getRevision().getId()).isEqualTo(master);
@@ -479,7 +479,7 @@
         GitilesRequestFailureException.class, () -> getView("/repo/+blame/master..branch"));
 
     view = getView("/repo/+blame/master/foo/bar");
-    assertThat(view.getType()).isEqualTo(Type.BLAME);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.BLAME);
     assertThat(view.getRepositoryName()).isEqualTo("repo");
     assertThat(view.getRevision().getName()).isEqualTo("master");
     assertThat(view.getRevision().getId()).isEqualTo(master);
@@ -542,23 +542,23 @@
         };
 
     GitilesView view = getView("/repo/+/master", branchRedirect);
-    assertThat(view.getType()).isEqualTo(Type.REVISION);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.REVISION);
     assertThat(view.getRevision().getName()).isEqualTo(MAIN);
     assertThat(view.getRevision().getId()).isEqualTo(main);
 
     view = getView("/repo/+/master/index.c", branchRedirect);
-    assertThat(view.getType()).isEqualTo(Type.PATH);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.PATH);
     assertThat(view.getPathPart()).isEqualTo("index.c");
     assertThat(view.getRevision().getName()).isEqualTo(MAIN);
     assertThat(view.getRevision().getId()).isEqualTo(main);
 
     view = getView("/repo/+/some@branch", branchRedirect);
-    assertThat(view.getType()).isEqualTo(Type.REVISION);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.REVISION);
     assertThat(view.getRevision().getName()).isEqualTo(MAIN);
     assertThat(view.getRevision().getId()).isEqualTo(main);
 
     view = getView("/repo/+/master/master", branchRedirect);
-    assertThat(view.getType()).isEqualTo(Type.PATH);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.PATH);
     assertThat(view.getPathPart()).isEqualTo("master");
     assertThat(view.getRevision().getName()).isEqualTo(MAIN);
     assertThat(view.getRevision().getId()).isEqualTo(main);
@@ -602,7 +602,7 @@
     GitilesView view;
 
     view = getView("/repo/+diff/master^..master", branchRedirect);
-    assertThat(view.getType()).isEqualTo(Type.DIFF);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DIFF);
     assertThat(view.getRevision().getName()).isEqualTo(MAIN);
     assertThat(view.getRevision().getId()).isEqualTo(main);
     assertThat(view.getOldRevision().getName()).isEqualTo("refs/heads/main^");
@@ -610,7 +610,7 @@
     assertThat(view.getPathPart()).isEmpty();
 
     view = getView("/repo/+diff/master..master^", branchRedirect);
-    assertThat(view.getType()).isEqualTo(Type.DIFF);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DIFF);
     assertThat(view.getRevision().getName()).isEqualTo("refs/heads/main^");
     assertThat(view.getRevision().getId()).isEqualTo(parent);
     assertThat(view.getOldRevision().getName()).isEqualTo(MAIN);
@@ -618,7 +618,7 @@
     assertThat(view.getPathPart()).isEmpty();
 
     view = getView("/repo/+diff/master^..master/", branchRedirect);
-    assertThat(view.getType()).isEqualTo(Type.DIFF);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DIFF);
     assertThat(view.getRevision().getName()).isEqualTo(MAIN);
     assertThat(view.getRevision().getId()).isEqualTo(main);
     assertThat(view.getOldRevision().getName()).isEqualTo("refs/heads/main^");
@@ -626,7 +626,7 @@
     assertThat(view.getPathPart()).isEmpty();
 
     view = getView("/repo/+diff/master^..master/foo", branchRedirect);
-    assertThat(view.getType()).isEqualTo(Type.DIFF);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DIFF);
     assertThat(view.getRevision().getName()).isEqualTo(MAIN);
     assertThat(view.getRevision().getId()).isEqualTo(main);
     assertThat(view.getOldRevision().getName()).isEqualTo("refs/heads/main^");
@@ -634,7 +634,7 @@
     assertThat(view.getPathPart()).isEqualTo("foo");
 
     view = getView("/repo/+diff/refs/heads/master^..refs/heads/master", branchRedirect);
-    assertThat(view.getType()).isEqualTo(Type.DIFF);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.DIFF);
     assertThat(view.getRevision().getName()).isEqualTo(MAIN);
     assertThat(view.getRevision().getId()).isEqualTo(main);
     assertThat(view.getOldRevision().getName()).isEqualTo("refs/heads/main^");
@@ -663,13 +663,13 @@
 
     view = getView("/repo/+show/master/", branchRedirect);
     assertThat(view.getRevision().getName()).isEqualTo(MAIN);
-    assertThat(view.getType()).isEqualTo(Type.PATH);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.PATH);
     assertThat(view.getRevision().getId()).isEqualTo(main);
     assertThat(view.getPathPart()).isEmpty();
 
     view = getView("/repo/+show/master/foo", branchRedirect);
     assertThat(view.getRevision().getName()).isEqualTo(MAIN);
-    assertThat(view.getType()).isEqualTo(Type.PATH);
+    assertThat(view.getType()).isEqualTo(GitilesView.Type.PATH);
     assertThat(view.getRevision().getId()).isEqualTo(main);
     assertThat(view.getPathPart()).isEqualTo("foo");
   }
diff --git a/lib/BUILD b/lib/BUILD
index 4fec826..c763f24 100644
--- a/lib/BUILD
+++ b/lib/BUILD
@@ -10,6 +10,7 @@
 ) for n in [
     "autolink",
     "commonmark",
+    "commons-codec",
     "commons-lang3",
     "commons-text",
     "cm-autolink",
@@ -29,9 +30,9 @@
 ]]
 
 java_library(
-  name = "prettify",
-  visibility = ["//visibility:public"],
-  exports = ["@java-prettify"],
+    name = "prettify",
+    visibility = ["//visibility:public"],
+    exports = ["@java-prettify"],
 )
 
 java_library(
@@ -88,3 +89,9 @@
     name = "commons-compress",
     exports = ["@commons-compress//jar"],
 )
+
+java_library(
+    name = "errorprone-annotations",
+    visibility = ["//visibility:public"],
+    exports = ["@error-prone-annotations//jar"],
+)
\ No newline at end of file
diff --git a/lib/flogger/BUILD b/lib/flogger/BUILD
new file mode 100644
index 0000000..06fb211
--- /dev/null
+++ b/lib/flogger/BUILD
@@ -0,0 +1,13 @@
+load("@rules_java//java:defs.bzl", "java_library")
+
+java_library(
+    name = "flogger",
+    visibility = ["//visibility:public"],
+    exports = [
+        "@flogger-google-extensions//jar",
+        "@flogger-log4j-backend//jar",
+        "@flogger-system-backend//jar",
+        "@flogger//jar",
+        "@log4j//jar",
+    ],
+)
diff --git a/lib/guice/BUILD b/lib/guice/BUILD
deleted file mode 100644
index 188f2cc..0000000
--- a/lib/guice/BUILD
+++ /dev/null
@@ -1,25 +0,0 @@
-load("@rules_java//java:defs.bzl", "java_library")
-
-package(
-    default_visibility = ["//visibility:public"],
-)
-
-java_library(
-    name = "guice",
-    exports = [
-        ":aopalliance",
-        ":guice-assistedinject",
-        ":guice-library",
-        ":javax-inject",
-    ],
-)
-
-[java_library(
-    name = n,
-    runtime_deps = ["@%s//jar" % n],
-) for n in [
-    "guice-library",
-    "guice-assistedinject",
-    "javax-inject",
-    "aopalliance",
-]]
diff --git a/modules/java-prettify b/modules/java-prettify
index 8af621b..32fa081 160000
--- a/modules/java-prettify
+++ b/modules/java-prettify
@@ -1 +1 @@
-Subproject commit 8af621b7b99641eb803caa460009290a47fa3111
+Subproject commit 32fa081a797a97beaf77a4f2efca26c39168e72f
diff --git a/modules/jgit b/modules/jgit
index ca166a0..dc27dbd 160000
--- a/modules/jgit
+++ b/modules/jgit
@@ -1 +1 @@
-Subproject commit ca166a0c62af2ea87fdedf2728ac19cb59a12601
+Subproject commit dc27dbd2fef79a43f2e44ee1264777da9fbeaabb
diff --git a/tools/BUILD b/tools/BUILD
index 500e197..50c0463 100644
--- a/tools/BUILD
+++ b/tools/BUILD
@@ -34,68 +34,387 @@
     name = "error_prone",
     javacopts = [
         "-XepDisableWarningsInGeneratedCode",
+        "-Xep:AlmostJavadoc:ERROR",
+        "-Xep:AlreadyChecked:ERROR",
+        "-Xep:AlwaysThrows:ERROR",
         "-Xep:AmbiguousMethodReference:ERROR",
+        "-Xep:AnnotateFormatMethod:ERROR",
+        "-Xep:ArgumentSelectionDefectChecker:ERROR",
+        "-Xep:ArrayAsKeyOfSetOrMap:ERROR",
+        "-Xep:ArrayEquals:ERROR",
+        "-Xep:ArrayFillIncompatibleType:ERROR",
+        "-Xep:ArrayHashCode:ERROR",
+        "-Xep:ArraysAsListPrimitiveArray:ERROR",
+        "-Xep:ArrayToString:ERROR",
+        "-Xep:AssertEqualsArgumentOrderChecker:ERROR",
+        "-Xep:AssertionFailureIgnored:ERROR",
+        "-Xep:AsyncCallableReturnsNull:ERROR",
+        "-Xep:AsyncFunctionReturnsNull:ERROR",
+        "-Xep:AutoValueConstructorOrderChecker:ERROR",
+        "-Xep:AutoValueFinalMethods:ERROR",
+        "-Xep:AutoValueImmutableFields:ERROR",
+        "-Xep:AutoValueSubclassLeaked:ERROR",
         "-Xep:BadAnnotationImplementation:ERROR",
         "-Xep:BadComparable:ERROR",
+        "-Xep:BadImport:ERROR",
+        "-Xep:BadInstanceof:ERROR",
+        "-Xep:BadShiftAmount:ERROR",
+        "-Xep:BanJNDI:WARN",
+        "-Xep:BanSerializableRead:ERROR",
+        "-Xep:BigDecimalEquals:ERROR",
+        "-Xep:BigDecimalLiteralDouble:ERROR",
         "-Xep:BoxedPrimitiveConstructor:ERROR",
+        "-Xep:BoxedPrimitiveEquality:ERROR",
+        "-Xep:BundleDeserializationCast:ERROR",
+        "-Xep:ByteBufferBackingArray:ERROR",
+        "-Xep:CacheLoaderNull:ERROR",
         "-Xep:CannotMockFinalClass:ERROR",
+        "-Xep:CanonicalDuration:ERROR",
+        "-Xep:CatchAndPrintStackTrace:ERROR",
+        "-Xep:CatchFail:ERROR",
+        "-Xep:ChainedAssertionLosesContext:ERROR",
+        "-Xep:ChainingConstructorIgnoresParameter:ERROR",
+        "-Xep:CharacterGetNumericValue:ERROR",
+        "-Xep:CheckNotNullMultipleTimes:ERROR",
+        "-Xep:CheckReturnValue:ERROR",
         "-Xep:ClassCanBeStatic:ERROR",
+        "-Xep:ClassName:ERROR",
         "-Xep:ClassNewInstance:ERROR",
+        "-Xep:CollectionIncompatibleType:ERROR",
+        "-Xep:CollectionToArraySafeParameter:ERROR",
+        "-Xep:CollectionUndefinedEquality:ERROR",
+        "-Xep:CollectorShouldNotUseState:ERROR",
+        "-Xep:ComparableAndComparator:ERROR",
+        "-Xep:ComparableType:ERROR",
+        "-Xep:CompareToZero:ERROR",
+        "-Xep:ComparingThisWithNull:ERROR",
+        "-Xep:ComparisonOutOfRange:ERROR",
+        "-Xep:CompatibleWithAnnotationMisuse:ERROR",
+        "-Xep:CompileTimeConstant:ERROR",
+        "-Xep:ComplexBooleanConstant:ERROR",
+        "-Xep:ComputeIfAbsentAmbiguousReference:ERROR",
+        "-Xep:ConditionalExpressionNumericPromotion:ERROR",
+        "-Xep:ConstantOverflow:ERROR",
+        "-Xep:DaggerProvidesNull:ERROR",
+        "-Xep:DangerousLiteralNull:ERROR",
+        "-Xep:DateChecker:ERROR",
         "-Xep:DateFormatConstant:ERROR",
+        "-Xep:DeadException:ERROR",
+        "-Xep:DeadThread:ERROR",
         "-Xep:DefaultCharset:ERROR",
+        "-Xep:DefaultPackage:WARN",
+        "-Xep:DepAnn:ERROR",
+        "-Xep:DeprecatedVariable:ERROR",
+        "-Xep:DiscardedPostfixExpression:ERROR",
+        "-Xep:DoNotCall:ERROR",
+        "-Xep:DoNotCallSuggester:ERROR",
+        "-Xep:DoNotClaimAnnotations:ERROR",
+        "-Xep:DoNotMock:ERROR",
+        "-Xep:DoNotMockAutoValue:ERROR",
+        "-Xep:DoubleBraceInitialization:ERROR",
         "-Xep:DoubleCheckedLocking:ERROR",
-        "-Xep:DoubleCheckedLocking:ERROR",
-        "-Xep:ElementsCountedInLoop:ERROR",
-        "-Xep:ElementsCountedInLoop:ERROR",
+        "-Xep:DuplicateMapKeys:ERROR",
+        "-Xep:DurationFrom:ERROR",
+        "-Xep:DurationGetTemporalUnit:ERROR",
+        "-Xep:DurationTemporalUnit:ERROR",
+        "-Xep:DurationToLongTimeUnit:ERROR",
+        "-Xep:EmptyBlockTag:ERROR",
+        "-Xep:EmptyCatch:ERROR",
+        "-Xep:EmptySetMultibindingContributions:ERROR",
+        "-Xep:EqualsGetClass:ERROR",
         "-Xep:EqualsHashCode:ERROR",
         "-Xep:EqualsIncompatibleType:ERROR",
+        "-Xep:EqualsNaN:ERROR",
+        "-Xep:EqualsNull:ERROR",
+        "-Xep:EqualsReference:ERROR",
+        "-Xep:EqualsUnsafeCast:ERROR",
+        "-Xep:EqualsUsingHashCode:ERROR",
+        "-Xep:EqualsWrongThing:ERROR",
+        "-Xep:ErroneousThreadPoolConstructorChecker:ERROR",
+        "-Xep:EscapedEntity:ERROR",
         "-Xep:ExpectedExceptionChecker:ERROR",
+        "-Xep:ExtendingJUnitAssert:ERROR",
+        "-Xep:ExtendsAutoValue:ERROR",
+        "-Xep:FallThrough:ERROR",
         "-Xep:Finally:ERROR",
+        "-Xep:FloatCast:ERROR",
+        "-Xep:FloatingPointAssertionWithinEpsilon:ERROR",
         "-Xep:FloatingPointLiteralPrecision:ERROR",
+        "-Xep:FloggerArgumentToString:ERROR",
+        "-Xep:FloggerFormatString:ERROR",
+        "-Xep:FloggerLogString:WARN",
+        "-Xep:FloggerLogVarargs:ERROR",
+        "-Xep:FloggerSplitLogStatement:ERROR",
+        "-Xep:FloggerStringConcatenation:ERROR",
+        "-Xep:FormatString:ERROR",
+        "-Xep:FormatStringAnnotation:ERROR",
+        "-Xep:ForOverride:ERROR",
         "-Xep:FragmentInjection:ERROR",
         "-Xep:FragmentNotInstantiable:ERROR",
+        "-Xep:FromTemporalAccessor:ERROR",
         "-Xep:FunctionalInterfaceClash:ERROR",
+        "-Xep:FunctionalInterfaceMethodChanged:ERROR",
         "-Xep:FutureReturnValueIgnored:ERROR",
+        "-Xep:FuturesGetCheckedIllegalExceptionType:ERROR",
+        "-Xep:GetClassOnAnnotation:ERROR",
+        "-Xep:GetClassOnClass:ERROR",
         "-Xep:GetClassOnEnum:ERROR",
+        "-Xep:GuardedBy:ERROR",
+        "-Xep:GuiceAssistedInjectScoping:ERROR",
+        "-Xep:GuiceAssistedParameters:ERROR",
+        "-Xep:HashtableContains:ERROR",
+        "-Xep:HidingField:ERROR",
+        "-Xep:IdentityBinaryExpression:ERROR",
+        "-Xep:IdentityHashMapBoxing:ERROR",
+        "-Xep:IdentityHashMapUsage:ERROR",
+        "-Xep:IgnoredPureGetter:ERROR",
+        "-Xep:Immutable:ERROR",
         "-Xep:ImmutableAnnotationChecker:ERROR",
         "-Xep:ImmutableEnumChecker:WARN",
+        "-Xep:ImmutableModification:ERROR",
+        "-Xep:ImpossibleNullComparison:ERROR",
+        "-Xep:Incomparable:ERROR",
+        "-Xep:IncompatibleArgumentType:ERROR",
         "-Xep:IncompatibleModifiers:ERROR",
+        "-Xep:InconsistentCapitalization:ERROR",
+        "-Xep:InconsistentHashCode:ERROR",
+        "-Xep:IncrementInForLoopAndHeader:ERROR",
+        "-Xep:IndexOfChar:ERROR",
+        "-Xep:InexactVarargsConditional:ERROR",
+        "-Xep:InfiniteRecursion:ERROR",
+        "-Xep:InheritDoc:ERROR",
         "-Xep:InjectOnConstructorOfAbstractClass:ERROR",
+        "-Xep:InlineFormatString:ERROR",
+        "-Xep:InlineMeInliner:WARN",
+        "-Xep:InlineMeSuggester:ERROR",
+        "-Xep:InlineMeValidator:ERROR",
         "-Xep:InputStreamSlowMultibyteRead:ERROR",
+        "-Xep:InsecureCryptoUsage:ERROR",
+        "-Xep:InstanceOfAndCastMatchWrongType:ERROR",
+        "-Xep:InstantTemporalUnit:ERROR",
+        "-Xep:IntLongMath:ERROR",
+        "-Xep:InvalidBlockTag:ERROR",
+        "-Xep:InvalidInlineTag:ERROR",
+        "-Xep:InvalidJavaTimeConstant:ERROR",
+        "-Xep:InvalidLink:ERROR",
+        "-Xep:InvalidParam:ERROR",
+        "-Xep:InvalidPatternSyntax:ERROR",
+        "-Xep:InvalidThrows:ERROR",
+        "-Xep:InvalidThrowsLink:ERROR",
+        "-Xep:InvalidTimeZoneID:ERROR",
+        "-Xep:InvalidZoneId:ERROR",
+        "-Xep:IsInstanceIncompatibleType:ERROR",
+        "-Xep:IsInstanceOfClass:ERROR",
+        "-Xep:IsLoggableTagLength:ERROR",
         "-Xep:IterableAndIterator:ERROR",
+        "-Xep:IterablePathParameter:ERROR",
+        "-Xep:JavaDurationGetSecondsGetNano:ERROR",
+        "-Xep:JavaDurationWithNanos:ERROR",
+        "-Xep:JavaDurationWithSeconds:ERROR",
+        "-Xep:JavaInstantGetSecondsGetNano:ERROR",
+        "-Xep:JavaLangClash:ERROR",
+        "-Xep:JavaLocalDateTimeGetNano:ERROR",
+        "-Xep:JavaLocalTimeGetNano:ERROR",
+        "-Xep:JavaPeriodGetDays:ERROR",
+        "-Xep:JavaTimeDefaultTimeZone:ERROR",
+        "-Xep:JavaUtilDate:ERROR",
+        "-Xep:JdkObsolete:ERROR",
+        "-Xep:JodaConstructors:ERROR",
+        "-Xep:JodaDateTimeConstants:ERROR",
+        "-Xep:JodaDurationWithMillis:ERROR",
+        "-Xep:JodaInstantWithMillis:ERROR",
+        "-Xep:JodaNewPeriod:ERROR",
+        "-Xep:JodaPlusMinusLong:ERROR",
+        "-Xep:JodaTimeConverterManager:ERROR",
+        "-Xep:JodaToSelf:ERROR",
+        "-Xep:JodaWithDurationAddedLong:ERROR",
         "-Xep:JUnit3FloatingPointComparisonWithoutDelta:ERROR",
+        "-Xep:JUnit3TestNotRun:ERROR",
+        "-Xep:JUnit4ClassAnnotationNonStatic:ERROR",
+        "-Xep:JUnit4ClassUsedInJUnit3:ERROR",
+        "-Xep:JUnit4SetUpNotRun:ERROR",
+        "-Xep:JUnit4TearDownNotRun:ERROR",
+        "-Xep:JUnit4TestNotRun:ERROR",
+        "-Xep:JUnit4TestsNotRunWithinEnclosed:ERROR",
         "-Xep:JUnitAmbiguousTestClass:ERROR",
-        "-Xep:LiteralClassName:ERROR",
+        "-Xep:JUnitAssertSameCheck:ERROR",
+        "-Xep:JUnitParameterMethodNotFound:ERROR",
+        "-Xep:LiteByteStringUtf8:ERROR",
+        "-Xep:LiteEnumValueOf:ERROR",
+        "-Xep:LiteProtoToString:ERROR",
+        "-Xep:LocalDateTemporalAmount:ERROR",
+        "-Xep:LockNotBeforeTry:ERROR",
+        "-Xep:LockOnBoxedPrimitive:ERROR",
+        "-Xep:LogicalAssignment:ERROR",
+        "-Xep:LongFloatConversion:ERROR",
+        "-Xep:LongLiteralLowerCaseSuffix:ERROR",
+        "-Xep:LoopConditionChecker:ERROR",
+        "-Xep:LoopOverCharArray:ERROR",
+        "-Xep:LossyPrimitiveCompare:ERROR",
+        "-Xep:MathAbsoluteRandom:ERROR",
+        "-Xep:MathRoundIntLong:ERROR",
+        "-Xep:MemoizeConstantVisitorStateLookups:ERROR",
+        "-Xep:MislabeledAndroidString:ERROR",
         "-Xep:MissingCasesInEnumSwitch:ERROR",
         "-Xep:MissingFail:ERROR",
         "-Xep:MissingOverride:ERROR",
-        "-Xep:MutableConstantField:ERROR",
+        "-Xep:MissingSummary:ERROR",
+        "-Xep:MissingSuperCall:ERROR",
+        "-Xep:MissingTestCall:ERROR",
+        "-Xep:MisusedDayOfYear:ERROR",
+        "-Xep:MisusedWeekYear:ERROR",
+        "-Xep:MixedDescriptors:ERROR",
+        "-Xep:MixedMutabilityReturnType:WARN",
+        "-Xep:MockitoUsage:ERROR",
+        "-Xep:ModifiedButNotUsed:ERROR",
+        "-Xep:ModifyCollectionInEnhancedForLoop:ERROR",
+        "-Xep:ModifyingCollectionWithItself:ERROR",
+        "-Xep:ModifySourceCollectionInStream:ERROR",
+        "-Xep:MultipleParallelOrSequentialCalls:ERROR",
+        "-Xep:MultipleUnaryOperatorsInMethodCall:ERROR",
+        "-Xep:MustBeClosedChecker:ERROR",
+        "-Xep:MutableConstantField:WARN",
+        "-Xep:MutableMethodReturnType:WARN",
+        "-Xep:MutablePublicArray:ERROR",
         "-Xep:NarrowingCompoundAssignment:ERROR",
+        "-Xep:NCopiesOfChar:ERROR",
+        "-Xep:NestedInstanceOfConditions:ERROR",
         "-Xep:NonAtomicVolatileUpdate:ERROR",
+        "-Xep:NonCanonicalStaticImport:ERROR",
+        "-Xep:NonCanonicalType:ERROR",
+        "-Xep:NonFinalCompileTimeConstant:ERROR",
         "-Xep:NonOverridingEquals:ERROR",
+        "-Xep:NonRuntimeAnnotation:ERROR",
         "-Xep:NullableConstructor:ERROR",
         "-Xep:NullablePrimitive:ERROR",
+        "-Xep:NullablePrimitiveArray:ERROR",
         "-Xep:NullableVoid:ERROR",
+        "-Xep:NullOptional:ERROR",
+        "-Xep:NullTernary:ERROR",
+        "-Xep:ObjectEqualsForPrimitives:ERROR",
+        "-Xep:ObjectsHashCodePrimitive:ERROR",
+        "-Xep:ObjectToString:ERROR",
         "-Xep:OperatorPrecedence:ERROR",
+        "-Xep:OptionalEquality:ERROR",
+        "-Xep:OptionalMapToOptional:ERROR",
+        "-Xep:OptionalMapUnusedValue:ERROR",
+        "-Xep:OptionalNotPresent:ERROR",
+        "-Xep:OptionalOfRedundantMethod:ERROR",
+        "-Xep:OrphanedFormatString:ERROR",
+        "-Xep:OutlineNone:ERROR",
+        "-Xep:OverlappingQualifierAndScopeAnnotation:ERROR",
+        "-Xep:Overrides:ERROR",
         "-Xep:OverridesGuiceInjectableMethod:ERROR",
+        "-Xep:OverridesJavaxInjectableMethod:ERROR",
+        "-Xep:OverrideThrowableToString:ERROR",
+        "-Xep:PackageInfo:ERROR",
+        "-Xep:ParameterName:ERROR",
+        "-Xep:ParametersButNotParameterized:ERROR",
+        "-Xep:ParcelableCreator:ERROR",
+        "-Xep:PeriodFrom:ERROR",
+        "-Xep:PeriodGetTemporalUnit:ERROR",
+        "-Xep:PeriodTimeMath:ERROR",
+        "-Xep:PreconditionsCheckNotNullRepeated:ERROR",
         "-Xep:PreconditionsInvalidPlaceholder:ERROR",
-        "-Xep:ProtoFieldPreconditionsCheckNotNull:ERROR",
+        "-Xep:PrimitiveAtomicReference:ERROR",
+        "-Xep:PrivateSecurityContractProtoAccess:ERROR",
+        "-Xep:ProtectedMembersInFinalClass:ERROR",
+        "-Xep:ProtoBuilderReturnValueIgnored:ERROR",
         "-Xep:ProtocolBufferOrdinal:ERROR",
+        "-Xep:ProtoDurationGetSecondsGetNano:ERROR",
+        "-Xep:ProtoFieldNullComparison:ERROR",
+        "-Xep:ProtoRedundantSet:ERROR",
+        "-Xep:ProtoStringFieldReferenceEquality:ERROR",
+        "-Xep:ProtoTimestampGetSecondsGetNano:ERROR",
+        "-Xep:ProtoTruthMixedDescriptors:ERROR",
+        "-Xep:ProvidesMethodOutsideOfModule:WARN",
+        "-Xep:RandomCast:ERROR",
+        "-Xep:RandomModInteger:ERROR",
+        "-Xep:ReachabilityFenceUsage:ERROR",
+        "-Xep:RectIntersectReturnValueIgnored:ERROR",
         "-Xep:ReferenceEquality:ERROR",
+        "-Xep:RefersToDaggerCodegen:ERROR",
+        "-Xep:RemovedInJDK11:ERROR",
         "-Xep:RequiredModifiers:ERROR",
+        "-Xep:RestrictedApiChecker:ERROR",
+        "-Xep:RethrowReflectiveOperationExceptionAsLinkageError:ERROR",
+        "-Xep:ReturnFromVoid:ERROR",
+        "-Xep:ReturnMissingNullable:ERROR",
+        "-Xep:ReturnValueIgnored:ERROR",
+        "-Xep:RxReturnValueIgnored:ERROR",
+        "-Xep:SameNameButDifferent:ERROR",
+        "-Xep:SelfAssignment:ERROR",
+        "-Xep:SelfComparison:ERROR",
+        "-Xep:SelfEquals:ERROR",
         "-Xep:ShortCircuitBoolean:ERROR",
-        "-Xep:SimpleDateFormatConstant:ERROR",
+        "-Xep:ShouldHaveEvenArgs:ERROR",
+        "-Xep:SizeGreaterThanOrEqualsZero:ERROR",
+        "-Xep:StaticAssignmentInConstructor:ERROR",
         "-Xep:StaticGuardedByInstance:ERROR",
+        "-Xep:StaticMockMember:ERROR",
+        "-Xep:StaticQualifiedUsingExpression:ERROR",
+        "-Xep:StreamToString:ERROR",
+        "-Xep:StringBuilderInitWithChar:ERROR",
         "-Xep:StringEquality:ERROR",
+        "-Xep:StringSplitter:ERROR",
+        "-Xep:SubstringOfZero:ERROR",
+        "-Xep:SuppressWarningsDeprecated:ERROR",
+        "-Xep:SwigMemoryLeak:ERROR",
         "-Xep:SynchronizeOnNonFinalField:ERROR",
+        "-Xep:TemporalAccessorGetChronoField:ERROR",
+        "-Xep:TestParametersNotInitialized:ERROR",
+        "-Xep:TheoryButNoTheories:ERROR",
+        "-Xep:ThreadJoinLoop:ERROR",
+        "-Xep:ThreadLocalUsage:ERROR",
+        "-Xep:ThreadPriorityCheck:ERROR",
+        "-Xep:ThreeLetterTimeZoneID:ERROR",
+        "-Xep:ThrowIfUncheckedKnownChecked:ERROR",
+        "-Xep:ThrowNull:ERROR",
+        "-Xep:TimeUnitConversionChecker:ERROR",
+        "-Xep:ToStringReturnsNull:ERROR",
+        "-Xep:TreeToString:ERROR",
+        "-Xep:TruthAssertExpected:ERROR",
         "-Xep:TruthConstantAsserts:ERROR",
+        "-Xep:TruthGetOrDefault:ERROR",
+        "-Xep:TruthIncompatibleType:ERROR",
+        "-Xep:TruthSelfEquals:ERROR",
+        "-Xep:TryFailThrowable:ERROR",
+        "-Xep:TypeEquals:ERROR",
+        "-Xep:TypeNameShadowing:ERROR",
+        "-Xep:TypeParameterQualifier:ERROR",
         "-Xep:TypeParameterShadowing:ERROR",
         "-Xep:TypeParameterUnusedInFormals:ERROR",
-        "-Xep:URLEqualsHashCode:ERROR",
+        "-Xep:UndefinedEquals:ERROR",
+        "-Xep:UnescapedEntity:ERROR",
+        "-Xep:UnnecessaryAssignment:ERROR",
+        "-Xep:UnnecessaryCheckNotNull:ERROR",
+        "-Xep:UnnecessaryLambda:ERROR",
+        "-Xep:UnnecessaryMethodInvocationMatcher:ERROR",
+        "-Xep:UnnecessaryMethodReference:ERROR",
+        "-Xep:UnnecessaryParentheses:ERROR",
+        "-Xep:UnnecessaryTypeArgument:ERROR",
+        "-Xep:UnrecognisedJavadocTag:ERROR",
+        "-Xep:UnsafeFinalization:ERROR",
+        "-Xep:UnsafeReflectiveConstructionCast:ERROR",
         "-Xep:UnsynchronizedOverridesSynchronized:ERROR",
+        "-Xep:UnusedAnonymousClass:ERROR",
+        "-Xep:UnusedCollectionModifiedInPlace:ERROR",
         "-Xep:UnusedException:ERROR",
+        "-Xep:UnusedMethod:ERROR",
+        "-Xep:UnusedNestedClass:ERROR",
+        "-Xep:UnusedVariable:ERROR",
+        "-Xep:URLEqualsHashCode:ERROR",
+        "-Xep:UseBinds:ERROR",
+        "-Xep:UseCorrectAssertInTests:ERROR",
+        "-Xep:VariableNameSameAsType:ERROR",
+        "-Xep:VarTypeName:ERROR",
         "-Xep:WaitNotInLoop:ERROR",
+        "-Xep:WakelockReleasedDangerously:ERROR",
         "-Xep:WildcardImport:ERROR",
+        "-Xep:WithSignatureDiscouraged:ERROR",
+        "-Xep:WrongOneof:ERROR",
+        "-Xep:XorPower:ERROR",
+        "-Xep:ZoneIdOfZ:ERROR",
     ],
     packages = ["error_prone_packages"],
 )
diff --git a/version.bzl b/version.bzl
index e4bdfca..fef692b 100644
--- a/version.bzl
+++ b/version.bzl
@@ -3,4 +3,4 @@
 # Used by :install and :deploy when talking to the destination repository.
 # Project uses semantic versioning described at:
 # https://semver.org
-GITILES_VERSION = "1.2.0"
+GITILES_VERSION = "1.3.0"