openrewrite / rewrite-templating

Automated templating using code snippets.
Apache License 2.0
16 stars 7 forks source link

Refaster style recipes cannot match types that require transitive dependencies to be loaded #86

Closed sambsnyd closed 5 months ago

sambsnyd commented 5 months ago

This parser:

JavaTemplate.builder("#{any(com.azure.cosmos.CosmosClientBuilder)}.endpoint(\"boo\").userAgentSuffix(\"test\").buildAsyncClient()")
                .javaParser(JavaParser.fromJavaVersion().classpath("azure-cosmos"))
                .build()

Cannot be used to match a method invocation of CosmosClientBuilder.buildAsyncClient() because the method its parser produces lacks type information. CosmosClientBuilder is defined within the jar "azure-cosmos", but also requires "azure-core" for the java compiler to type attribute it.

This is because JavaParser.fromJavaVersion().classpath() does not look up transitive dependencies of the named artifact, so "azure-core" is absent from the classpath.

This test can be used to reproduce the issue. Changing JavaParser.fromJavaVersion().classpath(JavaParser.fromRuntimeClasspath()) resolves this problem because the full runtime classpath has both "azure-cosmos" and "azure-core".

Gueorgi commented 5 months ago

All my testing used already the JavaParser.fromJavaVersion().classpath(JavaParser.runtimeClasspath()) in the defaults spec.recipe for the generated recipe template. And it never worked - we debugged it few day ago and last week as well - that is how it was set-up already. Still does not work.

Gueorgi commented 5 months ago

@sambsnyd

Actually I copied your test in my local and modified it (not looking for specific userAgent, endpoint).... and it works! :)

Looks like the issue was indeed was with setting the classpath - the big difference was that I was doing it in the defaults:

public void defaults(RecipeSpec spec) { spec.recipe(new ReplaceAsyncClientBuilderRecipe()).parser(JavaParser.fromJavaVersion() .classpath(JavaParser.runtimeClasspath())); }

where it works only if I use it like you - in the JavaTemplate and on the running recipe instances:

rewriteRun( spec -> spec.recipe(toRecipe(() -> new JavaVisitor<>() { final JavaTemplate template = JavaTemplate.builder(..... ) .javaParser(JavaParser.fromJavaVersion().classpath(JavaParser.runtimeClasspath())) .build(); ..... ) .parser(JavaParser.fromJavaVersion().classpath(JavaParser.runtimeClasspath())) .....