openrewrite / openrewrite/rewrite
Kotlin external classpath artifact fail to parse
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 3.7k
- Forks
- 571
- Avg merge
- 13h 12m
- Merged PRs (30d)
- 261
Description
I am using
- OpenRewrite v8.30.0
- Gradle plugin v8.30.0
- rewrite-kotlin v8.30.0
How are you running OpenRewrite?
Using openrewrite with kotlin/gradle plugin, single module
Following on from slack conversation at https://rewriteoss.slack.com/archives/C01A843MWG5/p1721744738864449?thread_ts=1721135504.974819&cid=C01A843MWG5
What is the smallest, simplest way to reproduce the problem?
Based on the rewrite starter recipe, I am trying to write a simple replacement that references the jar io.kotest:kotest-property-jvm, however it fails on parsing
package com.yourorg;
import lombok.EqualsAndHashCode;
import lombok.Value;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.*;
import org.openrewrite.java.search.UsesMethod;
import org.openrewrite.java.tree.J;
import org.openrewrite.kotlin.KotlinIsoVisitor;
import org.openrewrite.kotlin.KotlinTemplate;
@Value
@EqualsAndHashCode(callSuper = false)
public class MigrateUUIDArbUsage extends Recipe {
@Override
public String getDisplayName() {
// language=markdown
return "Convert Arb uuid usages`";
}
@Override
public String getDescription() {
return "Convert arb uuid usages.";
}
private static MethodMatcher MATCHER = new MethodMatcher("io.kotest.property.arbitrary.ArbsKt next(..)");
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return Preconditions.check(new UsesMethod<>("io.kotest.property.arbitrary.ArbsKt next(..)", null),
new KotlinIsoVisitor<ExecutionContext>() {
@Override
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
// System.out.println(TreeVisitingPrinter.printTree(getCursor()));
J.MethodInvocation m = super.visitMethodInvocation(method, ctx);
if (!MATCHER.matches(m)) {
return m;
}
if (m.getSelect() instanceof J.Identifier && ((J.Identifier) m.getSelect()).getSimpleName().equals("uuidArb")) {
maybeAddImport("io.kotest.property.Arb", false);
maybeAddImport("io.kotest.property.arbitrary.UUIDVersion", false);
maybeAddImport("io.kotest.property.arbitrary.next", false);
m = KotlinTemplate.builder("Arb.uuid(UUIDVersion.V4, false).next()")
.doBeforeParseTemplate(t -> System.out.println(t))
.imports(
"io.kotest.property.arbitrary.next",
"io.kotest.property.arbitrary.UUIDVersion",
"io.kotest.property.Arb")
.javaParser(JavaParser.fromJavaVersion().logCompilationWarningsAndErrors(true)
.classpath(
"kotest-property-jvm"
)
)
.build()
.apply(getCursor(), m.getCoordinates().replace());
}
return m;
}
});
}
}
package com.yourorg
import org.junit.jupiter.api.Test
import org.openrewrite.DocumentExample
import org.openrewrite.kotlin.Assertions
import org.openrewrite.kotlin.KotlinParser
import org.openrewrite.test.RecipeSpec
import org.openrewrite.test.RewriteTest
class ArbTransformTest: RewriteTest {
override fun defaults(spec: RecipeSpec) {
spec.recipe(MigrateUUIDArbUsage())
.parser(
KotlinParser.builder() //.parser(
//JavaParser.fromJavaVersion()
.classpath(
"kotest-property-jvm",
"kotest-property",
"arbs",
"junit-jupiter-api")
)
}
@DocumentExample
@Test
fun kotlinFoo() {
rewriteRun(
Assertions.kotlin(
"""
import io.kotest.property.arbitrary.next
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.smw.arbs.uuidArb
class TestTest {
@Test
fun arbTest() {
val uuid = uuidArb.next()
Assertions.assertEquals(uuid, uuid)
}
}
""".trimIndent(), """
import io.kotest.property.Arb
import io.kotest.property.arbitrary.UUIDVersion
import io.kotest.property.arbitrary.next
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
class TestTest {
@Test
fun arbTest() {
val uuid = Arb.uuid(UUIDVersion.V4, false).next()
Assertions.assertEquals(uuid, uuid)
}
}
""".trimIndent()
)
)
}
}
Error when running the test is
import io.kotest.property.arbitrary.next
import io.kotest.property.arbitrary.UUIDVersion
import io.kotest.property.Arb
import org.openrewrite.java.internal.template.__M__;
import org.openrewrite.java.internal.template.__P__;
class Template {
var o : Object =
/*__TEMPLATE__*/Arb.uuid(UUIDVersion.V4, false).next()/*__TEMPLATE_STOP__*/
;
}
java.lang.IllegalStateException: LST contains missing or invalid type information
Identifier->MethodInvocation->MethodInvocation->NamedVariable->VariableDeclarations->Block->MethodDeclaration->Block->ClassDeclaration->CompilationUnit
/*~~(Identifier type is missing or malformed)~~>*/Arb
at org.openrewrite.kotlin.Assertions.assertValidTypes(Assertions.java:235)
at org.openrewrite.kotlin.Assertions.validateTypes(Assertions.java:56)
at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:508)
at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:132)
at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:127)
at com.yourorg.ArbTransformTest.kotlinFoo(ArbTransformTest.kt:27)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
The artifact is included in the project via
testRuntimeOnly("io.kotest:kotest-property:5.9.1")
If I add spec.typeValidationOptions(TypeValidation.none()) to the test, it passes, ideally would like to avoid this.
Are you interested in contributing a fix to OpenRewrite?
Happy to help where I can
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the KotlinTemplate builder's JavaParser classpath handling and the KotlinParser configuration in ArbTransformTest.kt. Run kotlinFoo with type validation enabled and inspect the failure reported by Assertions.validateTypes. Done means the external Kotest artifact is resolved for the template and the test passes without TypeValidation.none().
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, kotlin
- Domain
- testing-qa, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100