From 65b5ec2cbf83a2c628f67e1d2a9506409b50cfad Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Wed, 1 Jan 2025 23:34:41 +0100 Subject: [PATCH 1/5] Prefer JDK methods for Maps and Sets of an expected size --- .../guava/NoMapsAndSetsWithExpectedSize.java | 97 +++++++++++++++++++ .../resources/META-INF/rewrite/no-guava.yml | 12 ++- .../NoMapsAndSetsWithExpectedSizeTest.java | 67 +++++++++++++ 3 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSize.java create mode 100644 src/test/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSizeTest.java diff --git a/src/main/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSize.java b/src/main/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSize.java new file mode 100644 index 000000000..bc163bd74 --- /dev/null +++ b/src/main/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSize.java @@ -0,0 +1,97 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Moderne Source Available License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://docs.moderne.io/licensing/moderne-source-available-license + *

+ * 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 org.openrewrite.java.migrate.guava; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Preconditions; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.JavaVisitor; +import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.search.UsesMethod; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaCoordinates; + +public class NoMapsAndSetsWithExpectedSize extends Recipe { + + private static final MethodMatcher NEW_HASHMAP = new MethodMatcher("com.google.common.collect.Maps newHashMapWithExpectedSize(int)", false); + private static final MethodMatcher NEW_LINKED_HASHMAP = new MethodMatcher("com.google.common.collect.Maps newLinkedHashMapWithExpectedSize(int)", false); + private static final MethodMatcher NEW_HASHSET = new MethodMatcher("com.google.common.collect.Sets newHashSetWithExpectedSize(int)", false); + private static final MethodMatcher NEW_LINKED_HASHSET = new MethodMatcher("com.google.common.collect.Sets newLinkedHashSetWithExpectedSize(int)", false); + + @Override + public String getDisplayName() { + return "Prefer JDK methods for Maps and Sets of an expected size"; + } + + @Override + public String getDescription() { + return "Prefer Java 19+ methods to create Maps and Sets of an expected size instead of using Guava methods."; + } + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check( + Preconditions.or( + new UsesMethod<>(NEW_HASHMAP), + new UsesMethod<>(NEW_LINKED_HASHMAP), + new UsesMethod<>(NEW_HASHSET), + new UsesMethod<>(NEW_LINKED_HASHSET) + ), + new JavaVisitor() { + @Override + public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation j = (J.MethodInvocation) super.visitMethodInvocation(method, ctx); + if (NEW_HASHMAP.matches(j)) { + maybeRemoveImport("com.google.common.collect.Maps"); + maybeAddImport("java.util.HashMap"); + JavaCoordinates coordinates = j.getCoordinates().replace(); + return JavaTemplate.builder("new HashMap<>(#{any()})") + .imports("java.util.HashMap") + .build() + .apply(getCursor(), coordinates, j.getArguments().toArray()); + } else if (NEW_LINKED_HASHMAP.matches(j)) { + maybeRemoveImport("com.google.common.collect.Maps"); + maybeAddImport("java.util.LinkedHashMap"); + JavaCoordinates coordinates = j.getCoordinates().replace(); + return JavaTemplate.builder("new LinkedHashMap<>(#{any()})") + .imports("java.util.LinkedHashMap") + .build() + .apply(getCursor(), coordinates, j.getArguments().toArray()); + } else if (NEW_HASHSET.matches(j)) { + maybeRemoveImport("com.google.common.collect.Sets"); + maybeAddImport("java.util.HashSet"); + JavaCoordinates coordinates = j.getCoordinates().replace(); + return JavaTemplate.builder("new HashSet<>(#{any()})") + .imports("java.util.HashSet") + .build() + .apply(getCursor(), coordinates, j.getArguments().toArray()); + } else if (NEW_LINKED_HASHSET.matches(j)) { + maybeRemoveImport("com.google.common.collect.Sets"); + maybeAddImport("java.util.LinkedHashSet"); + JavaCoordinates coordinates = j.getCoordinates().replace(); + return JavaTemplate.builder("new LinkedHashSet<>(#{any()})") + .imports("java.util.LinkedHashSet") + .build() + .apply(getCursor(), coordinates, j.getArguments().toArray()); + } + return j; + } + } + ); + } +} diff --git a/src/main/resources/META-INF/rewrite/no-guava.yml b/src/main/resources/META-INF/rewrite/no-guava.yml index 82f7f90a3..0ef9477b5 100644 --- a/src/main/resources/META-INF/rewrite/no-guava.yml +++ b/src/main/resources/META-INF/rewrite/no-guava.yml @@ -25,6 +25,8 @@ description: >- tags: - guava recipeList: + - org.openrewrite.java.migrate.guava.NoGuavaJava11 + - org.openrewrite.java.migrate.guava.NoGuavaJava21 - org.openrewrite.java.migrate.guava.NoGuavaCreateTempDir - org.openrewrite.java.migrate.guava.NoGuavaDirectExecutor - org.openrewrite.java.migrate.guava.NoGuavaListsNewArrayList @@ -73,8 +75,10 @@ description: >- tags: - guava - java11 +preconditions: + - org.openrewrite.java.search.HasJavaVersion: + version: 11 recipeList: - - org.openrewrite.java.migrate.guava.NoGuava - org.openrewrite.java.migrate.guava.NoGuavaImmutableListOf - org.openrewrite.java.migrate.guava.NoGuavaImmutableMapOf - org.openrewrite.java.migrate.guava.NoGuavaImmutableSetOf @@ -95,9 +99,13 @@ description: >- tags: - guava - java21 +preconditions: + - org.openrewrite.java.search.HasJavaVersion: + version: 21 recipeList: - - org.openrewrite.java.migrate.guava.NoGuavaJava11 + - org.openrewrite.java.migrate.guava.NoMapsAndSetsWithExpectedSize - org.openrewrite.java.migrate.guava.PreferMathClamp + --- type: specs.openrewrite.org/v1beta/recipe name: org.openrewrite.java.migrate.guava.PreferJavaNioCharsetStandardCharsets diff --git a/src/test/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSizeTest.java b/src/test/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSizeTest.java new file mode 100644 index 000000000..af676f66d --- /dev/null +++ b/src/test/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSizeTest.java @@ -0,0 +1,67 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Moderne Source Available License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://docs.moderne.io/licensing/moderne-source-available-license + *

+ * 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 org.openrewrite.java.migrate.guava; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class NoMapsAndSetsWithExpectedSizeTest implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec.recipe(new NoMapsAndSetsWithExpectedSize()); + } + + @DocumentExample + @Test + void noMapSetWithExpectedSize() { + rewriteRun( + //language=java + java( + """ + import com.google.common.collect.Maps; + import com.google.common.collect.Sets; + import java.util.Map; + import java.util.Set; + + class A { + void method() { + Map a = Maps.newHashMapWithExpectedSize(1); + Map b = Maps.newLinkedHashMapWithExpectedSize(1); + Set c = Sets.newHashSetWithExpectedSize(1); + Set d = Sets.newLinkedHashSetWithExpectedSize(1); + } + } + """, + """ + import java.util.*; + + class A { + void method() { + Map a = new HashMap<>(1); + Map b = new LinkedHashMap<>(1); + Set c = new HashSet<>(1); + Set d = new LinkedHashSet<>(1); + } + } + """ + ) + ); + } +} From 74680e112350f75622ae0c34d500c774c6067303 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Wed, 1 Jan 2025 23:49:46 +0100 Subject: [PATCH 2/5] Also include Picnic's `InputStreamRulesRecipes` with `NoGuava` --- build.gradle.kts | 2 ++ src/main/resources/META-INF/rewrite/no-guava.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index af572b74a..367aabb7f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -35,6 +35,8 @@ dependencies { runtimeOnly("org.openrewrite:rewrite-java-17") runtimeOnly("org.openrewrite:rewrite-java-21") + runtimeOnly("tech.picnic.error-prone-support:error-prone-contrib:latest.release:recipes") + testImplementation("org.junit.jupiter:junit-jupiter-api:latest.release") testImplementation("org.junit.jupiter:junit-jupiter-params:latest.release") testImplementation("org.junit-pioneer:junit-pioneer:2.0.0") diff --git a/src/main/resources/META-INF/rewrite/no-guava.yml b/src/main/resources/META-INF/rewrite/no-guava.yml index 0ef9477b5..58601bd70 100644 --- a/src/main/resources/META-INF/rewrite/no-guava.yml +++ b/src/main/resources/META-INF/rewrite/no-guava.yml @@ -64,6 +64,8 @@ recipeList: - org.openrewrite.java.migrate.guava.PreferMathMultiplyExact - org.openrewrite.java.migrate.guava.NoGuavaAtomicsNewReference + - tech.picnic.errorprone.refasterrules.InputStreamRulesRecipes + --- type: specs.openrewrite.org/v1beta/recipe name: org.openrewrite.java.migrate.guava.NoGuavaJava11 From 0e20d0cedf4959f15b5e3cb21a89c2779d3e8966 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Thu, 2 Jan 2025 00:02:15 +0100 Subject: [PATCH 3/5] Rename test and move mismatched test --- ...ectsTest.java => NoGuavaRefasterTest.java} | 29 +------------- .../java/migrate/guava/NoGuavaTest.java | 38 +++++++++++++++---- 2 files changed, 32 insertions(+), 35 deletions(-) rename src/test/java/org/openrewrite/java/migrate/guava/{PreferJavaUtilObjectsTest.java => NoGuavaRefasterTest.java} (85%) diff --git a/src/test/java/org/openrewrite/java/migrate/guava/PreferJavaUtilObjectsTest.java b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaRefasterTest.java similarity index 85% rename from src/test/java/org/openrewrite/java/migrate/guava/PreferJavaUtilObjectsTest.java rename to src/test/java/org/openrewrite/java/migrate/guava/NoGuavaRefasterTest.java index f3df9d5b3..7ebd43113 100644 --- a/src/test/java/org/openrewrite/java/migrate/guava/PreferJavaUtilObjectsTest.java +++ b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaRefasterTest.java @@ -23,7 +23,7 @@ import static org.openrewrite.java.Assertions.java; -class PreferJavaUtilObjectsTest implements RewriteTest { +class NoGuavaRefasterTest implements RewriteTest { @Override public void defaults(RecipeSpec spec) { spec.recipe(new NoGuavaRefasterRecipes()) @@ -184,31 +184,4 @@ Object foo(Object obj) { ) ); } - - @Test - void moreObjectsFirstNonNullToObjectsRequireNonNullElse() { - rewriteRun(spec -> spec.recipeFromResource("/META-INF/rewrite/no-guava.yml", "org.openrewrite.java.migrate.guava.NoGuavaJava11"), - //language=java - java( - """ - import com.google.common.base.MoreObjects; - - class A { - Object foo(Object obj) { - return MoreObjects.firstNonNull(obj, "default"); - } - } - """, - """ - import java.util.Objects; - - class A { - Object foo(Object obj) { - return Objects.requireNonNullElse(obj, "default"); - } - } - """ - ) - ); - } } diff --git a/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaTest.java b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaTest.java index 5701794a8..d49b94f83 100644 --- a/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaTest.java +++ b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaTest.java @@ -17,22 +17,18 @@ import org.junit.jupiter.api.Test; import org.openrewrite.Issue; -import org.openrewrite.config.Environment; import org.openrewrite.java.JavaParser; import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; import static org.openrewrite.java.Assertions.java; +import static org.openrewrite.java.Assertions.javaVersion; class NoGuavaTest implements RewriteTest { @Override public void defaults(RecipeSpec spec) { - spec.recipe( - Environment.builder() - .scanRuntimeClasspath("org.openrewrite.java.migrate.guava") - .build() - .activateRecipes("org.openrewrite.java.migrate.guava.NoGuava") - ) + spec + .recipeFromResource("/META-INF/rewrite/no-guava.yml", "org.openrewrite.java.migrate.guava.NoGuava") .parser(JavaParser.fromJavaVersion().classpath("guava")); } @@ -101,4 +97,32 @@ static boolean isEqual(Object obj0, Object obj1) { ) ); } + + @Test + void moreObjectsFirstNonNullToObjectsRequireNonNullElse() { + rewriteRun( + //language=java + java( + """ + import com.google.common.base.MoreObjects; + + class A { + Object foo(Object obj) { + return MoreObjects.firstNonNull(obj, "default"); + } + } + """, + """ + import java.util.Objects; + + class A { + Object foo(Object obj) { + return Objects.requireNonNullElse(obj, "default"); + } + } + """, + spec -> spec.markers(javaVersion(11)) + ) + ); + } } From 2249e2cd5efc98cc827e70997de8fc1392f179a2 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Thu, 2 Jan 2025 00:09:18 +0100 Subject: [PATCH 4/5] Correctly set minimum Java versions in preconditions --- .../guava/NoMapsAndSetsWithExpectedSize.java | 14 +++-- .../resources/META-INF/rewrite/no-guava.yml | 4 +- .../java/migrate/guava/NoGuavaJava21Test.java | 56 ++++++++----------- .../NoMapsAndSetsWithExpectedSizeTest.java | 4 +- 4 files changed, 38 insertions(+), 40 deletions(-) diff --git a/src/main/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSize.java b/src/main/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSize.java index bc163bd74..76398631d 100644 --- a/src/main/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSize.java +++ b/src/main/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSize.java @@ -22,6 +22,7 @@ import org.openrewrite.java.JavaTemplate; import org.openrewrite.java.JavaVisitor; import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.search.UsesJavaVersion; import org.openrewrite.java.search.UsesMethod; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaCoordinates; @@ -46,11 +47,14 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { return Preconditions.check( - Preconditions.or( - new UsesMethod<>(NEW_HASHMAP), - new UsesMethod<>(NEW_LINKED_HASHMAP), - new UsesMethod<>(NEW_HASHSET), - new UsesMethod<>(NEW_LINKED_HASHSET) + Preconditions.and( + new UsesJavaVersion<>(19), + Preconditions.or( + new UsesMethod<>(NEW_HASHMAP), + new UsesMethod<>(NEW_LINKED_HASHMAP), + new UsesMethod<>(NEW_HASHSET), + new UsesMethod<>(NEW_LINKED_HASHSET) + ) ), new JavaVisitor() { @Override diff --git a/src/main/resources/META-INF/rewrite/no-guava.yml b/src/main/resources/META-INF/rewrite/no-guava.yml index 58601bd70..56e204bf7 100644 --- a/src/main/resources/META-INF/rewrite/no-guava.yml +++ b/src/main/resources/META-INF/rewrite/no-guava.yml @@ -79,7 +79,7 @@ tags: - java11 preconditions: - org.openrewrite.java.search.HasJavaVersion: - version: 11 + version: "[11,)" recipeList: - org.openrewrite.java.migrate.guava.NoGuavaImmutableListOf - org.openrewrite.java.migrate.guava.NoGuavaImmutableMapOf @@ -103,7 +103,7 @@ tags: - java21 preconditions: - org.openrewrite.java.search.HasJavaVersion: - version: 21 + version: "[21,)" recipeList: - org.openrewrite.java.migrate.guava.NoMapsAndSetsWithExpectedSize - org.openrewrite.java.migrate.guava.PreferMathClamp diff --git a/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaJava21Test.java b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaJava21Test.java index f59f1a57d..8eed3f18d 100644 --- a/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaJava21Test.java +++ b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaJava21Test.java @@ -17,23 +17,17 @@ import org.junit.jupiter.api.Test; import org.openrewrite.Issue; -import org.openrewrite.config.Environment; import org.openrewrite.java.JavaParser; import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; -import static org.openrewrite.java.Assertions.java; -import static org.openrewrite.java.Assertions.version; +import static org.openrewrite.java.Assertions.*; class NoGuavaJava21Test implements RewriteTest { @Override public void defaults(RecipeSpec spec) { - spec.recipe( - Environment.builder() - .scanRuntimeClasspath("org.openrewrite.java.migrate.guava") - .build() - .activateRecipes("org.openrewrite.java.migrate.guava.NoGuavaJava21") - ) + spec + .recipeFromResource("/META-INF/rewrite/no-guava.yml", "org.openrewrite.java.migrate.guava.NoGuava") .parser(JavaParser.fromJavaVersion().classpath("guava")); } @@ -122,32 +116,30 @@ public float testMethod() { @Test void noGuavaImmutableOfException() { rewriteRun( - version( - //language=java - java( - """ - import com.google.common.collect.ImmutableSet; - import com.google.common.collect.ImmutableMap; + //language=java + java( + """ + import com.google.common.collect.ImmutableSet; + import com.google.common.collect.ImmutableMap; - class A { - public Object getMap() { - return ImmutableMap.of("key", ImmutableSet.of("value1", "value2")); - } - } - """, - """ - import com.google.common.collect.ImmutableSet; + class A { + public Object getMap() { + return ImmutableMap.of("key", ImmutableSet.of("value1", "value2")); + } + } + """, + """ + import com.google.common.collect.ImmutableSet; - import java.util.Map; + import java.util.Map; - class A { - public Object getMap() { - return Map.of("key", ImmutableSet.of("value1", "value2")); - } - } - """ - ), - 21 + class A { + public Object getMap() { + return Map.of("key", ImmutableSet.of("value1", "value2")); + } + } + """, + spec -> spec.markers(javaVersion(21)) ) ); } diff --git a/src/test/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSizeTest.java b/src/test/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSizeTest.java index af676f66d..aad926d65 100644 --- a/src/test/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSizeTest.java +++ b/src/test/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSizeTest.java @@ -21,6 +21,7 @@ import org.openrewrite.test.RewriteTest; import static org.openrewrite.java.Assertions.java; +import static org.openrewrite.java.Assertions.javaVersion; class NoMapsAndSetsWithExpectedSizeTest implements RewriteTest { @Override @@ -60,7 +61,8 @@ void method() { Set d = new LinkedHashSet<>(1); } } - """ + """, + spec -> spec.markers(javaVersion(21)) ) ); } From bf42f72631ef077fd0937c9a41c4fe9cf0375740 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Thu, 2 Jan 2025 00:12:28 +0100 Subject: [PATCH 5/5] Tag first test as document example --- .../java/migrate/guava/NoGuavaTest.java | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaTest.java b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaTest.java index d49b94f83..f53de64aa 100644 --- a/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaTest.java +++ b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaTest.java @@ -16,6 +16,7 @@ package org.openrewrite.java.migrate.guava; import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; import org.openrewrite.Issue; import org.openrewrite.java.JavaParser; import org.openrewrite.test.RecipeSpec; @@ -32,6 +33,35 @@ public void defaults(RecipeSpec spec) { .parser(JavaParser.fromJavaVersion().classpath("guava")); } + @DocumentExample + @Test + void moreObjectsFirstNonNullToObjectsRequireNonNullElse() { + rewriteRun( + //language=java + java( + """ + import com.google.common.base.MoreObjects; + + class A { + Object foo(Object obj) { + return MoreObjects.firstNonNull(obj, "default"); + } + } + """, + """ + import java.util.Objects; + + class A { + Object foo(Object obj) { + return Objects.requireNonNullElse(obj, "default"); + } + } + """, + spec -> spec.markers(javaVersion(11)) + ) + ); + } + @Test @Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/39#issuecomment-910673213") void preferJavaUtilObjectsHashCode() { @@ -97,32 +127,4 @@ static boolean isEqual(Object obj0, Object obj1) { ) ); } - - @Test - void moreObjectsFirstNonNullToObjectsRequireNonNullElse() { - rewriteRun( - //language=java - java( - """ - import com.google.common.base.MoreObjects; - - class A { - Object foo(Object obj) { - return MoreObjects.firstNonNull(obj, "default"); - } - } - """, - """ - import java.util.Objects; - - class A { - Object foo(Object obj) { - return Objects.requireNonNullElse(obj, "default"); - } - } - """, - spec -> spec.markers(javaVersion(11)) - ) - ); - } }