Initial commit
This commit is contained in:
13
skills/recipe-writer/templates/license-header.txt
Normal file
13
skills/recipe-writer/templates/license-header.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
Copyright ${year} the original author or authors.
|
||||
<p>
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
<p>
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
<p>
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
122
skills/recipe-writer/templates/template-declarative-recipe.yml
Normal file
122
skills/recipe-writer/templates/template-declarative-recipe.yml
Normal file
@@ -0,0 +1,122 @@
|
||||
---
|
||||
# OpenRewrite Declarative Recipe Template
|
||||
# Save this file in: src/main/resources/META-INF/rewrite/
|
||||
|
||||
# Required: Recipe type identifier
|
||||
type: specs.openrewrite.org/v1beta/recipe
|
||||
|
||||
# Required: Fully qualified recipe name (convention: com.yourorg.RecipeName)
|
||||
name: com.yourorg.YourRecipeName
|
||||
|
||||
# Required: Human-readable recipe name (sentence case, end with period if sentence)
|
||||
displayName: Your recipe display name
|
||||
|
||||
# Required: Clear description of what the recipe does
|
||||
description: A clear description of what this recipe accomplishes. This can span multiple lines and should explain the purpose and effect of running this recipe.
|
||||
|
||||
# Optional: Tags for categorization and searchability
|
||||
tags:
|
||||
- category1
|
||||
- category2
|
||||
- framework-name
|
||||
|
||||
# Optional: Estimated time saved by this recipe (in ISO-8601 duration format)
|
||||
# estimatedEffortPerOccurrence: PT5M
|
||||
|
||||
# Optional: Set to true if this recipe requires multiple execution cycles
|
||||
# causesAnotherCycle: true
|
||||
|
||||
# Optional: Define preconditions that files must meet to run this recipe
|
||||
# preconditions:
|
||||
# - org.openrewrite.java.search.UsesType:
|
||||
# fullyQualifiedTypeName: com.example.TargetType
|
||||
|
||||
# Required: List of recipes to execute (in order)
|
||||
recipeList:
|
||||
# Example: Recipe with no parameters
|
||||
- org.openrewrite.java.format.AutoFormat
|
||||
|
||||
# Example: Recipe with parameters
|
||||
- org.openrewrite.java.ChangeType:
|
||||
oldFullyQualifiedTypeName: old.package.OldType
|
||||
newFullyQualifiedTypeName: new.package.NewType
|
||||
# Optional parameter
|
||||
ignoreDefinition: false
|
||||
|
||||
# Example: Another recipe with parameters
|
||||
- org.openrewrite.java.ChangePackage:
|
||||
oldPackageName: com.old.package
|
||||
newPackageName: com.new.package
|
||||
recursive: true
|
||||
|
||||
# Example: Add a dependency (only if type is used)
|
||||
- org.openrewrite.java.dependencies.AddDependency:
|
||||
groupId: org.example
|
||||
artifactId: example-library
|
||||
version: latest.release
|
||||
onlyIfUsing: com.example.SomeClass
|
||||
configuration: implementation
|
||||
|
||||
# Example: Maven-specific recipe
|
||||
- org.openrewrite.maven.UpgradePluginVersion:
|
||||
groupId: org.apache.maven.plugins
|
||||
artifactId: maven-compiler-plugin
|
||||
newVersion: 3.11.0
|
||||
|
||||
# Add your recipes here
|
||||
# - com.yourorg.AnotherRecipe
|
||||
# - com.yourorg.YetAnotherRecipe:
|
||||
# parameter: value
|
||||
|
||||
---
|
||||
# You can define multiple recipes in the same file by using '---' separator
|
||||
|
||||
# type: specs.openrewrite.org/v1beta/recipe
|
||||
# name: com.yourorg.AnotherRecipe
|
||||
# displayName: Another recipe
|
||||
# description: Description of the second recipe.
|
||||
# recipeList:
|
||||
# - ...
|
||||
|
||||
# Common Recipe References:
|
||||
#
|
||||
# Java Type Changes:
|
||||
# - org.openrewrite.java.ChangeType
|
||||
# - org.openrewrite.java.ChangePackage
|
||||
# - org.openrewrite.java.ChangeMethodName
|
||||
# - org.openrewrite.java.ChangeFieldName
|
||||
#
|
||||
# Dependency Management:
|
||||
# - org.openrewrite.java.dependencies.AddDependency
|
||||
# - org.openrewrite.java.dependencies.RemoveDependency
|
||||
# - org.openrewrite.java.dependencies.ChangeDependency
|
||||
# - org.openrewrite.java.dependencies.UpgradeDependencyVersion
|
||||
#
|
||||
# Maven:
|
||||
# - org.openrewrite.maven.UpgradePluginVersion
|
||||
# - org.openrewrite.maven.UpgradeDependencyVersion
|
||||
# - org.openrewrite.maven.ChangePropertyValue
|
||||
#
|
||||
# Static Analysis:
|
||||
# - org.openrewrite.staticanalysis.CommonStaticAnalysis
|
||||
# - org.openrewrite.staticanalysis.FinalizeLocalVariables
|
||||
# - org.openrewrite.staticanalysis.RemoveUnusedImports
|
||||
#
|
||||
# Testing:
|
||||
# - org.openrewrite.java.testing.junit5.JUnit4to5Migration
|
||||
# - org.openrewrite.java.testing.junit5.AssertToAssertions
|
||||
#
|
||||
# Spring:
|
||||
# - org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_0
|
||||
# - org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_7
|
||||
#
|
||||
# Formatting:
|
||||
# - org.openrewrite.java.format.AutoFormat
|
||||
# - org.openrewrite.java.format.RemoveUnusedImports
|
||||
# - org.openrewrite.java.format.TabsAndIndents
|
||||
#
|
||||
# Search recipes (use these in preconditions):
|
||||
# - org.openrewrite.java.search.UsesType
|
||||
# - org.openrewrite.java.search.UsesMethod
|
||||
# - org.openrewrite.java.search.FindTypes
|
||||
# - org.openrewrite.java.search.FindMethods
|
||||
200
skills/recipe-writer/templates/template-imperative-recipe.java
Normal file
200
skills/recipe-writer/templates/template-imperative-recipe.java
Normal file
@@ -0,0 +1,200 @@
|
||||
package com.yourorg;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.openrewrite.*;
|
||||
import org.openrewrite.java.JavaIsoVisitor;
|
||||
import org.openrewrite.java.JavaTemplate;
|
||||
import org.openrewrite.java.tree.J;
|
||||
|
||||
/**
|
||||
* TODO: Add recipe description
|
||||
*
|
||||
* Example usage in YAML:
|
||||
* ```yaml
|
||||
* type: specs.openrewrite.org/v1beta/recipe
|
||||
* name: com.yourorg.MyRecipeGroup
|
||||
* recipeList:
|
||||
* - com.yourorg.TemplateRecipe:
|
||||
* parameterName: value
|
||||
* ```
|
||||
*/
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class TemplateRecipe extends Recipe {
|
||||
|
||||
/**
|
||||
* TODO: Add options for recipe configuration
|
||||
* Each option becomes a parameter that can be configured in YAML
|
||||
*/
|
||||
@Option(
|
||||
displayName = "Parameter Display Name",
|
||||
description = "A clear description of what this parameter does.",
|
||||
example = "com.example.ExampleValue"
|
||||
)
|
||||
@NonNull
|
||||
String parameterName;
|
||||
|
||||
// Add more @Option fields as needed
|
||||
// @Option(displayName = "Another Parameter", ...)
|
||||
// String anotherParameter;
|
||||
|
||||
/**
|
||||
* All recipes must be serializable via Jackson.
|
||||
* Use @JsonCreator and @JsonProperty annotations.
|
||||
*/
|
||||
@JsonCreator
|
||||
public TemplateRecipe(
|
||||
@NonNull @JsonProperty("parameterName") String parameterName
|
||||
) {
|
||||
this.parameterName = parameterName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Your recipe display name";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "A clear description of what this recipe does. Use sentence case and end with a period.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional: Add preconditions to improve performance
|
||||
* Recipes only run on files that match these conditions
|
||||
*/
|
||||
// @Override
|
||||
// public TreeVisitor<?, ExecutionContext> getVisitor() {
|
||||
// return Preconditions.check(
|
||||
// new UsesType<>("com.example.SomeType", true),
|
||||
// new TemplateRecipeVisitor()
|
||||
// );
|
||||
// }
|
||||
|
||||
@Override
|
||||
public TreeVisitor<?, ExecutionContext> getVisitor() {
|
||||
// IMPORTANT: Always return a NEW instance (no caching)
|
||||
return new TemplateRecipeVisitor();
|
||||
}
|
||||
|
||||
/**
|
||||
* The visitor implements the actual transformation logic.
|
||||
* Use JavaIsoVisitor when always returning the same LST type.
|
||||
*/
|
||||
public class TemplateRecipeVisitor extends JavaIsoVisitor<ExecutionContext> {
|
||||
|
||||
/**
|
||||
* Optional: Create JavaTemplates for complex code generation
|
||||
* Templates are parsed once and can be reused
|
||||
*/
|
||||
// private final JavaTemplate template = JavaTemplate
|
||||
// .builder("your.code.template(#{any(String)})")
|
||||
// .imports("your.imports.Here")
|
||||
// .build();
|
||||
|
||||
/**
|
||||
* Override visit methods for the LST elements you want to transform.
|
||||
* Common visit methods:
|
||||
* - visitCompilationUnit() - entire file
|
||||
* - visitClassDeclaration() - class declarations
|
||||
* - visitMethodDeclaration() - method declarations
|
||||
* - visitMethodInvocation() - method calls
|
||||
* - visitVariableDeclarations() - variable declarations
|
||||
* - visitAssignment() - assignments
|
||||
* - visitBinary() - binary operations
|
||||
* - visitImport() - imports
|
||||
*/
|
||||
@Override
|
||||
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) {
|
||||
// Step 1: ALWAYS call super to traverse the subtree
|
||||
J.ClassDeclaration cd = super.visitClassDeclaration(classDecl, ctx);
|
||||
|
||||
// Step 2: Check if this element needs to be changed
|
||||
// DO NO HARM: If unsure, return unchanged
|
||||
if (!shouldChange(cd)) {
|
||||
return cd;
|
||||
}
|
||||
|
||||
// Step 3: Make your changes
|
||||
// Never mutate the LST - always use .withX() methods
|
||||
cd = makeYourChanges(cd, ctx);
|
||||
|
||||
// Step 4: Optional - chain other visitors
|
||||
// doAfterVisit(new SomeOtherRecipe().getVisitor());
|
||||
|
||||
// Step 5: Optional - add/remove imports
|
||||
// maybeAddImport("java.util.List");
|
||||
// maybeRemoveImport("old.package.Type");
|
||||
|
||||
return cd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to determine if changes are needed
|
||||
*/
|
||||
private boolean shouldChange(J.ClassDeclaration classDecl) {
|
||||
// TODO: Implement your logic
|
||||
// Check if change is necessary and safe
|
||||
// Example: Check if class matches criteria
|
||||
|
||||
// Check for null type (avoid NPE)
|
||||
if (classDecl.getType() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Example: Check fully qualified name
|
||||
// if (!classDecl.getType().getFullyQualifiedName().equals(parameterName)) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// Example: Check if change already exists
|
||||
// if (alreadyHasTheChange(classDecl)) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to perform the transformation
|
||||
*/
|
||||
private J.ClassDeclaration makeYourChanges(J.ClassDeclaration classDecl, ExecutionContext ctx) {
|
||||
// TODO: Implement your transformation logic
|
||||
|
||||
// Example: Using a JavaTemplate
|
||||
// classDecl = classDecl.withBody(
|
||||
// template.apply(
|
||||
// new Cursor(getCursor(), classDecl.getBody()),
|
||||
// classDecl.getBody().getCoordinates().lastStatement(),
|
||||
// someParameter
|
||||
// )
|
||||
// );
|
||||
|
||||
// Example: Modifying using LST methods
|
||||
// classDecl = classDecl.withName(classDecl.getName().withSimpleName("NewName"));
|
||||
|
||||
// Example: Using ListUtils to avoid mutation
|
||||
// classDecl = classDecl.withModifiers(
|
||||
// ListUtils.concat(classDecl.getModifiers(), newModifier)
|
||||
// );
|
||||
|
||||
return classDecl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional: Example of another visit method
|
||||
*/
|
||||
// @Override
|
||||
// public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
|
||||
// J.MethodInvocation m = super.visitMethodInvocation(method, ctx);
|
||||
//
|
||||
// // Your logic here
|
||||
//
|
||||
// return m;
|
||||
// }
|
||||
}
|
||||
}
|
||||
292
skills/recipe-writer/templates/template-recipe-test.java
Normal file
292
skills/recipe-writer/templates/template-recipe-test.java
Normal file
@@ -0,0 +1,292 @@
|
||||
package com.yourorg;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openrewrite.DocumentExample;
|
||||
import org.openrewrite.test.RecipeSpec;
|
||||
import org.openrewrite.test.RewriteTest;
|
||||
|
||||
import static org.openrewrite.java.Assertions.java;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test class for TemplateRecipe
|
||||
*
|
||||
* Best Practices:
|
||||
* - Test both cases where changes ARE made and where they ARE NOT made
|
||||
* - Test edge cases and boundary conditions
|
||||
* - Use meaningful test names that describe what is being tested
|
||||
* - Add @DocumentExample to one test to generate documentation
|
||||
*/
|
||||
class TemplateRecipeTest implements RewriteTest {
|
||||
|
||||
/**
|
||||
* Configure defaults for all tests in this class.
|
||||
* This is called before each test method.
|
||||
*/
|
||||
@Override
|
||||
public void defaults(RecipeSpec spec) {
|
||||
// Set the recipe to test with default parameters
|
||||
spec.recipe(new TemplateRecipe("parameter-value"));
|
||||
|
||||
// Optional: Configure parser with classpath dependencies
|
||||
// spec.parser(JavaParser.fromJavaVersion()
|
||||
// .classpath("library-name")
|
||||
// .logCompilationWarningsAndErrors(true));
|
||||
|
||||
// Optional: Configure for specific Java version
|
||||
// spec.allSources(s -> s.markers(javaVersion(17)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the recipe makes the expected change.
|
||||
* @DocumentExample marks this as the primary example for documentation.
|
||||
*/
|
||||
@DocumentExample
|
||||
@Test
|
||||
void makesExpectedChange() {
|
||||
rewriteRun(
|
||||
// First argument: before state
|
||||
// Second argument: after state
|
||||
java(
|
||||
"""
|
||||
package com.example;
|
||||
|
||||
class BeforeExample {
|
||||
// TODO: Add code that should be changed
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package com.example;
|
||||
|
||||
class AfterExample {
|
||||
// TODO: Add expected code after transformation
|
||||
}
|
||||
"""
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the recipe does NOT make changes when they are not needed.
|
||||
* This is crucial - recipes must not make unnecessary changes!
|
||||
*/
|
||||
@Test
|
||||
void doesNotChangeWhenNotNeeded() {
|
||||
rewriteRun(
|
||||
java(
|
||||
"""
|
||||
package com.example;
|
||||
|
||||
class AlreadyCorrect {
|
||||
// TODO: Add code that should NOT be changed
|
||||
}
|
||||
"""
|
||||
// No second argument means we expect NO changes
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test edge case or boundary condition
|
||||
*/
|
||||
@Test
|
||||
void handlesEdgeCase() {
|
||||
rewriteRun(
|
||||
java(
|
||||
"""
|
||||
package com.example;
|
||||
|
||||
class EdgeCase {
|
||||
// TODO: Add edge case scenario
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package com.example;
|
||||
|
||||
class EdgeCase {
|
||||
// TODO: Add expected result for edge case
|
||||
}
|
||||
"""
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Test with multiple files
|
||||
* Demonstrates that some files change and others don't
|
||||
*/
|
||||
@Test
|
||||
void handlesMultipleFiles() {
|
||||
rewriteRun(
|
||||
// First file: should change
|
||||
java(
|
||||
"""
|
||||
package com.example;
|
||||
|
||||
class ShouldChange {
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package com.example;
|
||||
|
||||
class DidChange {
|
||||
}
|
||||
"""
|
||||
),
|
||||
// Second file: should NOT change
|
||||
java(
|
||||
"""
|
||||
package com.example;
|
||||
|
||||
class ShouldNotChange {
|
||||
}
|
||||
"""
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Test with custom recipe spec for this specific test
|
||||
*/
|
||||
@Test
|
||||
void testWithCustomConfiguration() {
|
||||
rewriteRun(
|
||||
// Customize the spec for just this test
|
||||
spec -> spec
|
||||
.recipe(new TemplateRecipe("different-parameter"))
|
||||
// Add specific classpath for this test
|
||||
// .parser(JavaParser.fromJavaVersion().classpath("specific-library"))
|
||||
,
|
||||
java(
|
||||
"""
|
||||
package com.example;
|
||||
|
||||
class Example {
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package com.example;
|
||||
|
||||
class Example {
|
||||
// Changes based on different parameter
|
||||
}
|
||||
"""
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Test with afterRecipe callback for additional assertions
|
||||
*/
|
||||
@Test
|
||||
void testWithCallback() {
|
||||
rewriteRun(
|
||||
java(
|
||||
"""
|
||||
package com.example;
|
||||
|
||||
class Example {
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package com.example;
|
||||
|
||||
class Example {
|
||||
// Some change
|
||||
}
|
||||
""",
|
||||
// Callback to perform additional assertions after recipe runs
|
||||
spec -> spec.afterRecipe(cu -> {
|
||||
// Custom assertions on the compilation unit
|
||||
assertThat(cu.getClasses()).hasSize(1);
|
||||
// Add more assertions as needed
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Test for declarative YAML recipe
|
||||
*/
|
||||
// @Test
|
||||
// void testDeclarativeRecipe() {
|
||||
// rewriteRun(
|
||||
// spec -> spec
|
||||
// .recipeFromResources("com.yourorg.TemplateRecipe")
|
||||
// .parser(JavaParser.fromJavaVersion()
|
||||
// .classpath("dependencies-needed-for-before-code")),
|
||||
// java(
|
||||
// """
|
||||
// package com.example;
|
||||
//
|
||||
// class Before {
|
||||
// }
|
||||
// """,
|
||||
// """
|
||||
// package com.example;
|
||||
//
|
||||
// class After {
|
||||
// }
|
||||
// """
|
||||
// )
|
||||
// );
|
||||
// }
|
||||
|
||||
/**
|
||||
* Example: Test with specific file path
|
||||
*/
|
||||
// @Test
|
||||
// void testWithSpecificPath() {
|
||||
// rewriteRun(
|
||||
// java(
|
||||
// """
|
||||
// server.port=8080
|
||||
// """,
|
||||
// """
|
||||
// server.port=80
|
||||
// """,
|
||||
// spec -> spec.path("src/main/resources/application.properties")
|
||||
// )
|
||||
// );
|
||||
// }
|
||||
|
||||
/**
|
||||
* Example: Test with Java version marker
|
||||
*/
|
||||
// @Test
|
||||
// void testWithJavaVersion() {
|
||||
// rewriteRun(
|
||||
// spec -> spec.allSources(s -> s.markers(javaVersion(17))),
|
||||
// java(
|
||||
// """
|
||||
// package com.example;
|
||||
//
|
||||
// class Example {
|
||||
// // Java 17 specific code
|
||||
// }
|
||||
// """
|
||||
// )
|
||||
// );
|
||||
// }
|
||||
|
||||
/**
|
||||
* Example: Test combining different source file types
|
||||
*/
|
||||
// @Test
|
||||
// void testMultipleFileTypes() {
|
||||
// rewriteRun(
|
||||
// java(
|
||||
// """
|
||||
// package com.example;
|
||||
// class Example { }
|
||||
// """
|
||||
// ),
|
||||
// // You can mix java(), xml(), yaml(), properties(), etc.
|
||||
// // yaml(
|
||||
// // """
|
||||
// // key: value
|
||||
// // """
|
||||
// // )
|
||||
// );
|
||||
// }
|
||||
}
|
||||
134
skills/recipe-writer/templates/template-refaster-template.java
Normal file
134
skills/recipe-writer/templates/template-refaster-template.java
Normal file
@@ -0,0 +1,134 @@
|
||||
package com.yourorg;
|
||||
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import org.openrewrite.java.template.RecipeDescriptor;
|
||||
|
||||
/**
|
||||
* Refaster template for simple expression/statement replacements.
|
||||
*
|
||||
* Refaster templates provide a middle ground between declarative YAML and imperative Java recipes:
|
||||
* - Faster than imperative recipes
|
||||
* - Type-aware matching
|
||||
* - Concise syntax
|
||||
* - Good for API migrations
|
||||
*
|
||||
* Usage:
|
||||
* 1. Define @BeforeTemplate with the code pattern to match
|
||||
* 2. Define @AfterTemplate with the replacement code
|
||||
* 3. OpenRewrite generates a recipe that performs the transformation
|
||||
*
|
||||
* Example usage in YAML:
|
||||
* ```yaml
|
||||
* type: specs.openrewrite.org/v1beta/recipe
|
||||
* name: com.yourorg.MyRefasterRecipe
|
||||
* recipeList:
|
||||
* - com.yourorg.TemplateRefaster
|
||||
* ```
|
||||
*/
|
||||
@RecipeDescriptor(
|
||||
name = "Your Refaster recipe name",
|
||||
description = "Clear description of what this Refaster template accomplishes."
|
||||
)
|
||||
public class TemplateRefaster {
|
||||
|
||||
/**
|
||||
* Example 1: Simple method call replacement
|
||||
* Replaces StringUtils.equals() with Objects.equals()
|
||||
*/
|
||||
public static class ReplaceStringUtilsEquals {
|
||||
@BeforeTemplate
|
||||
boolean before(String s1, String s2) {
|
||||
return org.apache.commons.lang3.StringUtils.equals(s1, s2);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
boolean after(String s1, String s2) {
|
||||
return java.util.Objects.equals(s1, s2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example 2: Expression replacement with type awareness
|
||||
* Replaces new ArrayList<>() with List.of() for immutable lists (Java 9+)
|
||||
*/
|
||||
public static class ReplaceArrayListWithListOf {
|
||||
@BeforeTemplate
|
||||
<T> java.util.List<T> before() {
|
||||
return new java.util.ArrayList<>();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
<T> java.util.List<T> after() {
|
||||
return java.util.List.of();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example 3: Statement replacement
|
||||
* Replaces traditional for loop with enhanced for loop
|
||||
*/
|
||||
public static class ReplaceTraditionalForWithEnhanced {
|
||||
@BeforeTemplate
|
||||
void before(java.util.List<String> items) {
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
String item = items.get(i);
|
||||
System.out.println(item);
|
||||
}
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(java.util.List<String> items) {
|
||||
for (String item : items) {
|
||||
System.out.println(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example 4: API migration with different parameters
|
||||
* Migrates from old API to new API with parameter reordering
|
||||
*/
|
||||
public static class MigrateOldApiToNew {
|
||||
@BeforeTemplate
|
||||
void before(String value, int timeout) {
|
||||
com.oldapi.Client.connect(value, timeout);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(String value, int timeout) {
|
||||
com.newapi.Client.connect(timeout, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Add your Refaster templates here
|
||||
*
|
||||
* Tips:
|
||||
* - Keep templates simple - complex logic should use imperative recipes
|
||||
* - Use type parameters for generic matching (<T>, <S>, etc.)
|
||||
* - Method names (before/after) can be anything - only annotations matter
|
||||
* - Return types and parameters must match between before and after for type safety
|
||||
* - You can have multiple nested template classes in one file
|
||||
*/
|
||||
|
||||
public static class YourRefasterTemplate {
|
||||
/**
|
||||
* Define what code pattern to match
|
||||
*/
|
||||
@BeforeTemplate
|
||||
void before() {
|
||||
// TODO: Add the code pattern you want to match and replace
|
||||
// Example: someOldMethod()
|
||||
}
|
||||
|
||||
/**
|
||||
* Define what to replace it with
|
||||
*/
|
||||
@AfterTemplate
|
||||
void after() {
|
||||
// TODO: Add the replacement code
|
||||
// Example: someNewMethod()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user