据了解,OpenRewrite 主要有 3 种创建配方的方法:Declarative、Refaster 和 Imperative。这是关于 Refaster 方法的。
我创建了以下 Refaster 模板类来进行简单的代码更改 - 确保除法发生在乘法之后。 (只是一个测试 OpenRewrite 功能的示例)
package com.self.openrewrite_lib.refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import org.openrewrite.java.template.RecipeDescriptor;
@RecipeDescriptor(name = "Multiply then divide formatter", description = "Ensures that divisions occur after multiplication for accuracy.")
public class MultiplyThenDivide {
@BeforeTemplate
public double divideThenMultiply(double original, double divisor, double multiplier) {
return original / divisor * multiplier;
}
@AfterTemplate
public double multiplyThenDivide(double original, double divisor, double multiplier) {
return original * multiplier / divisor;
}
}
在终端中运行
mvn compile
后,会在target/generated-sources/annotations/com/self/openrewrite_lib/refaster
目录中生成Recipe类。
package com.self.openrewrite_lib.refaster;
import org.jspecify.annotations.NullMarked;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.JavaParser;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.search.*;
import org.openrewrite.java.template.Primitive;
import org.openrewrite.java.template.function.*;
import org.openrewrite.java.template.internal.AbstractRefasterJavaVisitor;
import org.openrewrite.java.tree.*;
import javax.annotation.Generated;
import java.util.*;
import static org.openrewrite.java.template.internal.AbstractRefasterJavaVisitor.EmbeddingOption.*;
/**
* OpenRewrite recipe created for Refaster template {@code MultiplyThenDivide}.
*/
@SuppressWarnings("all")
@NullMarked
@Generated("org.openrewrite.java.template.processor.RefasterTemplateProcessor")
public class MultiplyThenDivideRecipe extends Recipe {
/**
* Instantiates a new instance.
*/
public MultiplyThenDivideRecipe() {}
@Override
public String getDisplayName() {
return "Multiply then divide formatter";
}
@Override
public String getDescription() {
return "Ensures that divisions occur after multiplication for accuracy.";
}
@Override
public TreeVisitor\<?, ExecutionContext\> getVisitor() {
return new AbstractRefasterJavaVisitor() {
final JavaTemplate divideThenMultiply = JavaTemplate
.builder("#{original:any(double)} / #{divisor:any(double)} * #{multiplier:any(double)}")
.build();
final JavaTemplate multiplyThenDivide = JavaTemplate
.builder("#{original:any(double)} * #{multiplier:any(double)} / #{divisor:any(double)}")
.build();
@Override
public J visitBinary(J.Binary elem, ExecutionContext ctx) {
JavaTemplate.Matcher matcher;
if ((matcher = divideThenMultiply.matcher(getCursor())).find()) {
return embed(
multiplyThenDivide.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0), matcher.parameter(2), matcher.parameter(1)),
getCursor(),
ctx,
SHORTEN_NAMES
);
}
return super.visitBinary(elem, ctx);
}
};
}
}
在编写 OpenRewrite 测试用例时可以使用上面的内容,但是当尝试通过
mvn rewrite:run
命令在我自己的代码上运行配方时,或者尝试通过 mvn rewrite:discover
命令发现配方时,找不到新生成的配方.
测试用例使用(通过):
package com.self.openrewrite_lib;
import com.self.openrewrite_lib.refaster.MultiplyThenDivideRecipe;
import org.junit.jupiter.api.Test;
import org.openrewrite.test.RewriteTest;
class OpenRewriteTests implements RewriteTest {
@Test
void multiplyThenDivideRecipe() {
rewriteRun(spec -> spec.recipe(new MultiplyThenDivideRecipe()),
//language=java
org.openrewrite.java.Assertions.java(
"""
class TestExample {
public double calculate(double a, double b, double c) {
return a / b * c;
}
}
""",
"""
class TestExample {
public double calculate(double a, double b, double c) {
return a * c / b;
}
}
"""
));
}
}
运行
mvn rewrite:discover
:
Failed to execute goal org.openrewrite.maven:rewrite-maven-plugin:5.42.2:discover (default-cli) on project openrewrite-lib: Could not find recipe 'com.self.openrewrite_lib.refaster.MultiplyThenDivideRecipe' among available recipes -> [Help 1]
运行
mvn rewrite:run
:
Failed to execute goal org.openrewrite.maven:rewrite-maven-plugin:5.42.2:run (default-cli) on project openrewrite-lib: Execution default-cli of goal org.openrewrite.maven:rewrite-maven-plugin:5.42.2:run failed: Recipe(s) not found: com.self.openrewrite_lib.refaster.MultiplyThenDivideRecipe
任何指导将不胜感激。谢谢。
用于参考的教程/文档:https://docs.openrewrite.org/authoring-recipes/refaster-recipes
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.self</groupId>
<artifactId>openrewrite-lib</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>openrewrite-lib</name>
<description>Demo project for Spring Boot</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<java.version>17</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-recipe-bom</artifactId>
<version>2.21.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.openrewrite</groupId>
<artifactId>rewrite-java</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openrewrite</groupId>
<artifactId>rewrite-java-17</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.openrewrite</groupId>
<artifactId>rewrite-yaml</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openrewrite</groupId>
<artifactId>rewrite-templating</artifactId>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
<version>2.34.0</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service-annotations</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openrewrite</groupId>
<artifactId>rewrite-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M9</version>
</plugin>
<!-- lombok is optional, but recommended for authoring recipes -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>17</source>
<target>17</target>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
</path>
<path>
<groupId>org.openrewrite</groupId>
<artifactId>rewrite-templating</artifactId>
<version>1.16.1</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>5.42.2</version>
<configuration>
<activeRecipes>
<recipe>com.self.openrewrite_lib.refaster.MultiplyThenDivideRecipe</recipe>
</activeRecipes>
</configuration>
</plugin>
</plugins>
</build>
</project>
您是否将该
target/generated-sources/annotations/
文件夹标记为生成的源根目录?如果文件存在但找不到该类,听起来您的 IDE 尚未识别该文件。
对于参考实现,您还可以查看我们的重写配方启动器: https://github.com/moderneinc/rewrite-recipe-starter/blob/main/pom.xml#L150-L154
希望有帮助!