diff --git a/build.gradle b/build.gradle
index 4f8f2d56cbd..30b923ca25d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -464,6 +464,10 @@ allprojects {
                 // TODO: Ignore this-escape for now, we may want to review and suppress each one later.
                 lint +=',-this-escape'
             }
+            if (!isJava8 && useJdkCompiler >= 23) {
+                // TODO: Ignore dangling-doc-comments for now, we may want to fix them later.
+                lint +=',-dangling-doc-comments'
+            }
             options.compilerArgs += [
                 '-g',
                 '-Werror',
diff --git a/checker/src/main/java/org/checkerframework/checker/optional/OptionalVisitor.java b/checker/src/main/java/org/checkerframework/checker/optional/OptionalVisitor.java
index eb21564c5f9..c7d922d1741 100644
--- a/checker/src/main/java/org/checkerframework/checker/optional/OptionalVisitor.java
+++ b/checker/src/main/java/org/checkerframework/checker/optional/OptionalVisitor.java
@@ -510,7 +510,7 @@ public Void visitVariable(VariableTree tree, Void p) {
      * {@code x = Optional.of(Optional.of("baz"));}. However, the type of the right-hand side is
      * {@code Optional<? extends Object>}, not {@code Optional<Optional<String>>}. Therefore, to
      * fully check for improper types, it is necessary to examine, in the type checker, the argument
-     * to construction of an Optional. Method {@link handleNestedOptionalCreation} does so.
+     * to construction of an Optional. Method {@link #handleNestedOptionalCreation} does so.
      */
     private final class OptionalTypeValidator extends BaseTypeValidator {
 
diff --git a/dataflow/build.gradle b/dataflow/build.gradle
index c78c1cd2b60..f7dd7424c4b 100644
--- a/dataflow/build.gradle
+++ b/dataflow/build.gradle
@@ -9,6 +9,11 @@ dependencies {
 
     // Node implements org.plumelib.util.UniqueId, so this dependency must be "api".
     api "org.plumelib:plume-util:${versions.plumeUtil}"
+    // plume-util has an `implementation` dependency on hashmap-util.
+    // That follows Gradle's rules, but Gradle's rules are not entirely correct:
+    // https://github.com/gradle/gradle/issues/30054
+    // To build with JDK 22+, we need to redeclare that dependency here.
+    implementation "org.plumelib:hashmap-util:${versions.hashmapUtil}"
 
     // External dependencies:
     // If you add an external dependency, you must shadow its packages both in the dataflow-shaded
diff --git a/javacutil/build.gradle b/javacutil/build.gradle
index 7bc77e7de3b..f4a17396271 100644
--- a/javacutil/build.gradle
+++ b/javacutil/build.gradle
@@ -17,6 +17,11 @@ dependencies {
     // https://mvnrepository.com/artifact/org.plumelib/plume-util
     implementation "org.plumelib:plume-util:${versions.plumeUtil}"
     implementation "org.plumelib:reflection-util:${versions.reflectionUtil}"
+    // plume-util has an `implementation` dependency on hashmap-util.
+    // That follows Gradle's rules, but Gradle's rules are not entirely correct:
+    // https://github.com/gradle/gradle/issues/30054
+    // To build with JDK 22+, we need to redeclare that dependency here.
+    implementation "org.plumelib:hashmap-util:${versions.hashmapUtil}"
 
     // External dependencies:
     // If you add an external dependency, you must shadow its packages both in checker.jar and