diff --git a/core/pom.xml b/core/pom.xml
index 038e4eda6..d1363fed1 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -226,7 +226,7 @@
jdk11
- (,17)
+ [11,17)
@@ -236,6 +236,7 @@
**/Java17InputAstVisitor.java
+ **/Java21InputAstVisitor.java
@@ -243,6 +244,32 @@
maven-javadoc-plugin
com.google.googlejavaformat.java.java17
+ com.google.googlejavaformat.java.java21
+
+
+
+
+
+
+ jdk17
+
+ [17,21)
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ **/Java21InputAstVisitor.java
+
+
+
+
+ maven-javadoc-plugin
+
+ com.google.googlejavaformat.java.java21
diff --git a/core/src/main/java/com/google/googlejavaformat/java/Formatter.java b/core/src/main/java/com/google/googlejavaformat/java/Formatter.java
index 9ff702d5a..5aa7a1233 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/Formatter.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/Formatter.java
@@ -151,16 +151,14 @@ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOExcept
OpsBuilder builder = new OpsBuilder(javaInput, javaOutput);
// Output the compilation unit.
JavaInputAstVisitor visitor;
- if (Runtime.version().feature() >= 17) {
- try {
- visitor =
- Class.forName("com.google.googlejavaformat.java.java17.Java17InputAstVisitor")
- .asSubclass(JavaInputAstVisitor.class)
- .getConstructor(OpsBuilder.class, int.class)
- .newInstance(builder, options.indentationMultiplier());
- } catch (ReflectiveOperationException e) {
- throw new LinkageError(e.getMessage(), e);
- }
+ if (Runtime.version().feature() >= 21) {
+ visitor =
+ createVisitor(
+ "com.google.googlejavaformat.java.java21.Java21InputAstVisitor", builder, options);
+ } else if (Runtime.version().feature() >= 17) {
+ visitor =
+ createVisitor(
+ "com.google.googlejavaformat.java.java17.Java17InputAstVisitor", builder, options);
} else {
visitor = new JavaInputAstVisitor(builder, options.indentationMultiplier());
}
@@ -173,6 +171,18 @@ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOExcept
javaOutput.flush();
}
+ private static JavaInputAstVisitor createVisitor(
+ final String className, final OpsBuilder builder, final JavaFormatterOptions options) {
+ try {
+ return Class.forName(className)
+ .asSubclass(JavaInputAstVisitor.class)
+ .getConstructor(OpsBuilder.class, int.class)
+ .newInstance(builder, options.indentationMultiplier());
+ } catch (ReflectiveOperationException e) {
+ throw new LinkageError(e.getMessage(), e);
+ }
+ }
+
static boolean errorDiagnostic(Diagnostic> input) {
if (input.getKind() != Diagnostic.Kind.ERROR) {
return false;
diff --git a/core/src/main/java/com/google/googlejavaformat/java/java17/Java17InputAstVisitor.java b/core/src/main/java/com/google/googlejavaformat/java/java17/Java17InputAstVisitor.java
index a0561e2fe..97bb2ffe5 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/java17/Java17InputAstVisitor.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/java17/Java17InputAstVisitor.java
@@ -29,6 +29,7 @@
import com.sun.source.tree.CaseTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.InstanceOfTree;
import com.sun.source.tree.ModifiersTree;
import com.sun.source.tree.ModuleTree;
@@ -238,6 +239,15 @@ public Void visitCase(CaseTree node, Void unused) {
}
builder.close();
}
+
+ final ExpressionTree guard = getGuard(node);
+ if (guard != null) {
+ builder.space();
+ token("when");
+ builder.space();
+ scan(guard, null);
+ }
+
switch (node.getCaseKind()) {
case STATEMENT:
token(":");
@@ -267,4 +277,8 @@ public Void visitCase(CaseTree node, Void unused) {
}
return null;
}
+
+ protected ExpressionTree getGuard(final CaseTree node) {
+ return null;
+ }
}
diff --git a/core/src/main/java/com/google/googlejavaformat/java/java21/Java21InputAstVisitor.java b/core/src/main/java/com/google/googlejavaformat/java/java21/Java21InputAstVisitor.java
new file mode 100644
index 000000000..a96ef99e2
--- /dev/null
+++ b/core/src/main/java/com/google/googlejavaformat/java/java21/Java21InputAstVisitor.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2023 The google-java-format Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.googlejavaformat.java.java21;
+
+import com.google.googlejavaformat.OpsBuilder;
+import com.google.googlejavaformat.java.java17.Java17InputAstVisitor;
+import com.sun.source.tree.CaseTree;
+import com.sun.source.tree.ExpressionTree;
+
+/**
+ * Extends {@link Java17InputAstVisitor} with support for AST nodes that were added or modified in
+ * Java 21.
+ */
+public class Java21InputAstVisitor extends Java17InputAstVisitor {
+
+ public Java21InputAstVisitor(OpsBuilder builder, int indentMultiplier) {
+ super(builder, indentMultiplier);
+ }
+
+ @Override
+ protected ExpressionTree getGuard(final CaseTree node) {
+ return node.getGuard();
+ }
+}
diff --git a/core/src/test/java/com/google/googlejavaformat/java/FormatterIntegrationTest.java b/core/src/test/java/com/google/googlejavaformat/java/FormatterIntegrationTest.java
index 61a43468a..688b24d8e 100644
--- a/core/src/test/java/com/google/googlejavaformat/java/FormatterIntegrationTest.java
+++ b/core/src/test/java/com/google/googlejavaformat/java/FormatterIntegrationTest.java
@@ -52,6 +52,7 @@ public class FormatterIntegrationTest {
.putAll(15, "I603")
.putAll(16, "I588")
.putAll(17, "I683", "I684", "I696")
+ .putAll(21, "SwitchGuardClause")
.build();
@Parameters(name = "{index}: {0}")
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchGuardClause.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchGuardClause.input
new file mode 100644
index 000000000..25df58096
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchGuardClause.input
@@ -0,0 +1,9 @@
+class SwitchGuardClause {
+ boolean test(Object x) {
+ return switch (x) {
+ case String s when s.length() < 5 -> true;
+ case Integer i -> false;
+ default -> true;
+ };
+ }
+}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchGuardClause.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchGuardClause.output
new file mode 100644
index 000000000..25df58096
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchGuardClause.output
@@ -0,0 +1,9 @@
+class SwitchGuardClause {
+ boolean test(Object x) {
+ return switch (x) {
+ case String s when s.length() < 5 -> true;
+ case Integer i -> false;
+ default -> true;
+ };
+ }
+}