openrewrite 自定义recipe part2

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.

相关推荐
0和1的舞者3 天前
基于Spring的论坛系统-前置知识
java·后端·spring·系统·开发·知识
康谋自动驾驶6 天前
汽车多总线数据采集:挑战、架构与同步策略全解析
算法·自动驾驶·开发·数据处理·总线数据
智行众维18 天前
从“测试泥潭”到“智能加速”:我们对自动驾驶仿真测试的新思考
数据库·自动驾驶·开发·技术·场景库·自动驾驶仿真测试·场景开发
Leweslyh23 天前
制导算法开发实践指南:从入门到精通
算法·开发·武器·制导律设计
0和1的舞者1 个月前
Git 实战踩坑:如何让多个 IDE 项目共用一个远程仓库(附子模块问题解决)
git·开发·仓库·码云·子模块·操作·冲突
我有一棵树1 个月前
一、GitHub 的 WIP 功能简介
github·开发·前端、
myzzb1 个月前
python调用ffmpeg.exe封装装饰类调用
python·学习·ffmpeg·开发
程序员鱼皮1 个月前
从夯到拉,锐评 28 个后端技术!
后端·计算机·程序员·开发·编程经验
总是学不会.1 个月前
[特殊字符] 自动分区管理系统实践:让大型表维护更轻松
java·后端·数据库开发·开发