-
Notifications
You must be signed in to change notification settings - Fork 366
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rewrite 8 migration requirements #3234
Comments
@kunli2 One more thing that is coming is the refactoring of the class FactoryMethod {
@BeforeTemplate
JavaTemplate before(String code, Supplier<Cursor> context) {
return JavaTemplate.builder(context, code);
}
@AfterTemplate
JavaTemplate after(String code, Supplier<Cursor> context) {
return JavaTemplate.builder(code).context(context);
}
} When applying the template the code changes something like this (this is a pseudo-template which isn't 100% correct): class TemplateApplication {
@BeforeTemplate
J before(TreeVisitor context, J j, JavaTemplate template, JavaCoordinates coordinates, Object... parameters) {
return j.withTemplate(template, coordinates, parameters);
}
@AfterTemplate
J after(TreeVisitor context, J j, JavaTemplate template, JavaCoordinates coordinates, Object... parameters) {
return j.withTemplate(template, context.getCursor(), coordinates, parameters);
}
} Please also note that the return literal
.withTemplate(
JavaTemplate.builder(template).context(this::getCursor).imports(owningType).build(),
getCursor(),
literal.getCoordinates().replace())
.withPrefix(literal.getPrefix()); |
Yeah, we can have a separate recipe for this change and add it to the yaml recipe |
|
Unless somebody objects, it might also be nice to handle the conversion from |
Point 8 above for the recipes moved to rewrite-static-analysis was also identified in openrewrite/rewrite-gradle-plugin#203 and could be a nice addition to META-INF/rewrite/migrate-rewrite.yml. We'd need to update those values in custom recipes, yaml files, and build plugin configurations. |
Tested recipe verified and it looks good to me, after addressing all the comments put by the migration recipes. it can pass compile. |
@shanman190 we now have such a recipe in UpdateMovedRecipe which we already use in src/main/resources/META-INF/rewrite/migrate-rewrite.yml; sounds like we'd need to add one more recipe to that list? Many thanks to @kunli2 for all the work on this! |
@timtebeek, yeah that should work for this case most definitely. |
Background of rewrite-8
Background for the impetus for rewrite 8. It is to support large repositories. Before 8, all LST for a repository needed to be loaded into memory and available for LST to operate. For large repos like Shelter’s e-commerce or Block’s franklin, this would not fit into memory. So we needed to redesign everything because the constraint now is that only part of LST is available in memory at a time and you don’t have random access - therefore LST needs to be scanned first to collect all info and then edit LST.
Rewrite 7 -> 8 change log highlights
org.openrewrite.Recipe getSingleSourceApplicableTest()
andorg.openrewrite.Recipe getApplicableTest()
methods are removed, introduced newPreconditions
APIs as a replacement.Recipe visit(List<SourceFile> before, ExecutionContext ctx)
that is used to visit multiple sources has been removed in rewrite 8. This method is used to change files, collect information, or generate new files.There are 3 phases in the new rewrite 8 API design.
- (1) Scanning phase
- (2) generating phase
- (3) Editing phase
basically, the Scanning phase doesn't make any code change, but just does information collection, rewrite8 introduces a new
ScanningRecipe
class to support this, For the generating phase, there is a new method .a
ScanningRecipe
may first scan a repository and study it in one pass over the repository's source files before, in another pass, it decides how to transform the code. New source file generation is part of this type as well, since in almost every case we check that a file doesn't yet exist (and perhaps other conditions) before deciding to generate a file.rewrite-static-analysis
and the package name is changed fromorg.openrewrite.java.cleanup
toorg.openrewrite.staticanalysis
JavaSourceFile org.openrewrite.java.JavaVisitor.visitJavaSourceFile(JavaSourceFile cu, P p)
is removed, we need to useJ org.openrewrite.java.TreeVisitor.visit(@Nullable Tree tree, P p)
instead.org.openrewrite.marker.Markers#SearchResult()
andorg.openrewrite.marker.Markers.searchResult(@Nullable String description
are deprecated and removed, useSearchResult.found()
instead.org.openrewrite.Recipe doNext(..)
is removed, it needs to change to use scanning recipe if the current recipe doesn't make any change, or just simply replace to useTreeVisitor#doAfterVisit()
, and in some unit test, we need to change cod likespec.recipe(X.doNext(Y))
tospec.recipes(X, Y)
sincespec.recipe()
method is removed as well.Comments from Sam (in this thread)
Visiting. Scanning/generating/editing
Recipes whose changes are local to a single source file have to make only minimal changes.
Recipe.getVisitor()
becamepublic
where previously it wasprotected
. Recipes which must query information from multiple different sources now need to be aScanningRecipe
.ScanningRecipe
is the replacement for the oldRecipe.visit(List<SourceFile>)
method which is now gone as the random access it provided is incompatible with efficient operation on large source sets. AScanningRecipe
provides an accumulator and a scanner. An accumulator is a custom data structure defined by the recipe itself which stores whatever information it needs later. A scanner is a visitor which populates the accumulator with data. The accumulator is then available during an optional generation step where new sources may be added to the list, and in the edit phase where the recipe provides a visitor which makes changes to source files as usual.Applicability and Preconditions
Applicability
tests have been supplanted byPreconditions
. Recipe no longer exposes agetSingleSourceApplicabilityTest()
orgetApplicabilityTest()
methods. Instead withingetVisitor()
a recipe author may usePreconditions.check(TreeVisitor check, TreeVisitor visitor)
to conditionally apply the visitor only if the check makes a change. This is equivalent semantically to a rewrite 7 single source applicability test, so usually all a recipe written in code has to do is copy the body of the old applicability test method into the first argument of a call toPreconditions.check()
.Recipe.getApplicabilityTest()
was rarely used and confusing, one of the reasons for this change, but since it had the property of checking all source files any recipe which requires those semantics will have to be aScanningRecipe
.There is unfortunately no way for a yaml recipe to use
Preconditions
. This is a reduction in functionality for yaml recipes relative to rewrite 7. We will have a way to supportPreconditions
or something similar eventually.Rewrite 7 -> 8 migration requires below changes
getVisitor()
toTreeVisitor<?, ExecutionContext>
, because that is what Preconditions returnsJavaSourceFile visitJavaSourceFile(JavaSourceFile cu, ExecutionContext ctx)
toJ visit(@Nullable Tree tree, ExecutionContext ctx)
Applicability.of()
->Preconditions.of()
, andApplicability.and()
->Preconditions.and()
rewrite-static-analysis
JavaTemplate.Builder#javaParser(Supplier<JavaParser>)
method no longer exists. Jonathan created a recipe to migrate it toJavaTemplate.Builder#javaParser(JavaParser.Builder)
, but I think that recipe needs to be extended a bit, in case theSupplier<JavaParser>
is represented by a variable or fieldTreeVisitor.doNext(..)
is removed, leave a comment to replace withTreeVisitor.doAfterVisit(..)
or follow the instruction.spec.recipe(X.doNext(Y)
) tospec.recipes(X, Y)
org.openrewrite.marker.Markers#SearchResult()
andorg.openrewrite.marker.Markers.searchResult(@Nullable String description
are deprecated and removed, useSearchResult.found()
instead.13. Gradle ChangeJavaCompatibility was renamed to UpdateJavaCompatibility with slightly different arguments in Feature/gradle/enhance update java compatibility #323814. handle the conversion fromgradle.RemoveGradleDependency
(yet to be removed) ->gradle.RemoveDependency
(argument order was flipped around to be consistent other than the rename;TreeVisitor#doAfterVisit(Recipe)
has been removed, left a comment to usedoAfterVisit(Recipe.getVisitor())
instead or use "inline" withvisit()
,doAfterVisit(Recipe)
was always more or less shorthand fordoAfterVisit(Recipe.getVisitor())
, which means it only runs on the current source, not all sources. So there are quite a few places where someone while visiting a java source file tried to usedoAfterVisit(Recipe)
to affect a dependency update that would never happen. So keep an eye out for mistaken usages ofdoAfterVisit(Recipe)
X.withTemplate(t, coordinate, params)
tot.apply(cursor, coordinate, params)
andJavaTemplate.builder(this::getCursor, "xyz")
->JavaTemplate.builder("xyz").contextSensitive()
, and put comments to require human review.The text was updated successfully, but these errors were encountered: