
1 使用javaTemplate修改method
1.1 注意openrewrite大量使用stream模式处理,比如map、filter
1.1.1 使用collect收集汇聚结果
1.2 override JavaIsoVisitor Declaration方法
1.2.1 visitClassDeclaration
1.2.2 visitMethodDeclaration
1.2.3 visitVariableDeclarations
1.3 限制visitor范围
1.3.1 就是控制执行范围,避免误修改其它代码
1.3.2 使用各类Matcher,或者precondition
2 cursor使用
2.1 使用存在的cursor
2.1.1 最常见的用例。当访问器中的光标未进行任何更改时,以及当您想要准确访问光标指向的内容时使用
2.2 创建 new Cursor(getCursor(), ...)
2.2.1 适用于现有光标所指内容与您想修改的内容不匹配的情况,常用于新增代码,如在class内新增method、field等
2.2.2 注意:可能希望将模板应用于 ClassDeclaration 内部的 J.Block,而非 ClassDeclaration 本身
2.3 update当前cursor
2.3.1 修改了当前J对象(即visit的对象)并希望继续进行更改时,都需要使用 updateCursor()
2.3.2 注意需要同步定位coordinate
3 自定义data table输出
3.1 用于各种分析,run命令可以加输出到data table的参数
3.2 自定义data table
3.2.1 Extend org.openrewrite.DataTable
3.2.2 使用@Column定义column
列名称-displayName
用途描述-description
java
example
@Column(displayName = "Relationship",
description = "Whether the class implements a super interface or extends a superclass.")
Relationship relationship;
3.2.3 使用transient 类型创建report
transient关键字用于声明类的某些变量不应该被序列化。
insertRow 输出内容到data table
4 eslint
4.1 引入eslint依赖
4.1.1
java
gradle-"dependencies": {
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
}
4.2 使用已有recipe
4.2.1 https://github.com/moderneinc/rewrite-codemods/tree/main
Subtopic
4.2.2 这个recipe 不仅仅包括了eslint
https://github.com/moderneinc/rewrite-codemods/tree/main/src/main/resources/META-INF/rewrite
5 在同一个recipe里面创建多个visitors
5.1 一般用于交叉检查后执行某个动作,官方的例子是检查变量是否有被assign,如果没有就添加final
5.2 vistor的执行可通过代码驱动
java
//调用另外一个,,如果是的,就是
//注意使用了,即没有才执行
if (variableDeclarations.getVariables().stream()
.noneMatch(namedVariable ->
FindAssignmentReferencesToVariable.find(getCursor()
.getParentTreeCursor()
.getValue(),
namedVariable)
.get()))
6 预估时间
6.1 代码
@Override
public Duration getEstimatedEffortPerOccurrence() {
return Duration.ofMinutes(10);
}
6.2 查看结果
6.2.1 estimated time saved in the SourcesFileResults table
7 指定recipe间依赖版
7.1 默认依赖最新版本
7.2 -依靠recipe-library
7.2.1
xml
Gradle-build.gradle
plugins {
id("org.openrewrite.build.recipe-library") version "latest.release"
}
recipeDependencies {
parserClasspath("org.mockito:mockito-core:2.16.0")
parserClasspath("org.mockito:mockito-core:3.12.4")
parserClasspath("junit:junit:3.7")
parserClasspath("junit:junit:4.13.2")
}
7.2.2 Maven
增加typetable profile
xml
<profiles>
<!--
When you want to generate a TypeTable for use in JavaParser for JavaTemplate, run the following command:
./mvnw generate-resources -Ptypetable
-->
<profile>
<id>typetable</id>
<build>
<plugins>
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>6.9.0-SNAPSHOT</version>
<configuration>
<recipeArtifactCoordinates>
junit:junit:3.8.1,
junit:junit:4.13.2,
org.mockito:mockito-core:2.16.0,
org.mockito:mockito-core:3.12.4
</recipeArtifactCoordinates>
</configuration>
<executions>
<execution>
<goals>
<goal>typetable</goal>
</goals>
<phase>generate-resources</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
7.2.3 生成typetable
生成定义文件
保存在src/main/resources/META-INF/rewrite
maven
./mvnw generate-resources -Ptypetable
gradle
-run the createTypeTable task
下载相关依赖-downloadRecipeDependencies task
7.3 代码指定
7.3.1
java
@Override
public void defaults(RecipeSpec spec) {
spec
.parser(JavaParser.fromJavaVersion()
.classpathFromResources(new InMemoryExecutionContext(), "junit-4.13.2", "mockito-core-3.12.4"));
}
7.3.2 增加依赖jar 到src/main/resources/META-INF/rewrite/classpath下
7.3.3 好像只能用于测试,example是基于org.openrewrite.test.RecipeSpec
8 Preconditions
8.1 使用Preconditions来在最外围保障执行范围,替代在执行过程中的检查
java
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return Preconditions.check(
Preconditions.or(new UsesMethod<>(STRING_BUILDER_APPEND),
new UsesMethod<>(STRING_BUILDER_APPEND)), new JavaIsoVisitor<ExecutionContext>() {
@Override
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
J.MethodInvocation m = super.visitMethodInvocation(method, ctx);
// do something
return m;
}
});
}
9 ScanningRecipe
9.1 2个函数
9.1.1 scan函数,入口参数维后续generate要处理的对象
9.1.2 @Override
public TreeVisitor<?, ExecutionContext> getScanner(Accumulator acc) {
9.1.3 @Override
public Collection<? extends SourceFile> generate(Accumulator acc, ExecutionContext ctx) {
generate回返回一个对象,然后由对应visitor处理
9.2 一个visitor
9.2.1 visit generate 返回的对象,进行处理
public TreeVisitor<?, ExecutionContext> getVisitor(Accumulator acc) {
9.2.2 注意和2个函数的入参一样,这样数据可以在2个函数及visitor 间传递
9.3 用途
9.3.1 scan所有指定对象,然后generate accumulator 给visitor处理
如果一个 Recipe 需要生成新的源文件或者需要在进行更改前查看所有源文件,那它必须是 ScanningRecpie。
在实现层面 ScanningRecipe 扩展了 Recipe ,添加两个关键对象:accumulator 和 scanner。
accumulator 是由 Recipe 自身来定义的数据结构,用于存储 Recipe 运行时所需的任何信息。
scanner 是一个用数据来填充 accumulator 的 Visitor #visitor.