diff --git a/rewrite-groovy/build.gradle.kts b/rewrite-groovy/build.gradle.kts index c718923f83..1d03b58c62 100644 --- a/rewrite-groovy/build.gradle.kts +++ b/rewrite-groovy/build.gradle.kts @@ -12,18 +12,20 @@ testing { } register("groovy2Test") { - configurations.getByName("groovy2TestRuntimeClasspath") { - resolutionStrategy { - force("org.codehaus.groovy:groovy:2.5.22") - } - } - dependencies { implementation(project()) implementation(project(":rewrite-test")) implementation("org.assertj:assertj-core:latest.release") } + // Replace Groovy 4.x (org.apache.groovy) with Groovy 2.x (org.codehaus.groovy) + configurations.named("groovy2TestRuntimeClasspath") { + exclude(group = "org.apache.groovy") + } + configurations.named("groovy2TestRuntimeOnly") { + dependencies.add(project.dependencies.create("org.codehaus.groovy:groovy:2.5.22")) + } + targets { all { testTask.configure { diff --git a/rewrite-groovy/src/groovy2Test/java/org/openrewrite/groovy/GroovyParserTest.java b/rewrite-groovy/src/groovy2Test/java/org/openrewrite/groovy/GroovyParserTest.java index 1b5ea5b105..4c0d85782b 100644 --- a/rewrite-groovy/src/groovy2Test/java/org/openrewrite/groovy/GroovyParserTest.java +++ b/rewrite-groovy/src/groovy2Test/java/org/openrewrite/groovy/GroovyParserTest.java @@ -18,10 +18,18 @@ import org.junit.jupiter.api.Test; import org.openrewrite.test.RewriteTest; +import static org.assertj.core.api.Assertions.assertThat; import static org.openrewrite.groovy.Assertions.groovy; class GroovyParserTest implements RewriteTest { + @Test + void groovyRuntimeIsVersion2() throws Exception { + Class groovySystem = Class.forName("groovy.lang.GroovySystem"); + String version = (String) groovySystem.getMethod("getVersion").invoke(null); + assertThat(version).startsWith("2."); + } + @Test void shouldNotTreatDivisionAsDelimiter() { rewriteRun( @@ -90,4 +98,17 @@ void shouldBeAbleToParseParenthesisedIntegerConstantExpressions() { ); } + @Test + void shouldBeAbleToParseClassDeclaration() { + rewriteRun( + groovy( + """ + class Foo { + String bar + } + """ + ) + ); + } + } diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index 5ac0b4e12e..c5a974d13a 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -107,6 +107,9 @@ public class GroovyParserVisitor { @Nullable private static Boolean olderThanGroovy3; + @Nullable + private static Boolean groovy4OrLater; + @SuppressWarnings("unused") public GroovyParserVisitor(Path sourcePath, @Nullable FileAttributes fileAttributes, EncodingDetectingInputStream source, JavaTypeCache typeCache, ExecutionContext ctx) { this.sourcePath = sourcePath; @@ -124,15 +127,25 @@ public GroovyParserVisitor(Path sourcePath, @Nullable FileAttributes fileAttribu this.typeMapping = new GroovyTypeMapping(typeCache); } + private static int groovyMajorVersion() { + String groovyVersionText = GroovySystem.getVersion(); + return Integer.parseInt(groovyVersionText.substring(0, groovyVersionText.indexOf('.'))); + } + private static boolean isOlderThanGroovy3() { if (olderThanGroovy3 == null) { - String groovyVersionText = GroovySystem.getVersion(); - int majorVersion = Integer.parseInt(groovyVersionText.substring(0, groovyVersionText.indexOf('.'))); - olderThanGroovy3 = majorVersion < 3; + olderThanGroovy3 = groovyMajorVersion() < 3; } return olderThanGroovy3; } + private static boolean isGroovy4OrLater() { + if (groovy4OrLater == null) { + groovy4OrLater = groovyMajorVersion() >= 4; + } + return groovy4OrLater; + } + public G.CompilationUnit visit(SourceUnit unit, ModuleNode ast) throws GroovyParsingException { NavigableMap sortedByPosition = new TreeMap<>(); for (org.codehaus.groovy.ast.stmt.Statement s : ast.getStatementBlock().getStatements()) { @@ -254,7 +267,7 @@ public void visitClass(ClassNode clazz) { } else if (clazz.isEnum()) { kindType = J.ClassDeclaration.Kind.Type.Enum; skip("enum"); - } else if (clazz.isRecord()) { + } else if (isGroovy4OrLater() && clazz.isRecord()) { kindType = J.ClassDeclaration.Kind.Type.Record; skip("record"); } else { @@ -328,7 +341,7 @@ public void visitClass(ClassNode clazz) { } JContainer permitting = null; - if (clazz.isSealed() && clazz.getPermittedSubclasses() != null && !clazz.getPermittedSubclasses().isEmpty()) { + if (isGroovy4OrLater() && clazz.isSealed() && clazz.getPermittedSubclasses() != null && !clazz.getPermittedSubclasses().isEmpty()) { Space permitsPrefix = sourceBefore("permits"); List permitted = clazz.getPermittedSubclasses(); List> permitTypes = new ArrayList<>(permitted.size()); @@ -393,7 +406,7 @@ class A { */ Set fieldInitializers = new HashSet<>(); Set recordComponentNames = new HashSet<>(); - if (clazz.getRecordComponents() != null) { + if (isGroovy4OrLater() && clazz.getRecordComponents() != null) { for (RecordComponentNode rc : clazz.getRecordComponents()) { recordComponentNames.add(rc.getName()); }