Initial commit
This commit is contained in:
15
.claude-plugin/plugin.json
Normal file
15
.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "openrewrite-recipe",
|
||||
"description": "Expert guidance for writing OpenRewrite recipes - automated refactoring operations for source code. Includes templates, examples, and comprehensive best practices.",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "Moderne, Inc.",
|
||||
"url": "https://github.com/openrewrite"
|
||||
},
|
||||
"skills": [
|
||||
"./skills/writing-openrewrite-recipes"
|
||||
],
|
||||
"commands": [
|
||||
"./commands/create-recipe.md"
|
||||
]
|
||||
}
|
||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# openrewrite-recipe
|
||||
|
||||
Expert guidance for writing OpenRewrite recipes - automated refactoring operations for source code. Includes templates, examples, and comprehensive best practices.
|
||||
7
commands/create-recipe.md
Normal file
7
commands/create-recipe.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
name: create-recipe
|
||||
description: Create an OpenRewrite recipe for a specific problem
|
||||
args: Problem description
|
||||
---
|
||||
|
||||
Use the writing-openrewrite-recipes skill to create a recipe for: {{args}}
|
||||
137
plugin.lock.json
Normal file
137
plugin.lock.json
Normal file
@@ -0,0 +1,137 @@
|
||||
{
|
||||
"$schema": "internal://schemas/plugin.lock.v1.json",
|
||||
"pluginId": "gh:openrewrite/rewrite-docs:openrewrite-recipe-writer",
|
||||
"normalized": {
|
||||
"repo": null,
|
||||
"ref": "refs/tags/v20251128.0",
|
||||
"commit": "97f83cd2197f9345566220cb3c613a4eb5386558",
|
||||
"treeHash": "049fc4cdd92369bce2da02fd52742233dd73d5cedbe66ac17a777f45a869e4bb",
|
||||
"generatedAt": "2025-11-28T10:27:27.303609Z",
|
||||
"toolVersion": "publish_plugins.py@0.2.0"
|
||||
},
|
||||
"origin": {
|
||||
"remote": "git@github.com:zhongweili/42plugin-data.git",
|
||||
"branch": "master",
|
||||
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
|
||||
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
|
||||
},
|
||||
"manifest": {
|
||||
"name": "openrewrite-recipe",
|
||||
"description": "Expert guidance for writing OpenRewrite recipes - automated refactoring operations for source code. Includes templates, examples, and comprehensive best practices.",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"content": {
|
||||
"files": [
|
||||
{
|
||||
"path": "README.md",
|
||||
"sha256": "36bd9aab221816b97156d93d47dbfce43f6bfb154d371809278459928970a2d9"
|
||||
},
|
||||
{
|
||||
"path": ".claude-plugin/plugin.json",
|
||||
"sha256": "9026c3316790657e578487f7dea78c3a8d1747cbe7df1e88719e2967255a0493"
|
||||
},
|
||||
{
|
||||
"path": "commands/create-recipe.md",
|
||||
"sha256": "df47437b157326d517df39b0f516dffbe8463b6f2371063e32c32ce7b7753d83"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/SKILL.md",
|
||||
"sha256": "328234d8905fdc27cf6d9567db04635b74ac395a36b170d42fd4bf9773667e98"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/references/example-say-hello-recipe.java",
|
||||
"sha256": "12b384c30934e1ff2d874cc6f65a10d0cbd699453cb079ebc379ec9d7949f120"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/references/recipes-all.csv",
|
||||
"sha256": "5e08c9b8456f4b71bfdada2bad28b5f968a2849903f522ddfd57e5922c1ab30e"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/references/checklist-recipe-development.md",
|
||||
"sha256": "8750d9a048a22fd7c0da51d9f8e5eabeecab9c84b17ee4ba139ebac21f64dfd2"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/references/recipes-xml-yaml-json-common.csv",
|
||||
"sha256": "bf5097aec80a573b23bbdb5943cc23d4b784b27429a9c8057a15c3a62949153b"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/references/example-scanning-recipe.java",
|
||||
"sha256": "c87fe6c1dc09ceda8ba75e4099504eddd89da1db52cc17ee2bb79de96dc48809"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/references/recipes-framework-migrations-common.csv",
|
||||
"sha256": "043315a667d6eb733d8428c6179ae9f17e4c492d39c9e11e24b9274efdc8801f"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/references/example-declarative-migration.yml",
|
||||
"sha256": "ec94034dea27e0e647fe66f4dd6420c57fb1b64d926abe187232d81b69bdb388"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/references/recipes-spring-boot-common.csv",
|
||||
"sha256": "7fbec3a2b8397bd8e755ef9976f50b23f9433eeaa33069e09f774f0acb63cec0"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/references/recipes-java-basic.csv",
|
||||
"sha256": "34fe896e82bb342f2662a4008dd13464fe8ad3d17aae27e237587d30d4c3a94f"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/references/recipes-dependencies-common.csv",
|
||||
"sha256": "b881a20a8589613a6412d75cbf099968d6dcb2fafb2d081470c49f8d69f5401f"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/references/recipes-file-operations.csv",
|
||||
"sha256": "9453041510ce0d33080248009b2891e710fada212826b3799c3919b460e91c10"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/references/recipes-static-analysis-common.csv",
|
||||
"sha256": "27f044c2a1bf82e90175fb9c9253682f48cd957e43a390b40ba4f43d0f47f9e1"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/references/recipes-testing-common.csv",
|
||||
"sha256": "a9fef84a7bbcb7d597b9263cbc6fb37b0f3956785f85d405d8c76442c8cb4d14"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/references/recipes-security-common.csv",
|
||||
"sha256": "028df3f99e4033df3939c44a968e85f31f10f02bab3a08671d646fb65026d583"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/references/recipes-top.csv",
|
||||
"sha256": "2749b9d1e43bac9fe50d732526bedb19ba876180c4e1a6c96ac38a244981faaf"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/references/recipes-logging-common.csv",
|
||||
"sha256": "b0d975a8f0f7a15074b1a29c9eb9604e247add040a9c98465247c54d8ac5b424"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/scripts/categorize_recipes.py",
|
||||
"sha256": "b54ef626427183d6f03e02fb49a3ecd1cd44d72e12d2858e6399d57813fce357"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/scripts/upload-skill.sh",
|
||||
"sha256": "a8376ca001978a958fa456d03bf978998e31eb18424ffac9b4dd8fa8c3ee7585"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/scripts/create_curated_lists.py",
|
||||
"sha256": "7cd4840479afeaffbc0555aaf737180881fd7baa8a3a40412f16cdfe5015257c"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/assets/template-declarative-recipe.yml",
|
||||
"sha256": "a149b6067cf18e294b97491acc3ff69ef4583adf345e933743f64409185f67c2"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/assets/template-recipe-test.java",
|
||||
"sha256": "77761644a60fd635e9b9ea46f267fbd77cd3c1c538803be4e666889a192a7de7"
|
||||
},
|
||||
{
|
||||
"path": "skills/writing-openrewrite-recipes/assets/template-imperative-recipe.java",
|
||||
"sha256": "b8f6253d746ffd5375649b3ff1b5f44e8182702739c43702152186be05e9d0a2"
|
||||
}
|
||||
],
|
||||
"dirSha256": "049fc4cdd92369bce2da02fd52742233dd73d5cedbe66ac17a777f45a869e4bb"
|
||||
},
|
||||
"security": {
|
||||
"scannedAt": null,
|
||||
"scannerVersion": null,
|
||||
"flags": []
|
||||
}
|
||||
}
|
||||
462
skills/writing-openrewrite-recipes/SKILL.md
Normal file
462
skills/writing-openrewrite-recipes/SKILL.md
Normal file
@@ -0,0 +1,462 @@
|
||||
---
|
||||
name: writing-openrewrite-recipes
|
||||
description: Use when creating/writing/building OpenRewrite recipes, working with .java recipe files, RewriteTest files, recipe YAML files, LST visitors, JavaTemplate, visitor patterns, or when discussing recipe types (declarative YAML, Refaster templates, imperative Java recipes) - guides creation of OpenRewrite recipes for automated code transformations, AST manipulation, custom refactoring rules, and code migration.
|
||||
allowed-tools: Read, Write, Edit, Bash, Grep, Glob
|
||||
---
|
||||
|
||||
# OpenRewrite Recipe Writing Skill
|
||||
|
||||
## Overview
|
||||
|
||||
OpenRewrite recipes are automated refactoring operations that modify Lossless Semantic Trees (LSTs) representing source code. This skill guides through creating recipes efficiently and correctly.
|
||||
|
||||
## When NOT to Use This Skill
|
||||
|
||||
Do NOT use this skill for:
|
||||
- General Java programming questions unrelated to OpenRewrite
|
||||
- Questions about running existing OpenRewrite recipes (use OpenRewrite documentation)
|
||||
- Build tool configuration unrelated to recipe development
|
||||
- General refactoring advice without OpenRewrite context
|
||||
|
||||
## Quick Start Decision Tree
|
||||
|
||||
To determine the best approach quickly:
|
||||
|
||||
1. Can the transformation be expressed by composing existing recipes?
|
||||
→ **Use Declarative YAML** (see Declarative YAML Recipes section below)
|
||||
|
||||
2. Is it a simple expression/statement replacement pattern?
|
||||
→ **Use Refaster Template** (see Refaster Template Recipes section below)
|
||||
|
||||
3. Requires complex logic, conditional transformations, or custom analysis?
|
||||
→ **Use Imperative Java Recipe** (see Imperative Recipe Development Workflow below)
|
||||
|
||||
For imperative recipes, proceed to "Imperative Recipe Development Workflow" below.
|
||||
|
||||
## Recipe Type Selection
|
||||
|
||||
Choose the appropriate recipe type based on your needs:
|
||||
|
||||
### Declarative YAML Recipes (Preferred)
|
||||
|
||||
**Use when:** Composing existing recipes with configuration
|
||||
|
||||
**Advantages:** No code, simple, maintainable
|
||||
|
||||
**Example use case:** Combining framework migration steps
|
||||
|
||||
```yaml
|
||||
type: specs.openrewrite.org/v1beta/recipe
|
||||
name: com.yourorg.MyMigration
|
||||
displayName: Migrate to Framework X
|
||||
recipeList:
|
||||
- org.openrewrite.java.ChangeType:
|
||||
oldFullyQualifiedTypeName: old.Type
|
||||
newFullyQualifiedTypeName: new.Type
|
||||
- com.yourorg.OtherRecipe
|
||||
```
|
||||
|
||||
**Finding Recipes to Use:**
|
||||
When building declarative YAML recipes, consult the recipe catalog CSV files in the `references/` directory:
|
||||
|
||||
- `references/recipes-top.csv` - 50 commonly used recipes across all categories (best starting point)
|
||||
- `references/recipes-java-basic.csv` - 32 basic Java refactoring operations
|
||||
- `references/recipes-spring-boot-common.csv` - 60 Spring Boot migrations and best practices
|
||||
- `references/recipes-framework-migrations-common.csv` - 16 major framework migrations (diverse frameworks)
|
||||
- `references/recipes-testing-common.csv` - 60 most useful testing recipes (JUnit, Mockito, AssertJ)
|
||||
- `references/recipes-dependencies-common.csv` - 49 dependency operations (Maven+Gradle when possible)
|
||||
- `references/recipes-security-common.csv` - 30 security vulnerability detection and fixes
|
||||
- `references/recipes-xml-yaml-json-common.csv` - 50 configuration file operations
|
||||
- `references/recipes-static-analysis-common.csv` - 50 code analysis and search recipes
|
||||
- `references/recipes-logging-common.csv` - 50 logging framework operations
|
||||
- `references/recipes-file-operations.csv` - 14 file and text manipulation operations
|
||||
|
||||
**Usage Pattern:** Start with `recipes-top.csv`, then consult the specific category file based on what the user needs. These curated lists contain the most practical and commonly used recipes for each category.
|
||||
|
||||
### Refaster Template Recipes
|
||||
|
||||
**Use when:** Simple expression/statement replacements
|
||||
|
||||
**Advantages:** Faster than imperative, type-aware
|
||||
|
||||
**Example use case:** Replace `StringUtils.equals()` with `Objects.equals()`
|
||||
|
||||
### Imperative Java Recipes
|
||||
|
||||
**Use when:** Complex logic, conditional transformations, custom analysis
|
||||
|
||||
**Advantages:** Full control, complex transformations
|
||||
|
||||
**Example use case:** Add modifiers only to variables that aren't reassigned
|
||||
|
||||
**Decision Rule:** If it can be declarative, make it declarative. Use imperative only when necessary.
|
||||
|
||||
## Examples Quick Reference
|
||||
|
||||
Navigate to the right example based on your needs:
|
||||
|
||||
- **New to recipes?** Start with `references/example-say-hello-recipe.java`
|
||||
- **Need multi-file analysis?** See `references/example-scanning-recipe.java`
|
||||
- **Composing recipes?** Check `references/example-declarative-migration.yml`
|
||||
|
||||
## Imperative Recipe Development Workflow
|
||||
|
||||
### 1. Set Up Recipe Class
|
||||
|
||||
```java
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class YourRecipe extends Recipe {
|
||||
|
||||
@Option(displayName = "Display Name",
|
||||
description = "Clear description.",
|
||||
example = "com.example.Type")
|
||||
String parameterName;
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Your recipe name";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "What this recipe does.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public TreeVisitor<?, ExecutionContext> getVisitor() {
|
||||
return new YourVisitor();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Key Points:**
|
||||
|
||||
- Use `@Value` and `@EqualsAndHashCode(callSuper = false)` for immutability
|
||||
- Ensure all recipes are serializable
|
||||
- Define configurable parameters using `@Option` fields
|
||||
- Return a NEW instance from `getVisitor()` each time (no caching)
|
||||
|
||||
### 2. Implement the Visitor
|
||||
|
||||
```java
|
||||
public class YourVisitor extends JavaIsoVisitor<ExecutionContext> {
|
||||
|
||||
@Override
|
||||
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) {
|
||||
// ALWAYS call super to traverse the tree
|
||||
J.ClassDeclaration cd = super.visitClassDeclaration(classDecl, ctx);
|
||||
|
||||
// Check if change is needed (do no harm)
|
||||
if (!shouldChange(cd)) {
|
||||
return cd;
|
||||
}
|
||||
|
||||
// Make changes using JavaTemplate or LST methods
|
||||
cd = makeChanges(cd);
|
||||
|
||||
return cd;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Visitor Guidelines:**
|
||||
|
||||
- Use `JavaIsoVisitor` when returning the same type (most common)
|
||||
- Use `JavaVisitor` only when changing LST types
|
||||
- Call `super.visitX()` to traverse subtree in most cases. Omit the `super` call only when certain there could be no further edits below the current LST element
|
||||
- Return unchanged LST if no change needed (referential equality check)
|
||||
- Treat LSTs as immutable. Use `.withX()` methods for modifications
|
||||
|
||||
### 3. Use JavaTemplate for Complex Changes
|
||||
|
||||
```java
|
||||
private final JavaTemplate template = JavaTemplate
|
||||
.builder("public String hello() { return \"Hello from #{}!\"; }")
|
||||
.build();
|
||||
|
||||
// In visitor method:
|
||||
classDecl = template.apply(
|
||||
new Cursor(getCursor(), classDecl.getBody()),
|
||||
classDecl.getBody().getCoordinates().lastStatement(),
|
||||
fullyQualifiedClassName
|
||||
);
|
||||
```
|
||||
|
||||
**Template Tips:**
|
||||
|
||||
- Use `#{}` for string parameters
|
||||
- Use `#{any(Type)}` for typed LST elements
|
||||
- Declare imports: `.imports("java.util.List")`
|
||||
- Add classpath: `.javaParser(JavaParser.fromJavaVersion().classpath("library-name"))`
|
||||
- Prefer context-free templates (default) as they are faster
|
||||
- Use `.contextSensitive()` only when referencing local scope
|
||||
|
||||
### 4. Add Preconditions (Performance)
|
||||
|
||||
```java
|
||||
@Override
|
||||
public TreeVisitor<?, ExecutionContext> getVisitor() {
|
||||
return Preconditions.check(
|
||||
Preconditions.and(
|
||||
new UsesType<>("com.example.Type", true),
|
||||
new UsesJavaVersion<>(17)
|
||||
),
|
||||
new YourVisitor()
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**Benefits:** Limits recipe execution to relevant files only, improving performance
|
||||
|
||||
## Testing Recipes
|
||||
|
||||
### Test Structure
|
||||
|
||||
```java
|
||||
class YourRecipeTest implements RewriteTest {
|
||||
|
||||
@Override
|
||||
public void defaults(RecipeSpec spec) {
|
||||
spec.recipe(new YourRecipe("parameter-value"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void makesExpectedChange() {
|
||||
rewriteRun(
|
||||
//language=java
|
||||
java(
|
||||
// Before
|
||||
"""
|
||||
package com.example;
|
||||
class Before { }
|
||||
""",
|
||||
// After
|
||||
"""
|
||||
package com.example;
|
||||
class After { }
|
||||
"""
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotChangeWhenNotNeeded() {
|
||||
rewriteRun(
|
||||
//language=java
|
||||
java(
|
||||
"""
|
||||
package com.example;
|
||||
class AlreadyCorrect { }
|
||||
"""
|
||||
// No second argument = no change expected
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Notice how in Java template strings, the end `"""` delimiter is one indent to the right of the open delimiter. Java trims everything to the left of that same column.
|
||||
|
||||
**Testing Best Practices:**
|
||||
|
||||
- Test both changes AND no-changes cases
|
||||
- Test edge cases
|
||||
- Note that the test harness runs multiple cycles to ensure idempotence
|
||||
- Add `//language=XXX` comments to the highest level statement whose string arguments entirely consist of code snippets of that same language. This helps the IDE syntax highlight the test code
|
||||
|
||||
## ScanningRecipe Pattern
|
||||
|
||||
Use when you need to:
|
||||
|
||||
- See all files before making changes
|
||||
- Generate new files based on analysis
|
||||
- Share data across multiple files
|
||||
|
||||
```java
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class YourScanningRecipe extends ScanningRecipe<YourAccumulator> {
|
||||
|
||||
public static class YourAccumulator {
|
||||
Map<JavaProject, Boolean> projectData = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public YourAccumulator getInitialValue(ExecutionContext ctx) {
|
||||
return new YourAccumulator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TreeVisitor<?, ExecutionContext> getScanner(YourAccumulator acc) {
|
||||
return new JavaIsoVisitor<>() {
|
||||
@Override
|
||||
public J.CompilationUnit visitCompilationUnit(J.CompilationUnit cu, ExecutionContext ctx) {
|
||||
// Collect data into accumulator
|
||||
return cu;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public TreeVisitor<?, ExecutionContext> getVisitor(YourAccumulator acc) {
|
||||
return new JavaIsoVisitor<>() {
|
||||
@Override
|
||||
public J.CompilationUnit visitCompilationUnit(J.CompilationUnit cu, ExecutionContext ctx) {
|
||||
// Use data from accumulator to make changes
|
||||
return cu;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Critical Best Practices
|
||||
|
||||
### Do No Harm
|
||||
|
||||
- If unsure whether a change is safe, DON'T make it
|
||||
- Make minimal, least invasive changes
|
||||
- Respect existing formatting
|
||||
|
||||
### Immutability & Idempotence
|
||||
|
||||
- Recipes must be immutable (no mutable state)
|
||||
- Same input → same output, always
|
||||
- Use `@Value` and `@EqualsAndHashCode(callSuper = false)`
|
||||
- `getVisitor()` must return NEW instance
|
||||
|
||||
### Never Mutate LSTs
|
||||
|
||||
```java
|
||||
// WRONG
|
||||
method.getArguments().remove(0);
|
||||
|
||||
// CORRECT
|
||||
method.withArguments(ListUtils.map(method.getArguments(), (i, arg) ->
|
||||
i == 0 ? null : arg
|
||||
));
|
||||
```
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
- Display names: Sentence case, code in backticks, end with period
|
||||
- Example: "Change type from `OldType` to `NewType`."
|
||||
- Recipe names: `com.yourorg.VerbNoun` (e.g., `com.yourorg.ChangePackage`)
|
||||
|
||||
### State Management
|
||||
|
||||
- Within visitor: Use Cursor messaging (`getCursor().putMessage()`)
|
||||
- Between visitors: Use ScanningRecipe accumulator
|
||||
- Never use ExecutionContext for visitor state
|
||||
|
||||
### Multi-Module Projects
|
||||
|
||||
- Track per-project data: `Map<JavaProject, T>`
|
||||
- Don't assume single project per repository
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Adding Imports
|
||||
|
||||
```java
|
||||
maybeAddImport("java.util.List");
|
||||
maybeAddImport("java.util.Collections", "emptyList");
|
||||
```
|
||||
|
||||
### Removing Imports
|
||||
|
||||
```java
|
||||
maybeRemoveImport("old.package.Type");
|
||||
```
|
||||
|
||||
### Chaining Visitors
|
||||
|
||||
```java
|
||||
doAfterVisit(new OtherRecipe().getVisitor());
|
||||
```
|
||||
|
||||
### Checking Types
|
||||
|
||||
```java
|
||||
if (methodInvocation.getType() != null &&
|
||||
TypeUtils.isOfClassType(methodInvocation.getType(), "com.example.Type")) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
This skill includes several supporting files organized by purpose:
|
||||
|
||||
- **Templates** (`assets/`) - Files used as starting points for recipe development:
|
||||
|
||||
- `assets/template-imperative-recipe.java` - Boilerplate for imperative recipes
|
||||
- `assets/template-declarative-recipe.yml` - YAML recipe template
|
||||
- `assets/template-recipe-test.java` - Test class template
|
||||
|
||||
**Load when:** Creating a new recipe or needing a template to start from
|
||||
|
||||
- **Examples** (`references/`) - Reference documentation loaded as needed:
|
||||
|
||||
- `references/example-say-hello-recipe.java` - Complete working recipe with test and YAML usage
|
||||
- `references/example-scanning-recipe.java` - Advanced ScanningRecipe pattern for multi-file analysis
|
||||
- `references/example-declarative-migration.yml` - Real-world YAML migration examples
|
||||
|
||||
**Load when:** Needing to see a complete example, asking "show me an example", or understanding advanced patterns
|
||||
|
||||
- **Recipe Catalogs** (`references/`) - Curated lists for finding recipes when building declarative YAML recipes:
|
||||
- `references/recipes-top.csv` - 50 commonly used recipes (best starting point)
|
||||
- `references/recipes-java-basic.csv` - 32 basic Java refactoring operations
|
||||
- `references/recipes-spring-boot-common.csv` - 60 Spring Boot migrations and best practices
|
||||
- `references/recipes-framework-migrations-common.csv` - 16 major framework migrations (10 different frameworks)
|
||||
- `references/recipes-testing-common.csv` - 60 most useful testing recipes
|
||||
- `references/recipes-dependencies-common.csv` - 49 dependency operations (Maven+Gradle when possible)
|
||||
- `references/recipes-security-common.csv` - 30 security vulnerability recipes
|
||||
- `references/recipes-xml-yaml-json-common.csv` - 50 configuration file operations
|
||||
- `references/recipes-static-analysis-common.csv` - 50 code analysis recipes
|
||||
- `references/recipes-logging.csv` - 153 logging framework recipes
|
||||
- `references/recipes-file-operations.csv` - 14 file manipulation recipes
|
||||
- Note: `references/recipes-all.csv` exists for maintenance/script purposes but is too large (4,958 recipes) to be used directly
|
||||
|
||||
**Load when:** Looking for existing recipes
|
||||
|
||||
- **Checklist** (`references/`) - Verification guide:
|
||||
|
||||
- `references/checklist-recipe-development.md` - Comprehensive verification checklist covering planning, implementation, testing, and distribution
|
||||
|
||||
**Load when:** Reviewing a recipe for completeness, ensuring best practices, or preparing for distribution
|
||||
|
||||
- **Scripts** (`scripts/`) - Utility scripts:
|
||||
|
||||
- `scripts/upload-skill.sh` - Script to upload/update the skill via API
|
||||
|
||||
**Load when:** Managing the skill itself (meta-operation)
|
||||
|
||||
## Quick Reference
|
||||
|
||||
**Key Classes:**
|
||||
|
||||
- `Recipe` - Base class for all recipes
|
||||
- `JavaIsoVisitor<ExecutionContext>` - Most common visitor
|
||||
- `JavaTemplate` - For generating code snippets
|
||||
- `RewriteTest` - Testing interface
|
||||
- `ScanningRecipe<T>` - Multi-file analysis
|
||||
|
||||
**Key Methods:**
|
||||
|
||||
- `getVisitor()` - Returns visitor instance
|
||||
- `super.visitX()` - Traverse subtree
|
||||
- `.withX()` - Create modified LST copy
|
||||
- `ListUtils.map()` - Transform lists without mutation
|
||||
- `doAfterVisit()` - Chain additional visitors
|
||||
|
||||
**Use this skill for help with:**
|
||||
|
||||
- Choosing the right recipe type
|
||||
- Structuring recipe classes
|
||||
- Writing visitor logic
|
||||
- Using JavaTemplate
|
||||
- Writing tests
|
||||
- Debugging common issues
|
||||
- Understanding LST structure
|
||||
@@ -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
|
||||
@@ -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.YourRecipeName:
|
||||
* parameterName: value
|
||||
* ```
|
||||
*/
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class YourRecipeName 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 YourRecipeName(
|
||||
@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 YourRecipeVisitor()
|
||||
// );
|
||||
// }
|
||||
|
||||
@Override
|
||||
public TreeVisitor<?, ExecutionContext> getVisitor() {
|
||||
// IMPORTANT: Always return a NEW instance (no caching)
|
||||
return new YourRecipeVisitor();
|
||||
}
|
||||
|
||||
/**
|
||||
* The visitor implements the actual transformation logic.
|
||||
* Use JavaIsoVisitor when always returning the same LST type.
|
||||
*/
|
||||
public class YourRecipeVisitor 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;
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -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 YourRecipeName
|
||||
*
|
||||
* 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 YourRecipeNameTest 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 YourRecipeName("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 YourRecipeName("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.YourRecipeName")
|
||||
// .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
|
||||
// // """
|
||||
// // )
|
||||
// );
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
# OpenRewrite Recipe Development Checklist
|
||||
|
||||
Use this checklist to ensure you've covered all important aspects of recipe development.
|
||||
|
||||
## Contents
|
||||
- [Planning Phase](#planning-phase)
|
||||
- [Recipe Type Selection](#recipe-type-selection)
|
||||
- [Requirements Gathering](#requirements-gathering)
|
||||
- [Implementation Phase](#implementation-phase)
|
||||
- [Recipe Class Structure](#recipe-class-structure)
|
||||
- [Visitor Implementation](#visitor-implementation)
|
||||
- [JavaTemplate Usage](#javatemplate-usage)
|
||||
- [Advanced Features](#advanced-features)
|
||||
- [Imports and Dependencies](#imports-and-dependencies)
|
||||
- [Testing Phase](#testing-phase)
|
||||
- [Test Structure](#test-structure)
|
||||
- [Test Coverage](#test-coverage)
|
||||
- [Test Quality](#test-quality)
|
||||
- [Code Quality Phase](#code-quality-phase)
|
||||
- [Best Practices](#best-practices)
|
||||
- [Naming Conventions](#naming-conventions)
|
||||
- [Performance](#performance)
|
||||
- [Multi-Module Support](#multi-module-support)
|
||||
- [Documentation Phase](#documentation-phase)
|
||||
- [Code Documentation](#code-documentation)
|
||||
- [External Documentation](#external-documentation)
|
||||
- [Distribution Phase](#distribution-phase)
|
||||
- [Build Configuration](#build-configuration)
|
||||
- [Publishing](#publishing)
|
||||
- [Final Verification](#final-verification)
|
||||
- [Smoke Testing](#smoke-testing)
|
||||
- [Common Pitfalls Avoided](#common-pitfalls-avoided)
|
||||
- [Recipe-Specific Checklists](#recipe-specific-checklists)
|
||||
- [For Declarative Recipes](#for-declarative-recipes)
|
||||
- [For Refaster Template Recipes](#for-refaster-template-recipes)
|
||||
- [Notes](#notes)
|
||||
|
||||
## Planning Phase
|
||||
|
||||
### Recipe Type Selection
|
||||
- [ ] Determined if recipe can be declarative (preferred)
|
||||
- [ ] Evaluated if Refaster template would work for simple replacements
|
||||
- [ ] Confirmed imperative recipe is necessary for complex logic
|
||||
- [ ] Identified which LST elements need to be visited
|
||||
- [ ] Reviewed existing recipes to avoid duplication
|
||||
|
||||
### Requirements Gathering
|
||||
- [ ] Clearly defined what the recipe should change
|
||||
- [ ] Identified what should NOT be changed
|
||||
- [ ] Documented expected input and output
|
||||
- [ ] Listed any dependencies or external types needed
|
||||
- [ ] Determined if multi-file analysis is required (ScanningRecipe)
|
||||
|
||||
## Implementation Phase
|
||||
|
||||
### Recipe Class Structure
|
||||
- [ ] Used `@Value` and `@EqualsAndHashCode(callSuper = false)` for immutability
|
||||
- [ ] All fields are final (via Lombok or manual implementation)
|
||||
- [ ] Added `@JsonCreator` constructor with `@JsonProperty` annotations
|
||||
- [ ] Defined `@Option` fields with clear descriptions and examples
|
||||
- [ ] Implemented `getDisplayName()` with sentence-case name
|
||||
- [ ] Implemented `getDescription()` with clear, period-ending description
|
||||
- [ ] `getVisitor()` returns NEW instance (never cached)
|
||||
|
||||
### Visitor Implementation
|
||||
- [ ] Chose correct visitor type (JavaIsoVisitor vs JavaVisitor)
|
||||
- [ ] Called `super.visitX()` in overridden visit methods
|
||||
- [ ] Checked for null before accessing type information
|
||||
- [ ] Implemented "do no harm" - return unchanged LST when unsure
|
||||
- [ ] Used `.withX()` methods instead of mutating LSTs
|
||||
- [ ] Used `ListUtils` instead of stream operations on LST collections
|
||||
- [ ] Avoided creating new lists unnecessarily
|
||||
|
||||
### JavaTemplate Usage (if applicable)
|
||||
- [ ] Used typed substitution `#{any(Type)}` for LST elements
|
||||
- [ ] Used untyped substitution `#{}` for strings
|
||||
- [ ] Declared all imports with `.imports()`
|
||||
- [ ] Declared static imports with `.staticImports()`
|
||||
- [ ] Configured parser with `.javaParser()` if referencing external types
|
||||
- [ ] Added classpath dependencies or stubs as needed
|
||||
- [ ] Used context-free templates (default) when possible
|
||||
- [ ] Only used `.contextSensitive()` when necessary
|
||||
|
||||
### Advanced Features (if applicable)
|
||||
- [ ] Added preconditions with `Preconditions.check()`
|
||||
- [ ] Used `UsesType` or `UsesMethod` to filter applicable files
|
||||
- [ ] Implemented cursor messaging for intra-visitor communication
|
||||
- [ ] For ScanningRecipe: defined accumulator with `Map<JavaProject, T>`
|
||||
- [ ] For ScanningRecipe: implemented `getInitialValue()`
|
||||
- [ ] For ScanningRecipe: implemented `getScanner()` (no changes, only collect)
|
||||
- [ ] For ScanningRecipe: implemented `getVisitor()` (uses accumulator data)
|
||||
- [ ] For ScanningRecipe: implemented `generate()` if creating new files
|
||||
|
||||
### Imports and Dependencies
|
||||
- [ ] Used `maybeAddImport()` for new types
|
||||
- [ ] Used `maybeRemoveImport()` for removed types
|
||||
- [ ] Chained visitors with `doAfterVisit()` when needed
|
||||
|
||||
## Testing Phase
|
||||
|
||||
### Test Structure
|
||||
- [ ] Created test class implementing `RewriteTest`
|
||||
- [ ] Implemented `defaults(RecipeSpec)` with recipe configuration
|
||||
- [ ] Added `@DocumentExample` to primary test
|
||||
|
||||
### Test Coverage
|
||||
- [ ] Test for expected changes (before → after)
|
||||
- [ ] Test for no changes when not applicable (before only)
|
||||
- [ ] Test for edge cases and boundary conditions
|
||||
- [ ] Test with multiple files
|
||||
- [ ] Test that recipe doesn't change already-correct code
|
||||
- [ ] Test with different parameter values (if applicable)
|
||||
- [ ] Test with different Java versions (if version-specific)
|
||||
- [ ] Added classpath dependencies with `spec.parser()`
|
||||
|
||||
### Test Quality
|
||||
- [ ] Test names clearly describe what is being tested
|
||||
- [ ] Used meaningful package and class names in test code
|
||||
- [ ] Included comments explaining complex test scenarios
|
||||
- [ ] Verified tests pass (including multi-cycle verification)
|
||||
- [ ] Checked that recipe is idempotent (runs produce same result)
|
||||
|
||||
## Code Quality Phase
|
||||
|
||||
### Best Practices
|
||||
- [ ] Recipe follows "do no harm" principle
|
||||
- [ ] Recipe makes minimal, least invasive changes
|
||||
- [ ] Recipe is immutable (no mutable state)
|
||||
- [ ] Recipe is idempotent (same input → same output)
|
||||
- [ ] Recipe never mutates LSTs
|
||||
- [ ] Recipe respects existing formatting
|
||||
- [ ] Used referential equality checks (same object = no change)
|
||||
|
||||
### Naming Conventions
|
||||
- [ ] Display name uses sentence case
|
||||
- [ ] Display name uses backticks around code elements
|
||||
- [ ] Display name ends with period (if complete sentence)
|
||||
- [ ] Description is clear and concise
|
||||
- [ ] Recipe class name follows `VerbNoun` pattern
|
||||
- [ ] Package name follows `com.yourorg.category` pattern
|
||||
|
||||
### Performance
|
||||
- [ ] Added preconditions to skip irrelevant files
|
||||
- [ ] Used context-free JavaTemplates when possible
|
||||
- [ ] Avoided unnecessary LST allocations
|
||||
- [ ] Recipe completes work in single cycle (no `causesAnotherCycle`)
|
||||
- [ ] For ScanningRecipe: minimized accumulator size
|
||||
|
||||
### Multi-Module Support
|
||||
- [ ] For ScanningRecipe: tracked data per `JavaProject`
|
||||
- [ ] Did not assume single project per repository
|
||||
- [ ] Retrieved JavaProject from markers correctly
|
||||
|
||||
## Documentation Phase
|
||||
|
||||
### Code Documentation
|
||||
- [ ] Added class-level JavaDoc describing the recipe
|
||||
- [ ] Documented all `@Option` fields clearly
|
||||
- [ ] Added inline comments for complex logic
|
||||
- [ ] Included usage example in JavaDoc
|
||||
|
||||
### External Documentation
|
||||
- [ ] Created YAML file in `src/main/resources/META-INF/rewrite/` (if distributing)
|
||||
- [ ] Added recipe to catalog/index (if applicable)
|
||||
- [ ] Documented any known limitations
|
||||
- [ ] Added tags for categorization
|
||||
|
||||
## Distribution Phase
|
||||
|
||||
### Build Configuration
|
||||
- [ ] Recipe compiles with Java 8 target (or appropriate version)
|
||||
- [ ] Added `-parameters` compiler flag for Jackson
|
||||
- [ ] Included rewrite-recipe-bom for dependency management
|
||||
- [ ] Tests run successfully with build tool
|
||||
|
||||
### Publishing
|
||||
- [ ] Published to local Maven repository for testing (`publishToMavenLocal`)
|
||||
- [ ] Tested recipe in separate project
|
||||
- [ ] Configured publishing to artifact repository (if applicable)
|
||||
- [ ] Tagged release in version control
|
||||
|
||||
## Final Verification
|
||||
|
||||
### Smoke Testing
|
||||
- [ ] Ran recipe on sample project
|
||||
- [ ] Verified changes are correct
|
||||
- [ ] Verified no unwanted changes were made
|
||||
- [ ] Checked that formatting is preserved
|
||||
- [ ] Ran recipe multiple times (idempotence check)
|
||||
|
||||
### Common Pitfalls Avoided
|
||||
- [ ] Did not mutate LSTs directly
|
||||
- [ ] Did not cache visitor instances
|
||||
- [ ] Did not use ExecutionContext for visitor state
|
||||
- [ ] Did not forget to call `super.visitX()`
|
||||
- [ ] Did not create unnecessary list allocations
|
||||
- [ ] Did not forget imports in JavaTemplate
|
||||
- [ ] Did not skip null checks on type information
|
||||
- [ ] Did not assume single project per repository
|
||||
|
||||
## Recipe-Specific Checklists
|
||||
|
||||
### For Declarative Recipes
|
||||
- [ ] Saved in `src/main/resources/META-INF/rewrite/`
|
||||
- [ ] Used `type: specs.openrewrite.org/v1beta/recipe`
|
||||
- [ ] All recipe names are fully qualified
|
||||
- [ ] All parameters are correctly indented
|
||||
- [ ] String values with special characters are quoted
|
||||
- [ ] Recipe list is in logical order
|
||||
- [ ] Tested with `spec.recipeFromResources()`
|
||||
|
||||
### For Refaster Template Recipes
|
||||
- [ ] Created template class with `@RecipeDescriptor`
|
||||
- [ ] Implemented `@BeforeTemplate` methods
|
||||
- [ ] Implemented single `@AfterTemplate` method
|
||||
- [ ] Verified generated recipe works correctly
|
||||
- [ ] Recipe name uses generated form (e.g., `RecipesName`)
|
||||
|
||||
## Notes
|
||||
|
||||
Remember:
|
||||
- **Do no harm**: If unsure, don't change
|
||||
- **Minimize changes**: Make only necessary modifications
|
||||
- **Immutability**: Recipes and LSTs must not be mutated
|
||||
- **Test thoroughly**: Both positive and negative cases
|
||||
- **Document clearly**: Future maintainers will thank you
|
||||
|
||||
For more information, see:
|
||||
- SKILL.md in this skill directory
|
||||
- OpenRewrite documentation in this repository
|
||||
- Examples in examples/ directory
|
||||
@@ -0,0 +1,257 @@
|
||||
---
|
||||
# ==============================================================================
|
||||
# Example: Framework Migration Recipe
|
||||
# ==============================================================================
|
||||
# This example demonstrates a realistic declarative recipe for migrating
|
||||
# from one version of a framework to another, combining multiple recipes
|
||||
# with configuration.
|
||||
#
|
||||
# Save this file in: src/main/resources/META-INF/rewrite/
|
||||
|
||||
type: specs.openrewrite.org/v1beta/recipe
|
||||
name: com.yourorg.MigrateToFrameworkX
|
||||
displayName: Migrate to Framework X 2.0
|
||||
description: |
|
||||
Migrates applications from Framework X 1.x to 2.0. This recipe performs the following steps:
|
||||
- Updates dependency versions
|
||||
- Migrates renamed packages and types
|
||||
- Updates deprecated API usage
|
||||
- Applies code formatting
|
||||
tags:
|
||||
- framework-x
|
||||
- migration
|
||||
- upgrade
|
||||
estimatedEffortPerOccurrence: PT15M
|
||||
|
||||
recipeList:
|
||||
# Step 1: Update dependencies
|
||||
- org.openrewrite.java.dependencies.ChangeDependency:
|
||||
oldGroupId: com.example.frameworkx
|
||||
oldArtifactId: frameworkx-core
|
||||
newGroupId: com.example.frameworkx
|
||||
newArtifactId: frameworkx-core
|
||||
newVersion: 2.0.x
|
||||
|
||||
- org.openrewrite.java.dependencies.AddDependency:
|
||||
groupId: com.example.frameworkx
|
||||
artifactId: frameworkx-new-module
|
||||
version: 2.0.x
|
||||
onlyIfUsing: com.example.frameworkx.NewFeature
|
||||
configuration: implementation
|
||||
|
||||
# Step 2: Package and type migrations
|
||||
- org.openrewrite.java.ChangePackage:
|
||||
oldPackageName: com.example.frameworkx.old
|
||||
newPackageName: com.example.frameworkx.v2
|
||||
recursive: true
|
||||
|
||||
- org.openrewrite.java.ChangeType:
|
||||
oldFullyQualifiedTypeName: com.example.frameworkx.OldConfig
|
||||
newFullyQualifiedTypeName: com.example.frameworkx.v2.NewConfig
|
||||
|
||||
- org.openrewrite.java.ChangeType:
|
||||
oldFullyQualifiedTypeName: com.example.frameworkx.OldClient
|
||||
newFullyQualifiedTypeName: com.example.frameworkx.v2.Client
|
||||
|
||||
# Step 3: Method migrations
|
||||
- org.openrewrite.java.ChangeMethodName:
|
||||
methodPattern: com.example.frameworkx.v2.Client execute(..)
|
||||
newMethodName: run
|
||||
|
||||
# Step 4: Apply custom recipes (if you have any)
|
||||
# - com.yourorg.CustomFrameworkXMigration
|
||||
|
||||
# Step 5: Format the code
|
||||
- org.openrewrite.java.format.AutoFormat
|
||||
|
||||
---
|
||||
# ==============================================================================
|
||||
# Example: Security Fixes Recipe
|
||||
# ==============================================================================
|
||||
# This recipe applies common security fixes across a codebase
|
||||
|
||||
type: specs.openrewrite.org/v1beta/recipe
|
||||
name: com.yourorg.ApplySecurityFixes
|
||||
displayName: Apply security best practices
|
||||
description: Applies a collection of security-related fixes and improvements to the codebase.
|
||||
tags:
|
||||
- security
|
||||
- SAST
|
||||
|
||||
recipeList:
|
||||
# Use secure random number generation
|
||||
- org.openrewrite.java.security.SecureRandom
|
||||
|
||||
# Fix SQL injection vulnerabilities
|
||||
- org.openrewrite.java.security.UseFileCreateTempFile
|
||||
|
||||
# Apply static analysis security fixes
|
||||
- org.openrewrite.staticanalysis.CommonStaticAnalysis
|
||||
|
||||
# Remove unused imports
|
||||
- org.openrewrite.java.format.RemoveUnusedImports
|
||||
|
||||
---
|
||||
# ==============================================================================
|
||||
# Example: Testing Framework Migration
|
||||
# ==============================================================================
|
||||
# Migrates from JUnit 4 to JUnit 5
|
||||
|
||||
type: specs.openrewrite.org/v1beta/recipe
|
||||
name: com.yourorg.MigrateToJUnit5
|
||||
displayName: Migrate to JUnit 5
|
||||
description: Migrates JUnit 4 tests to JUnit 5 (Jupiter).
|
||||
tags:
|
||||
- junit
|
||||
- testing
|
||||
- junit5
|
||||
|
||||
preconditions:
|
||||
- org.openrewrite.java.search.UsesType:
|
||||
fullyQualifiedTypeName: org.junit.Test
|
||||
|
||||
recipeList:
|
||||
# Update dependencies
|
||||
- org.openrewrite.java.dependencies.RemoveDependency:
|
||||
groupId: junit
|
||||
artifactId: junit
|
||||
|
||||
- org.openrewrite.java.dependencies.AddDependency:
|
||||
groupId: org.junit.jupiter
|
||||
artifactId: junit-jupiter
|
||||
version: 5.9.x
|
||||
onlyIfUsing: org.junit.Test
|
||||
configuration: testImplementation
|
||||
|
||||
# Migrate annotations and assertions
|
||||
- org.openrewrite.java.testing.junit5.JUnit4to5Migration
|
||||
|
||||
# Format
|
||||
- org.openrewrite.java.format.AutoFormat
|
||||
|
||||
---
|
||||
# ==============================================================================
|
||||
# Example: Code Quality Improvements
|
||||
# ==============================================================================
|
||||
# A collection of code quality improvements
|
||||
|
||||
type: specs.openrewrite.org/v1beta/recipe
|
||||
name: com.yourorg.ImproveCodeQuality
|
||||
displayName: Improve code quality
|
||||
description: Applies a comprehensive set of code quality improvements.
|
||||
tags:
|
||||
- code-quality
|
||||
- refactoring
|
||||
- best-practices
|
||||
|
||||
recipeList:
|
||||
# Static analysis
|
||||
- org.openrewrite.staticanalysis.CommonStaticAnalysis
|
||||
|
||||
# Finalize local variables that aren't reassigned
|
||||
- org.openrewrite.staticanalysis.FinalizeLocalVariables
|
||||
|
||||
# Add missing @Override annotations
|
||||
- org.openrewrite.staticanalysis.MissingOverrideAnnotation
|
||||
|
||||
# Simplify boolean expressions
|
||||
- org.openrewrite.staticanalysis.SimplifyBooleanExpression
|
||||
|
||||
# Remove unnecessary null checks
|
||||
- org.openrewrite.staticanalysis.UnnecessaryNullCheckBeforeInstanceOf
|
||||
|
||||
# Format code
|
||||
- org.openrewrite.java.format.AutoFormat
|
||||
|
||||
---
|
||||
# ==============================================================================
|
||||
# Example: Simple Type Replacement
|
||||
# ==============================================================================
|
||||
# A focused recipe that just replaces one type with another
|
||||
|
||||
type: specs.openrewrite.org/v1beta/recipe
|
||||
name: com.yourorg.ReplaceStringUtils
|
||||
displayName: Replace Apache Commons StringUtils with Spring StringUtils
|
||||
description: Replaces usage of Apache Commons StringUtils with Spring Framework's StringUtils.
|
||||
|
||||
recipeList:
|
||||
- org.openrewrite.java.ChangeType:
|
||||
oldFullyQualifiedTypeName: org.apache.commons.lang3.StringUtils
|
||||
newFullyQualifiedTypeName: org.springframework.util.StringUtils
|
||||
|
||||
- org.openrewrite.java.dependencies.AddDependency:
|
||||
groupId: org.springframework
|
||||
artifactId: spring-core
|
||||
version: 6.0.x
|
||||
onlyIfUsing: org.springframework.util.StringUtils
|
||||
configuration: implementation
|
||||
|
||||
---
|
||||
# ==============================================================================
|
||||
# TEST EXAMPLE
|
||||
# ==============================================================================
|
||||
# Here's how to test a declarative recipe:
|
||||
#
|
||||
# ```java
|
||||
# package com.yourorg;
|
||||
#
|
||||
# import org.junit.jupiter.api.Test;
|
||||
# import org.openrewrite.java.JavaParser;
|
||||
# import org.openrewrite.test.RecipeSpec;
|
||||
# import org.openrewrite.test.RewriteTest;
|
||||
#
|
||||
# import static org.openrewrite.java.Assertions.java;
|
||||
#
|
||||
# class MigrateToFrameworkXTest implements RewriteTest {
|
||||
#
|
||||
# @Override
|
||||
# public void defaults(RecipeSpec spec) {
|
||||
# spec
|
||||
# // Load the recipe from resources
|
||||
# .recipeFromResources("com.yourorg.MigrateToFrameworkX")
|
||||
# // Add dependencies needed to compile the "before" code
|
||||
# .parser(JavaParser.fromJavaVersion()
|
||||
# .classpath("frameworkx-core-1.0"));
|
||||
# }
|
||||
#
|
||||
# @Test
|
||||
# void migratesFrameworkXCode() {
|
||||
# rewriteRun(
|
||||
# java(
|
||||
# """
|
||||
# package com.example;
|
||||
#
|
||||
# import com.example.frameworkx.old.OldConfig;
|
||||
#
|
||||
# class Example {
|
||||
# OldConfig config;
|
||||
# }
|
||||
# """,
|
||||
# """
|
||||
# package com.example;
|
||||
#
|
||||
# import com.example.frameworkx.v2.NewConfig;
|
||||
#
|
||||
# class Example {
|
||||
# NewConfig config;
|
||||
# }
|
||||
# """
|
||||
# )
|
||||
# );
|
||||
# }
|
||||
# }
|
||||
# ```
|
||||
|
||||
# ==============================================================================
|
||||
# TIPS FOR DECLARATIVE RECIPES
|
||||
# ==============================================================================
|
||||
# 1. Keep them focused - one migration or fix per recipe
|
||||
# 2. Use meaningful names that describe what the recipe does
|
||||
# 3. Document the purpose and steps in the description
|
||||
# 4. Add tags for searchability
|
||||
# 5. Use preconditions to avoid running on irrelevant files
|
||||
# 6. Order matters - recipes run sequentially
|
||||
# 7. Consider adding AutoFormat at the end
|
||||
# 8. Test each recipe thoroughly
|
||||
# 9. Wrap string values in quotes if they contain special characters
|
||||
# 10. Use estimatedEffortPerOccurrence to help users understand the impact
|
||||
@@ -0,0 +1,186 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* A simple recipe that adds a hello() method to a specified class.
|
||||
*
|
||||
* This example demonstrates:
|
||||
* - Basic recipe structure with @Value and @EqualsAndHashCode
|
||||
* - Using @Option for configurable parameters
|
||||
* - Using JavaTemplate for code generation
|
||||
* - Checking preconditions before making changes
|
||||
* - Following the "do no harm" principle
|
||||
*
|
||||
* Based on the official OpenRewrite tutorial:
|
||||
* https://docs.openrewrite.org/authoring-recipes/writing-a-java-refactoring-recipe
|
||||
*/
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class SayHelloRecipe extends Recipe {
|
||||
|
||||
@Option(
|
||||
displayName = "Fully Qualified Class Name",
|
||||
description = "A fully qualified class name indicating which class to add a hello() method to.",
|
||||
example = "com.yourorg.FooBar"
|
||||
)
|
||||
@NonNull
|
||||
String fullyQualifiedClassName;
|
||||
|
||||
@JsonCreator
|
||||
public SayHelloRecipe(@NonNull @JsonProperty("fullyQualifiedClassName") String fullyQualifiedClassName) {
|
||||
this.fullyQualifiedClassName = fullyQualifiedClassName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Say 'Hello'";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Adds a \"hello\" method to the specified class.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public TreeVisitor<?, ExecutionContext> getVisitor() {
|
||||
// Always return a new instance - never cache visitors
|
||||
return new JavaIsoVisitor<ExecutionContext>() {
|
||||
|
||||
@Override
|
||||
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) {
|
||||
// Step 1: Traverse the subtree first
|
||||
J.ClassDeclaration cd = super.visitClassDeclaration(classDecl, ctx);
|
||||
|
||||
// Step 2: Check if this is the class we're looking for
|
||||
// Do no harm: return unchanged if this isn't the target class
|
||||
if (cd.getType() == null || !cd.getType().getFullyQualifiedName().equals(fullyQualifiedClassName)) {
|
||||
return cd;
|
||||
}
|
||||
|
||||
// Step 3: Check if the class already has a hello() method
|
||||
// Do no harm: don't add if it already exists
|
||||
boolean helloMethodExists = cd.getBody().getStatements().stream()
|
||||
.filter(statement -> statement instanceof J.MethodDeclaration)
|
||||
.map(J.MethodDeclaration.class::cast)
|
||||
.anyMatch(methodDeclaration -> "hello".equals(methodDeclaration.getName().getSimpleName()));
|
||||
|
||||
if (helloMethodExists) {
|
||||
return cd;
|
||||
}
|
||||
|
||||
// Step 4: Add the hello() method using JavaTemplate
|
||||
// The template uses #{} for parameter substitution
|
||||
J.Block body = JavaTemplate.apply(
|
||||
"public String hello() { return \"Hello from #{}!\"; }",
|
||||
new Cursor(getCursor(), cd.getBody()),
|
||||
cd.getBody().getCoordinates().lastStatement(),
|
||||
fullyQualifiedClassName
|
||||
);
|
||||
|
||||
return cd.withBody(body);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// TEST CLASS
|
||||
// ============================================================
|
||||
|
||||
/*
|
||||
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;
|
||||
|
||||
class SayHelloRecipeTest implements RewriteTest {
|
||||
|
||||
@Override
|
||||
public void defaults(RecipeSpec spec) {
|
||||
spec.recipe(new SayHelloRecipe("com.yourorg.FooBar"));
|
||||
}
|
||||
|
||||
@DocumentExample
|
||||
@Test
|
||||
void addsHelloToFooBar() {
|
||||
rewriteRun(
|
||||
java(
|
||||
"""
|
||||
package com.yourorg;
|
||||
|
||||
class FooBar {
|
||||
}
|
||||
""",
|
||||
"""
|
||||
package com.yourorg;
|
||||
|
||||
class FooBar {
|
||||
public String hello() {
|
||||
return "Hello from com.yourorg.FooBar!";
|
||||
}
|
||||
}
|
||||
"""
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotChangeExistingHello() {
|
||||
rewriteRun(
|
||||
java(
|
||||
"""
|
||||
package com.yourorg;
|
||||
|
||||
class FooBar {
|
||||
public String hello() { return ""; }
|
||||
}
|
||||
"""
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotChangeOtherClasses() {
|
||||
rewriteRun(
|
||||
java(
|
||||
"""
|
||||
package com.yourorg;
|
||||
|
||||
class OtherClass {
|
||||
}
|
||||
"""
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// ============================================================
|
||||
// YAML USAGE
|
||||
// ============================================================
|
||||
|
||||
/*
|
||||
Save this in src/main/resources/META-INF/rewrite/say-hello.yml:
|
||||
|
||||
---
|
||||
type: specs.openrewrite.org/v1beta/recipe
|
||||
name: com.yourorg.SayHelloToFooBar
|
||||
displayName: Say Hello to FooBar
|
||||
description: Adds a hello() method to the FooBar class.
|
||||
recipeList:
|
||||
- com.yourorg.SayHelloRecipe:
|
||||
fullyQualifiedClassName: com.yourorg.FooBar
|
||||
*/
|
||||
@@ -0,0 +1,294 @@
|
||||
package com.yourorg;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
import org.openrewrite.*;
|
||||
import org.openrewrite.java.JavaIsoVisitor;
|
||||
import org.openrewrite.java.tree.J;
|
||||
import org.openrewrite.marker.SearchResult;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A ScanningRecipe that marks classes only if the project uses a specific type.
|
||||
*
|
||||
* This example demonstrates:
|
||||
* - ScanningRecipe with accumulator pattern
|
||||
* - Three-phase execution: scan, generate (optional), edit
|
||||
* - Tracking per-project information with Map<JavaProject, T>
|
||||
* - Using accumulator data to inform editing decisions
|
||||
* - Proper handling of multi-module projects
|
||||
*
|
||||
* Use ScanningRecipe when you need to:
|
||||
* - See all files before making changes
|
||||
* - Generate new files based on analysis
|
||||
* - Share data across multiple files
|
||||
* - Make decisions based on project-wide information
|
||||
*/
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class ScanningRecipeExample extends ScanningRecipe<ScanningRecipeExample.Accumulator> {
|
||||
|
||||
/**
|
||||
* The accumulator stores data collected during the scanning phase.
|
||||
* This data is then available during the editing phase.
|
||||
*
|
||||
* Important: For multi-module projects, track data per JavaProject.
|
||||
*/
|
||||
public static class Accumulator {
|
||||
// Track which projects use the target type
|
||||
Map<JavaProject, Boolean> projectUsesTargetType = new HashMap<>();
|
||||
|
||||
// You can store any data structure you need
|
||||
// Map<JavaProject, Set<String>> projectClasses = new HashMap<>();
|
||||
// Map<JavaProject, List<MethodInfo>> projectMethods = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Mark classes in projects using target type";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Marks classes with SearchResult only if the project uses a specific type.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the accumulator before scanning begins.
|
||||
*/
|
||||
@Override
|
||||
public Accumulator getInitialValue(ExecutionContext ctx) {
|
||||
return new Accumulator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Phase 1: SCANNING
|
||||
*
|
||||
* The scanner visits all source files and collects information
|
||||
* into the accumulator. No changes are made in this phase.
|
||||
*/
|
||||
@Override
|
||||
public TreeVisitor<?, ExecutionContext> getScanner(Accumulator acc) {
|
||||
return new JavaIsoVisitor<ExecutionContext>() {
|
||||
|
||||
@Override
|
||||
public J.CompilationUnit visitCompilationUnit(J.CompilationUnit cu, ExecutionContext ctx) {
|
||||
// Get the JavaProject marker to track per-project data
|
||||
JavaProject project = cu.getMarkers().findFirst(JavaProject.class).orElse(null);
|
||||
if (project == null) {
|
||||
return cu;
|
||||
}
|
||||
|
||||
// Initialize project tracking if needed
|
||||
acc.projectUsesTargetType.putIfAbsent(project, false);
|
||||
|
||||
// Scan for the target type in this file
|
||||
// In this example, we're looking for usage of java.util.Optional
|
||||
cu.getImports().stream()
|
||||
.filter(imp -> imp.getTypeName().equals("java.util.Optional"))
|
||||
.findFirst()
|
||||
.ifPresent(imp -> acc.projectUsesTargetType.put(project, true));
|
||||
|
||||
// Continue scanning subtree
|
||||
return super.visitCompilationUnit(cu, ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public J.Import visitImport(J.Import import_, ExecutionContext ctx) {
|
||||
// You can also scan at finer granularity
|
||||
// Example: track specific imports, method calls, etc.
|
||||
return import_;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Phase 2: GENERATING (optional)
|
||||
*
|
||||
* This phase is used to generate new source files based on the
|
||||
* accumulated data. Return null if no new files are needed.
|
||||
*
|
||||
* Uncomment to implement:
|
||||
*/
|
||||
/*
|
||||
@Override
|
||||
public Collection<SourceFile> generate(Accumulator acc, ExecutionContext ctx) {
|
||||
List<SourceFile> newFiles = new ArrayList<>();
|
||||
|
||||
// Example: Generate a file for each project that uses the target type
|
||||
for (Map.Entry<JavaProject, Boolean> entry : acc.projectUsesTargetType.entrySet()) {
|
||||
if (entry.getValue()) {
|
||||
JavaProject project = entry.getKey();
|
||||
// Create a new source file
|
||||
// newFiles.add(createNewFile(project));
|
||||
}
|
||||
}
|
||||
|
||||
return newFiles;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Phase 3: EDITING
|
||||
*
|
||||
* The editor visits all source files again and makes changes
|
||||
* based on the data collected in the scanning phase.
|
||||
*/
|
||||
@Override
|
||||
public TreeVisitor<?, ExecutionContext> getVisitor(Accumulator acc) {
|
||||
return new JavaIsoVisitor<ExecutionContext>() {
|
||||
|
||||
@Override
|
||||
public J.CompilationUnit visitCompilationUnit(J.CompilationUnit cu, ExecutionContext ctx) {
|
||||
// Get the project for this file
|
||||
JavaProject project = cu.getMarkers().findFirst(JavaProject.class).orElse(null);
|
||||
if (project == null) {
|
||||
return cu;
|
||||
}
|
||||
|
||||
// Check the accumulator to see if this project uses the target type
|
||||
Boolean usesTargetType = acc.projectUsesTargetType.get(project);
|
||||
if (usesTargetType == null || !usesTargetType) {
|
||||
// Don't make changes in projects that don't use the target type
|
||||
return cu;
|
||||
}
|
||||
|
||||
// This project uses the target type, continue with editing
|
||||
return super.visitCompilationUnit(cu, ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) {
|
||||
J.ClassDeclaration cd = super.visitClassDeclaration(classDecl, ctx);
|
||||
|
||||
// Get the project
|
||||
JavaProject project = getCursor()
|
||||
.firstEnclosing(J.CompilationUnit.class)
|
||||
.getMarkers()
|
||||
.findFirst(JavaProject.class)
|
||||
.orElse(null);
|
||||
|
||||
if (project == null) {
|
||||
return cd;
|
||||
}
|
||||
|
||||
// Only mark classes in projects that use the target type
|
||||
Boolean usesTargetType = acc.projectUsesTargetType.get(project);
|
||||
if (usesTargetType != null && usesTargetType) {
|
||||
// Mark this class with a SearchResult
|
||||
return SearchResult.found(cd, "Found in project using Optional");
|
||||
}
|
||||
|
||||
return cd;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// SIMPLIFIED EXAMPLE: COUNT CLASSES
|
||||
// ============================================================
|
||||
|
||||
/*
|
||||
Here's a simpler ScanningRecipe that counts classes per project:
|
||||
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class CountClasses extends ScanningRecipe<CountClasses.Accumulator> {
|
||||
|
||||
public static class Accumulator {
|
||||
Map<JavaProject, Integer> classCounts = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Count classes per project";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Counts the number of classes in each project.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Accumulator getInitialValue(ExecutionContext ctx) {
|
||||
return new Accumulator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TreeVisitor<?, ExecutionContext> getScanner(Accumulator acc) {
|
||||
return new JavaIsoVisitor<ExecutionContext>() {
|
||||
@Override
|
||||
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration cd, ExecutionContext ctx) {
|
||||
JavaProject project = getCursor()
|
||||
.firstEnclosing(J.CompilationUnit.class)
|
||||
.getMarkers()
|
||||
.findFirst(JavaProject.class)
|
||||
.orElse(null);
|
||||
|
||||
if (project != null) {
|
||||
acc.classCounts.merge(project, 1, Integer::sum);
|
||||
}
|
||||
|
||||
return cd;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public TreeVisitor<?, ExecutionContext> getVisitor(Accumulator acc) {
|
||||
// Print the results
|
||||
return new JavaIsoVisitor<ExecutionContext>() {
|
||||
private boolean printed = false;
|
||||
|
||||
@Override
|
||||
public J.CompilationUnit visitCompilationUnit(J.CompilationUnit cu, ExecutionContext ctx) {
|
||||
if (!printed) {
|
||||
System.out.println("Class counts by project:");
|
||||
acc.classCounts.forEach((project, count) ->
|
||||
System.out.println(project.getProjectName() + ": " + count + " classes")
|
||||
);
|
||||
printed = true;
|
||||
}
|
||||
return cu;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// ============================================================
|
||||
// KEY TAKEAWAYS
|
||||
// ============================================================
|
||||
|
||||
/*
|
||||
1. ScanningRecipe has THREE phases:
|
||||
- Scan: Collect data (no changes)
|
||||
- Generate: Create new files (optional)
|
||||
- Edit: Make changes based on collected data
|
||||
|
||||
2. Always track per-project data with Map<JavaProject, T>
|
||||
- Don't assume single project per repository
|
||||
- Get JavaProject from markers
|
||||
|
||||
3. Accumulator is shared across all phases
|
||||
- Use it to pass data from scan to edit
|
||||
- Keep it simple and focused
|
||||
|
||||
4. Scanner makes NO changes
|
||||
- Only collect information
|
||||
- Mark files or store data
|
||||
|
||||
5. Editor uses accumulator data
|
||||
- Make informed decisions
|
||||
- Can access all collected information
|
||||
|
||||
6. When multiple ScanningRecipes are in a recipe list:
|
||||
- All scanners run first
|
||||
- Then all generators run
|
||||
- Then all editors run
|
||||
- Scanners see state before ANY edits
|
||||
- But scanners DO see generated files
|
||||
*/
|
||||
4958
skills/writing-openrewrite-recipes/references/recipes-all.csv
Normal file
4958
skills/writing-openrewrite-recipes/references/recipes-all.csv
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,50 @@
|
||||
Fully Qualified Recipe Name,Recipe Name,Description
|
||||
org.openrewrite.java.dependencies.ChangeDependency,Change Gradle or Maven dependency,Change the group ID artifact ID and/or the version of a specified Gradle or Maven dependency.
|
||||
org.openrewrite.java.dependencies.DependencyInsight,Dependency insight for Gradle and Maven,Finds dependencies including transitive dependencies in both Gradle and Maven projects. Matches within all Gradle dependency configurations and Maven scopes.
|
||||
org.openrewrite.java.dependencies.DependencyList,Dependency report,Emits a data table detailing all Gradle and Maven dependencies. This recipe makes no changes to any source file.
|
||||
org.openrewrite.java.dependencies.FindDependency,Find Maven and Gradle dependencies,Finds direct dependencies declared in Maven and Gradle build files. This does *not* search transitive dependencies. To detect both direct and transitive dependencies use `org.openrewrite.java.dependencies.DependencyInsight` This recipe works for both Maven and Gradle projects.
|
||||
org.openrewrite.java.dependencies.search.DoesNotIncludeDependency,Does not include dependency for Gradle and Maven,A precondition which returns false if visiting a Gradle file / Maven pom which includes the specified dependency in the classpath of some Gradle configuration / Maven scope. For compatibility with multimodule projects this should most often be applied as a precondition.
|
||||
org.openrewrite.java.dependencies.AddDependency,Add Gradle or Maven dependency,For a Gradle project add a gradle dependency to a `build.gradle` file in the correct configuration based on where it is used. Or For a maven project Add a Maven dependency to a `pom.xml` file in the correct scope based on where it is used.
|
||||
org.openrewrite.java.dependencies.DependencyResolutionDiagnostic,Dependency resolution diagnostic,Recipes which manipulate dependencies must be able to successfully access the artifact repositories and resolve dependencies from them. This recipe produces two data tables used to understand the state of dependency resolution. The Repository accessibility report lists all the artifact repositories known to the project and whether respond to network access. The network access is attempted while the recipe is run and so is representative of current conditions. The Gradle dependency configuration errors lists all the dependency configurations that failed to resolve one or more dependencies when the project was parsed. This is representative of conditions at the time the LST was parsed.
|
||||
org.openrewrite.java.dependencies.RelocatedDependencyCheck,Find relocated dependencies,Find Maven and Gradle dependencies and Maven plugins that have relocated to a new `groupId` or `artifactId`. Relocation information comes from the [oga-maven-plugin](https://github.com/jonathanlermitage/oga-maven-plugin/) maintained by Jonathan Lermitage Filipe Roque and others. This recipe makes no changes to any source file by default. Add `changeDependencies=true` to change dependencies but note that you might need to run additional recipes to update imports and adopt other breaking changes.
|
||||
org.openrewrite.java.dependencies.RemoveDependency,Remove a Gradle or Maven dependency,For Gradle project removes a single dependency from the dependencies section of the `build.gradle`. For Maven project removes a single dependency from the `<dependencies>` section of the pom.xml.
|
||||
org.openrewrite.java.dependencies.UpgradeDependencyVersion,Upgrade Gradle or Maven dependency versions,"For Gradle projects upgrade the version of a dependency in a `build.gradle` file. Supports updating dependency declarations of various forms: * `String` notation: `""group:artifact:version""` * `Map` notation: `group: 'group' name: 'artifact' version: 'version'` It is possible to update version numbers which are defined earlier in the same file in variable declarations. For Maven projects upgrade the version of a dependency by specifying a group ID and (optionally) an artifact ID using Node Semver advanced range selectors allowing more precise control over version updates to patch or minor releases."
|
||||
org.openrewrite.java.dependencies.UpgradeTransitiveDependencyVersion,Upgrade transitive Gradle or Maven dependencies,Upgrades the version of a transitive dependency in a Maven pom.xml or Gradle build.gradle. Leaves direct dependencies unmodified. Can be paired with the regular Upgrade Dependency Version recipe to upgrade a dependency everywhere regardless of whether it is direct or transitive.
|
||||
org.openrewrite.java.dependencies.search.FindMinimumDependencyVersion,Find the oldest matching dependency version in use,The oldest dependency version in use is the lowest dependency version in use in any source set of any subproject of a repository. It is possible that for example the main source set of a project uses Jackson 2.11 but a test source set uses Jackson 2.16. In this case the oldest Jackson version in use is Java 2.11.
|
||||
org.openrewrite.java.dependencies.search.ModuleHasDependency,Module has dependency,Searches for both Gradle and Maven modules that have a dependency matching the specified groupId and artifactId. Places a `SearchResult` marker on all sources within a module with a matching dependency. This recipe is intended to be used as a precondition for other recipes. For example this could be used to limit the application of a spring boot migration to only projects that use spring-boot-starter limiting unnecessary upgrading. If the search result you want is instead just the build.gradle(.kts) or pom.xml file applying the plugin use the `FindDependency` recipe instead.
|
||||
org.openrewrite.java.dependencies.search.RepositoryHasDependency,Repository has dependency,Searches for both Gradle and Maven modules that have a dependency matching the specified groupId and artifactId. Places a `SearchResult` marker on all sources within a repository with a matching dependency. This recipe is intended to be used as a precondition for other recipes. For example this could be used to limit the application of a spring boot migration to only projects that use a springframework dependency limiting unnecessary upgrading. If the search result you want is instead just the build.gradle(.kts) or pom.xml file applying the plugin use the `FindDependency` recipe instead.
|
||||
org.openrewrite.java.dependencies.DependencyLicenseCheck,Find licenses in use in third-party dependencies,Locates and reports on all licenses in use.
|
||||
org.openrewrite.java.dependencies.DependencyVulnerabilityCheck,Find and fix vulnerable dependencies,This software composition analysis (SCA) tool detects and upgrades dependencies with publicly disclosed vulnerabilities. This recipe both generates a report of vulnerable dependencies and upgrades to newer versions with fixes. This recipe by default only upgrades to the latest **patch** version. If a minor or major upgrade is required to reach the fixed version this can be controlled using the `maximumUpgradeDelta` option. Vulnerability information comes from the [GitHub Security Advisory Database](https://docs.github.com/en/code-security/security-advisories/global-security-advisories/about-the-github-advisory-database) which aggregates vulnerability data from several public databases including the [National Vulnerability Database](https://nvd.nist.gov/) maintained by the United States government. Upgrades dependencies versioned according to [Semantic Versioning](https://semver.org/). Last updated: 2025-10-20T1103.
|
||||
org.openrewrite.java.dependencies.RemoveUnusedDependencies,Remove unused dependencies,"Scans through source code collecting references to types and methods removing any dependencies that are not used from Maven or Gradle build files. This recipe takes reflective access into account: When reflective access to a class is made unambiguously via a string literal such as: `Class.forName(""java.util.List"")` that is counted correctly. When reflective access to a class is made ambiguously via anything other than a string literal no dependencies will be removed. This recipe takes transitive dependencies into account: When a direct dependency is not used but a transitive dependency it brings in _is_ in use the direct dependency is not removed."
|
||||
org.openrewrite.java.dependencies.SoftwareBillOfMaterials,Software bill of materials,Produces a software bill of materials (SBOM) for a project. An SBOM is a complete list of all dependencies used in a project including transitive dependencies. The produced SBOM is in the [CycloneDX](https://cyclonedx.org/) XML format. Supports Gradle and Maven. Places a file named sbom.xml adjacent to the Gradle or Maven build file.
|
||||
org.openrewrite.maven.AddAnnotationProcessor,Add an annotation processor to `maven-compiler-plugin`,Add an annotation processor to the maven compiler plugin. Will not do anything if it already exists. Also doesn't add anything when no other annotation processors are defined yet. (Perhaps `ChangePluginConfiguration` can be used).
|
||||
org.openrewrite.maven.AddParentPom,Add Maven parent,Add a parent pom to a Maven pom.xml. Does nothing if a parent pom is already present.
|
||||
org.openrewrite.maven.AddPlugin,Add Maven plugin,Add the specified Maven plugin to the pom.xml.
|
||||
org.openrewrite.maven.AddPluginDependency,Add Maven plugin dependencies,Adds the specified dependencies to a Maven plugin. Will not add the plugin if it does not already exist in the pom.
|
||||
org.openrewrite.maven.ChangeManagedDependencyGroupIdAndArtifactId,Change Maven managed dependency groupId artifactId and optionally the version,Change the groupId artifactId and optionally the version of a specified Maven managed dependency.
|
||||
org.openrewrite.maven.ChangeParentPom,Change Maven parent,Change the parent pom of a Maven pom.xml by matching the existing parent via groupId and artifactId and updating it to a new groupId artifactId version and optional relativePath. Also updates the project to retain dependency management and properties previously inherited from the old parent that are no longer provided by the new parent. Removes redundant dependency versions already managed by the new parent.
|
||||
org.openrewrite.maven.ChangePluginConfiguration,Change Maven plugin configuration,Apply the specified configuration to a Maven plugin. Will not add the plugin if it does not already exist in the pom.
|
||||
org.openrewrite.maven.ChangePluginDependencies,Change Maven plugin dependencies,Applies the specified dependencies to a Maven plugin. Will not add the plugin if it does not already exist in the pom.
|
||||
org.openrewrite.maven.ChangePluginExecutions,Change Maven plugin executions,Apply the specified executions to a Maven plugin. Will not add the plugin if it does not already exist in the pom.
|
||||
org.openrewrite.maven.ChangePluginGroupIdAndArtifactId,Change Maven plugin group and artifact ID,Change the groupId and/or the artifactId of a specified Maven plugin. Optionally update the plugin version. This recipe does not perform any validation and assumes all values passed are valid.
|
||||
org.openrewrite.maven.ManagedToRuntimeDependencies,Convert managed dependencies to runtime dependencies,This recipe processes Maven POMs converting all `<dependencyManagement>` entries into runtime scoped `<dependencies>` entries. Import scoped BOMs (like jackson-bom) are left unmodified in `<dependencyManagement>`. Some style guidelines prefer that `<dependencyManagement>` be used only for BOMs. This maintain that style while avoiding introducing new symbols onto the compile classpath unintentionally.
|
||||
org.openrewrite.maven.RemoveDuplicatePluginDeclarations,Remove duplicate plugin declarations,Maven 4 rejects duplicate plugin declarations (same groupId and artifactId) with an error. This recipe removes duplicate plugin declarations keeping only the first occurrence.
|
||||
org.openrewrite.maven.RemoveManagedDependency,Remove Maven managed dependency,Removes a single managed dependency from the <dependencyManagement><dependencies> section of the pom.xml.
|
||||
org.openrewrite.maven.RemovePlugin,Remove Maven plugin,Remove the specified Maven plugin from the POM.
|
||||
org.openrewrite.maven.RemovePluginDependency,Remove Maven plugin dependency,Removes a dependency from the <dependencies> section of a plugin in the pom.xml.
|
||||
org.openrewrite.maven.RemoveRedundantDependencyVersions,Remove redundant explicit dependency and plugin versions,Remove explicitly-specified dependency/plugin versions when a parent POM's `dependencyManagement`/`pluginManagement` specifies the version.
|
||||
org.openrewrite.maven.UpgradeParentVersion,Upgrade Maven parent project version,Set the parent pom version number according to a [version selector](https://docs.openrewrite.org/reference/dependency-version-selectors) or to a specific version number.
|
||||
org.openrewrite.gradle.plugins.AddBuildPlugin,Add Gradle plugin,Add a build plugin to a Gradle build file's `plugins` block.
|
||||
org.openrewrite.gradle.plugins.AddDevelocityGradlePlugin,Add the Develocity Gradle plugin,Add the Develocity Gradle plugin to settings.gradle files.
|
||||
org.openrewrite.gradle.plugins.AddSettingsPlugin,Add Gradle settings plugin,Add plugin to Gradle settings file `plugins` block by id.
|
||||
org.openrewrite.gradle.plugins.ChangePlugin,Change a Gradle plugin,Changes the selected Gradle plugin to the new plugin.
|
||||
org.openrewrite.gradle.plugins.ChangePluginVersion,Change a Gradle plugin version by id,Change a Gradle plugin by id to a later version.
|
||||
org.openrewrite.gradle.plugins.RemoveBuildPlugin,Remove Gradle plugin,Remove plugin from Gradle `plugins` block by its id. Does not remove plugins from the `buildscript` block.
|
||||
org.openrewrite.gradle.plugins.RemoveSettingsPlugin,Remove Gradle settings plugin,Remove plugin from Gradle settings file `plugins` block by id.
|
||||
org.openrewrite.gradle.search.FindGradleWrapper,Find Gradle wrappers,Find Gradle wrappers.
|
||||
org.openrewrite.gradle.search.FindJVMTestSuites,Find Gradle JVMTestSuite plugin configuration,Find Gradle JVMTestSuite plugin configurations and produce a data table.
|
||||
org.openrewrite.gradle.search.FindPlugins,Find Gradle plugin,Find a Gradle plugin by id and/or class name. For best results both should be specified as one cannot automatically be used to infer the other.
|
||||
org.openrewrite.gradle.UpdateGradleWrapper,Update Gradle wrapper,Update the version of Gradle used in an existing Gradle wrapper. Queries services.gradle.org to determine the available releases but prefers the artifact repository URL which already exists within the wrapper properties file. If your artifact repository does not contain the same Gradle distributions as services.gradle.org then the recipe may suggest a version which is not available in your artifact repository.
|
||||
org.openrewrite.gradle.plugins.UpgradePluginVersion,Update a Gradle plugin by id,Update a Gradle plugin by id to a later version defined by the plugins DSL. To upgrade a plugin dependency defined by `buildscript.dependencies` use the `UpgradeDependencyVersion` recipe instead.
|
||||
org.openrewrite.gradle.search.ModuleHasPlugin,Module has plugin,Searches for Gradle Projects (modules) that have a plugin matching the specified id or implementing class. Places a `SearchResult` marker on all sources within a project with a matching plugin. This recipe is intended to be used as a precondition for other recipes. For example this could be used to limit the application of a spring boot migration to only projects that apply the spring dependency management plugin limiting unnecessary upgrading. If the search result you want is instead just the build.gradle(.kts) file applying the plugin use the `FindPlugins` recipe instead.
|
||||
org.openrewrite.gradle.spring.AddSpringDependencyManagementPlugin,Add `io.spring.dependency-management` plugin if in use,Prior to Spring Boot 2.0 the dependency management plugin was applied automatically as part of the overall spring boot plugin. Afterwards the dependency-management plugin must be applied explicitly or Gradle's `platform()` feature may be used instead. This recipe makes usage of io-spring.dependency-management explicit in anticipation of upgrade to Spring Boot 2.0 or later.
|
||||
|
@@ -0,0 +1,15 @@
|
||||
Fully Qualified Recipe Name,Recipe Name,Description
|
||||
org.openrewrite.DeleteSourceFiles,Delete files,Delete files by source path.
|
||||
org.openrewrite.MoveFile,Move a file,Move a file to a different directory. The file name will remain the same.
|
||||
org.openrewrite.RenameFile,Rename a file,Rename a file while keeping it in the same directory.
|
||||
org.openrewrite.text.AppendToTextFile,Append to text file,Appends or replaces content of an existing plain text file or creates a new one if it doesn't already exist. Please note that this recipes requires existing plain text files' format to be successfully parsable by OpenRewrite. If a file is left unchanged it might be parsed as a `Quark` rather than plain text. In such case use the `plainTextMask` option. See the [Gradle](https://docs.openrewrite.org/reference/gradle-plugin-configuration#configuring-the-rewrite-dsl) or [Maven](https://openrewrite.github.io/rewrite-maven-plugin/run-mojo.html#plainTextMasks) plugin configuration page.
|
||||
org.openrewrite.text.ChangeText,Change text,Completely replaces the contents of the text file with other text. Use together with a `FindSourceFiles` precondition to limit which files are changed.
|
||||
org.openrewrite.text.CreateTextFile,Create text file,Creates a new plain text file.
|
||||
org.openrewrite.text.EndOfLineAtEndOfFile,End of Line @ End of File (EOL @ EOF),Ensure that the file ends with the newline character. *Note*: If this recipe modifies a file it converts the file into plain text. As such this recipe should be run after any recipe that modifies the language-specific LST.
|
||||
org.openrewrite.text.Find,Find text,Textual search optionally using Regular Expression (regex) to query.
|
||||
org.openrewrite.text.FindAndReplace,Find and replace,Textual find and replace optionally interpreting the search query as a Regular Expression (regex). When operating on source files that are language-specific Lossless Semantic Tree such as Java or XML this operation converts the source file to plain text for the rest of the recipe run. So if you are combining this recipe with language-specific recipes in a single recipe run put all the language-specific recipes before this recipe.
|
||||
org.openrewrite.text.FindMultiselect,Experimental find text with multiselect,Search for text treating all textual sources as plain text. This version of the recipe exists to experiment with multiselect recipe options.
|
||||
org.openrewrite.hcl.search.FindAndReplaceLiteral,Find and replace literals in HCL files,Find and replace literal values in HCL files. This recipe parses the source files on which it runs as HCL meaning you can execute HCL language-specific recipes before and after this recipe in a single recipe run.
|
||||
org.openrewrite.text.FindHardcodedLoopbackAddresses,Find hard-coded loopback IPv4 addresses,Locates mentions of hard-coded IPv4 addresses from the loopback IP range. The loopback IP range includes `127.0.0.0` to `127.255.255.255`. This detects the entire localhost/loopback subnet range not just the commonly used `127.0.0.1`.
|
||||
org.openrewrite.text.FindHardcodedPrivateIPAddresses,Find hard-coded private IPv4 addresses,Locates mentions of hard-coded IPv4 addresses from private IP ranges. Private IP ranges include: * `192.168.0.0` to `192.168.255.255` * `10.0.0.0` to `10.255.255.255` * `172.16.0.0` to `172.31.255.255` It is not detecting the localhost subnet `127.0.0.0` to `127.255.255.255`.
|
||||
org.openrewrite.text.RemoveHardcodedIPAddressesFromComments,Remove hard-coded IP addresses from comments,Removes hard-coded IPv4 addresses from comments when they match private IP ranges or loopback addresses. This targets IP addresses that are commented out in various comment formats: **Private IP ranges:** * `192.168.0.0` to `192.168.255.255` * `10.0.0.0` to `10.255.255.255` * `172.16.0.0` to `172.31.255.255` **Loopback IP range:** * `127.0.0.0` to `127.255.255.255` **Supported comment formats:** * C-style line comments (`//`) * C-style block comments (`/* */`) * Shell/Python style comments (`#`) * XML comments (`<!-- -->`) * YAML comments (`#`) * Properties file comments (`#` or `!`) For line comments the entire line is removed. For block comments only the IP address is removed.
|
||||
|
@@ -0,0 +1,17 @@
|
||||
Fully Qualified Recipe Name,Recipe Name,Description
|
||||
org.apache.camel.upgrade.camel40.CamelMigrationRecipe,Migrate `camel3` application to `camel4.`,Migrate `camel3` application to `camel4`.
|
||||
org.apache.camel.upgrade.camel410_4.CamelMigrationRecipe,Migrates `camel 4.10.3` application to `camel 4.10.4`,Migrates `camel 4.10.3` application to `camel 4.10.4`.
|
||||
io.moderne.elastic.elastic9.MigrateToElasticsearch9,Migrate from Elasticsearch 8 to 9,This recipe performs a comprehensive migration from Elasticsearch 8 to Elasticsearch 9 addressing breaking changes API removals deprecations and required code modifications.
|
||||
io.moderne.hibernate.update70.AddCascadePersistToIdMappedAssociations,Migrate implicit cascade=PERSIST for @Id and @MapsId associations,Hibernate used to automatically enable cascade=PERSIST for association fields annotated @Id or @MapsId. This was undocumented and unexpected behavior and no longer supported in Hibernate 7. Existing code which relies on this behavior will be modified by addition of explicit cascade=PERSIST to the association fields.
|
||||
io.moderne.hibernate.update70.MigrateConfigurableToGeneratorCreationContext,Migrate `Configurable.configure()` to use `GeneratorCreationContext`,In Hibernate 7.0 `Configurable.configure()` now takes a `GeneratorCreationContext` parameter instead of `ServiceRegistry`. This recipe migrates method signatures and call sites.
|
||||
org.openrewrite.jenkins.JavaxAnnotationsToSpotbugs,Migrate `javax.annotations` to SpotBugs annotations,SpotBugs is the [preferred replacement](https://www.jenkins.io/doc/developer/tutorial-improve/replace-jsr-305-annotations/) of JSR-305 annotations for Jenkins plugins.
|
||||
org.openrewrite.java.migrate.jakarta.Faces3xMigrationToFaces4x,Upgrade to Jakarta Faces 4.x,Jakarta EE 10 uses Faces 4.0.
|
||||
org.openrewrite.java.testing.junit5.UpgradeToJUnit514,Upgrade to JUnit 5.14,Upgrades JUnit 5 to 5.14.x and migrates all deprecated APIs.
|
||||
io.moderne.kafka.MigrateAlterConfigsToIncrementalAlterConfigs,Migrate `AdminClient.alterConfigs()` to `incrementalAlterConfigs()`,Migrates the removed `AdminClient.alterConfigs()` method to `incrementalAlterConfigs()` for Kafka 4.0 compatibility.
|
||||
io.moderne.kafka.MigrateConsumerCommittedToSet,Migrate `KafkaConsumer.committed(TopicPartition)` to `committed(Set<TopicPartition>)`,Migrates from the removed `KafkaConsumer.committed(TopicPartition)` to `committed(Set<TopicPartition>)` for Kafka 4.0 compatibility. Converts single `TopicPartition` arguments to `Collections.singleton()` calls.
|
||||
org.openrewrite.java.micronaut.Micronaut2to3Migration,Migrate from Micronaut 2.x to 3.x,This recipe will apply changes required for migrating from Micronaut 2 to Micronaut 3.
|
||||
org.openrewrite.java.micronaut.Micronaut3to4Migration,Migrate from Micronaut 3.x to 4.x,This recipe will apply changes required for migrating from Micronaut 3 to Micronaut 4.
|
||||
org.openrewrite.quarkus.Slf4jToQuarkusLogger,Migrate SLF4J Logger injection and usage to Quarkus static `Log`,Removes usage of SLF4J Logger fields adjusts imports and replaces logger method calls with static Quarkus Log calls including message formatting and method renaming for parameterized logging.
|
||||
org.openrewrite.quarkus.migrate.javaee.JavaEEtoQuarkus2Migration,Migrate JavaEE to Quarkus 2,These recipes help with the migration of a JavaEE application using EJBs and Hibernate to Quarkus 2. Additional transformations like JSF JMS Quarkus Tests may be necessary.
|
||||
io.moderne.java.spring.boot3.ConditionalOnAvailableEndpointMigrationSpring34,Migrate `ConditionalOnAvailableEndpoint` for Spring Boot 3.4,Migrate `@ConditionalOnAvailableEndpoint(EndpointExposure.CLOUD_FOUNDRY)` to `@ConditionalOnAvailableEndpoint(EndpointExposure.WEB)` for Spring Boot 3.4.
|
||||
io.moderne.java.spring.boot3.UpgradeSpringBoot_3_5,Migrate to Spring Boot 3.5,Migrate applications to the latest Spring Boot 3.5 release. This recipe will modify an application's build files make changes to deprecated/preferred APIs and migrate configuration settings that have changes between versions. This recipe will also chain additional framework migrations (Spring Framework Spring Data etc) that are required as part of the migration to Spring Boot 3.5.
|
||||
|
@@ -0,0 +1,33 @@
|
||||
Fully Qualified Recipe Name,Recipe Name,Description
|
||||
org.openrewrite.java.AddCommentToImport,Add comment to import statement,Add a comment to an import statement in a Java source file.
|
||||
org.openrewrite.java.AddCommentToMethod,Add comment to method declarations,Add a comment to method declarations in a Java source file.
|
||||
org.openrewrite.java.AddCommentToMethodInvocations,Add comment to method invocations,Add a comment to method invocations in a Java source file.
|
||||
org.openrewrite.java.AddMethodParameter,Add method parameter to a method declaration,Adds a new method parameter to an existing method declaration.
|
||||
org.openrewrite.java.ChangeMethodAccessLevel,Change method access level,Change the access level (public protected private package private) of a method.
|
||||
org.openrewrite.java.ChangeMethodInvocationReturnType,Change method invocation return type,Changes the return type of a method invocation.
|
||||
org.openrewrite.java.ChangeMethodName,Change method name,Rename a method.
|
||||
org.openrewrite.java.ChangeMethodTargetToStatic,Change method target to static,Change method invocations to static method calls.
|
||||
org.openrewrite.java.ChangeMethodTargetToVariable,Change method target to variable,Change method invocations to method calls on a variable.
|
||||
org.openrewrite.java.ChangePackage,Rename package name,A recipe that will rename a package name in package statements imports and fully-qualified types.
|
||||
org.openrewrite.java.ChangePackageInStringLiteral,Rename package name in String literals,A recipe that will rename a package name in String literals.
|
||||
org.openrewrite.java.ChangeType,Change type,Change a given type to another.
|
||||
org.openrewrite.java.ChangeTypeInStringLiteral,Change type in String literals,Change a given type to another when used in a String literal.
|
||||
org.openrewrite.java.DeleteMethodArgument,Delete method argument,Delete an argument from method invocations.
|
||||
org.openrewrite.java.RemoveAnnotation,Remove annotation,Remove matching annotations wherever they occur.
|
||||
org.openrewrite.java.RemoveAnnotationAttribute,Remove annotation attribute,Some annotations accept arguments. This recipe removes an existing attribute.
|
||||
org.openrewrite.java.ReplaceAnnotation,Replace annotation,Replace an Annotation with another one if the annotation pattern matches. Only fixed parameters can be set in the replacement.
|
||||
org.openrewrite.java.ReplaceConstant,Replace constant with literal value,Replace a named constant with a literal value when you wish to remove the old constant. A `String` literal must include escaped quotes.
|
||||
org.openrewrite.java.ReplaceConstantWithAnotherConstant,Replace constant with another constant,Replace a constant with another constant adding/removing import on class if needed.
|
||||
org.openrewrite.java.ReplaceStringLiteralValue,Replace `String` literal,Replace the value of a complete `String` literal.
|
||||
org.openrewrite.java.ReplaceStringLiteralWithConstant,Replace String literal with constant,Replace String literal with constant adding import on class if needed.
|
||||
org.openrewrite.java.ShortenFullyQualifiedTypeReferences,Add imports for fully qualified references to types,Any fully qualified references to Java types will be replaced with corresponding simple names and import statements provided that it doesn't result in any conflicts with other imports or types declared in the local compilation unit.
|
||||
org.openrewrite.maven.AddAnnotationProcessor,Add an annotation processor to `maven-compiler-plugin`,Add an annotation processor to the maven compiler plugin. Will not do anything if it already exists. Also doesn't add anything when no other annotation processors are defined yet. (Perhaps `ChangePluginConfiguration` can be used).
|
||||
org.openrewrite.python.ChangeMethodName,Change method name,Renames a method.
|
||||
org.openrewrite.java.micronaut.RemoveAnnotationProcessorPath,Remove Maven annotation processor path,Remove the Maven annotation processor path that matches the given groupId and artifactId.
|
||||
org.openrewrite.java.micronaut.AddAnnotationProcessorPath,Add Maven annotation processor path,Add the groupId artifactId version and exclusions of a Maven annotation processor path.
|
||||
org.openrewrite.java.migrate.ReplaceStringLiteralValue,Replace `String` literal,Replace the value of a complete `String` literal.
|
||||
org.openrewrite.java.spring.http.ReplaceStringLiteralsWithHttpHeadersConstants,Replace String literals with `HttpHeaders` constants,Replace String literals with `org.springframework.http.HttpHeaders` constants.
|
||||
org.openrewrite.java.spring.http.ReplaceStringLiteralsWithMediaTypeConstants,Replace String literals with `MediaType` constants,Replace String literals with `org.springframework.http.MediaType` constants.
|
||||
org.openrewrite.java.spring.boot3.ReplaceStringLiteralsWithConstants,Replace String literals with Spring constants,Replace String literals with Spring constants where applicable.
|
||||
org.apache.camel.upgrade.camel40.ChangeTypes,Migrate moved types between Camel 3.x and Camel 4.x,Change type of classes related to change of API.
|
||||
org.apache.camel.upgrade.camel49.DebeziumChangeTypes,Each camel-debezium module has its own subpackage corresponding to the database type,each camel-debezium module has its own subpackage corresponding to the database type. So for example all the classes of the module camel-debezium-postgres have been moved to a dedicated package which is org.apache.camel.component.debezium.postgres instead of having everything under the root package org.apache.camel.component.debezium.
|
||||
|
@@ -0,0 +1,51 @@
|
||||
Fully Qualified Recipe Name,Recipe Name,Description
|
||||
org.openrewrite.java.logging.containerized.ContainerizeLog4j2PropertiesConfiguration,Containerize Log4j2 Properties configuration,Transforms Log4j2 Properties configuration to write logs to stdout instead of files suitable for containerized environments.
|
||||
org.openrewrite.java.logging.containerized.ContainerizeLog4j2XmlConfiguration,Containerize Log4j2 XML configuration,Transforms Log4j2 XML configuration to write logs to stdout instead of files suitable for containerized environments.
|
||||
org.openrewrite.java.logging.containerized.ContainerizeLog4j2YamlConfiguration,Containerize Log4j2 YAML configuration,Transforms Log4j2 YAML configuration to write logs to stdout instead of files suitable for containerized environments. (Implementation in progress)
|
||||
org.openrewrite.java.logging.containerized.ContainerizeLogbackConfiguration,Containerize Logback configuration,Transforms Logback XML configuration to write logs to stdout instead of files suitable for containerized environments.
|
||||
org.openrewrite.java.logging.containerized.ContainerizeLogging,Containerize logging configuration,Transforms logging configurations to write to stdout instead of files making them suitable for containerized environments. This composite recipe applies transformations for multiple logging frameworks including Log4j2 Logback Log4j 1.x and Java Util Logging.
|
||||
org.openrewrite.java.logging.containerized.log4j2.ContainerizeLog4j2,Containerize Log4j2 configuration,Transforms all Log4j2 configuration formats (XML Properties YAML JSON) to write logs to stdout instead of files.
|
||||
org.openrewrite.codehaus.plexus.AbstractLogEnabledToSlf4j,Migrate from Plexus `AbstractLogEnabled` to SLF4J,Introduce a SLF4J `Logger` field and replace calls to `getLogger()` with calls to the field.
|
||||
org.openrewrite.java.logging.ArgumentArrayToVarargs,Unpack Logger method `new Object[] {...}` into varargs,For Logger methods that support varargs convert any final explicit `Object[]` arguments into their unpacked values.
|
||||
org.openrewrite.java.logging.ChangeLoggersToPrivate,Change logger fields to `private`,Ensures that logger fields are declared as `private` to encapsulate logging mechanics within the class.
|
||||
org.openrewrite.java.logging.ParameterizedLogging,Parameterize logging statements,"Transform logging statements using concatenation for messages and variables into a parameterized format. For example `logger.info(""hi "" + userName)` becomes `logger.info(""hi {}"" userName)`. This can significantly boost performance for messages that otherwise would be assembled with String concatenation. Particularly impactful when the log level is not enabled as no work is done to assemble the message."
|
||||
org.openrewrite.java.logging.PrintStackTraceToLogError,Use logger instead of `printStackTrace()`,When a logger is present log exceptions rather than calling `printStackTrace()`.
|
||||
org.openrewrite.java.logging.SystemErrToLogging,Use logger instead of `System.err` print statements,Replace `System.err` print statements with a logger.
|
||||
org.openrewrite.java.logging.SystemOutToLogging,Use logger instead of `System.out` print statements,Replace `System.out` print statements with a logger.
|
||||
org.openrewrite.java.logging.SystemPrintToLogging,Use logger instead of system print statements,Replace `System.out` and `System.err` print statements with a logger.
|
||||
org.openrewrite.java.logging.jboss.FormattedArgumentsToVMethodRecipes,Replace deprecated JBoss Logging Logger formatted message invocations with the v-version of methods,"Replace `logger.level(""hello {0}"" arg)` with `logger.levelv(""hello {0}"" arg)`."
|
||||
org.openrewrite.java.logging.jul.LoggerLevelArgumentToMethodRecipes$LogLevelConfigSupplierToMethodRecipe,Replace JUL `Logger.log(Level.CONFIG Supplier<String>)` with `Logger.config(Supplier<String>)`,Replace calls to `java.util.logging.Logger.log(Level.CONFIG Supplier<String>)` with `Logger.config(Supplier<String>)`.
|
||||
org.openrewrite.java.logging.jul.LoggerLevelArgumentToMethodRecipes$LogLevelConfigToMethodRecipe,Replace JUL `Logger.log(Level.CONFIG String)` with `Logger.config(String)`,Replace calls to `java.util.logging.Logger.log(Level.CONFIG String)` with `Logger.config(String)`.
|
||||
org.openrewrite.java.logging.jul.LoggerLevelArgumentToMethodRecipes$LogLevelFineSupplierToMethodRecipe,Replace JUL `Logger.log(Level.FINE Supplier<String>)` with `Logger.fine(Supplier<String>)`,Replace calls to `java.util.logging.Logger.log(Level.FINE Supplier<String>)` with `Logger.fine(Supplier<String>)`.
|
||||
org.openrewrite.java.logging.jul.LoggerLevelArgumentToMethodRecipes$LogLevelFineToMethodRecipe,Replace JUL `Logger.log(Level.FINE String)` with `Logger.fine(String)`,Replace calls to `java.util.logging.Logger.log(Level.FINE String)` with `Logger.fine(String)`.
|
||||
org.openrewrite.java.logging.jul.LoggerLevelArgumentToMethodRecipes$LogLevelFinerSupplierToMethodRecipe,Replace JUL `Logger.log(Level.FINER Supplier<String>)` with `Logger.finer(Supplier<String>)`,Replace calls to `java.util.logging.Logger.log(Level.FINER Supplier<String>)` with `Logger.finer(Supplier<String>)`.
|
||||
org.openrewrite.java.logging.jul.LoggerLevelArgumentToMethodRecipes$LogLevelFinerToMethodRecipe,Replace JUL `Logger.log(Level.FINER String)` with `Logger.finer(String)`,Replace calls to `java.util.logging.Logger.log(Level.FINER String)` with `Logger.finer(String)`.
|
||||
org.openrewrite.java.logging.jul.LoggerLevelArgumentToMethodRecipes$LogLevelFinestSupplierToMethodRecipe,Replace JUL `Logger.log(Level.FINEST Supplier<String>)` with `Logger.finest(Supplier<String>)`,Replace calls to `java.util.logging.Logger.log(Level.FINEST Supplier<String>)` with `Logger.finest(Supplier<String>)`.
|
||||
org.openrewrite.java.logging.jul.LoggerLevelArgumentToMethodRecipes$LogLevelFinestToMethodRecipe,Replace JUL `Logger.log(Level.FINEST String)` with `Logger.finest(String)`,Replace calls to `java.util.logging.Logger.log(Level.FINEST String)` with `Logger.finest(String)`.
|
||||
org.openrewrite.java.logging.jul.LoggerLevelArgumentToMethodRecipes$LogLevelInfoSupplierToMethodRecipe,Replace JUL `Logger.log(Level.INFO Supplier<String>)` with `Logger.info(Supplier<String>)`,Replace calls to `java.util.logging.Logger.log(Level.INFO Supplier<String>)` with `Logger.info(Supplier<String>)`.
|
||||
org.openrewrite.java.logging.jul.LoggerLevelArgumentToMethodRecipes$LogLevelInfoToMethodRecipe,Replace JUL `Logger.log(Level.INFO String)` with `Logger.info(String)`,Replace calls to `java.util.logging.Logger.log(Level.INFO String)` with `Logger.info(String)`.
|
||||
org.openrewrite.java.logging.jul.LoggerLevelArgumentToMethodRecipes$LogLevelSevereSupplierToMethodRecipe,Replace JUL `Logger.log(Level.SEVERE Supplier<String>)` with `Logger.severe(Supplier<String>)`,Replace calls to `java.util.logging.Logger.log(Level.SEVERE Supplier<String>)` with `Logger.severe(Supplier<String>)`.
|
||||
org.openrewrite.java.logging.jul.LoggerLevelArgumentToMethodRecipes$LogLevelSevereToMethodRecipe,Replace JUL `Logger.log(Level.SEVERE String)` with `Logger.severe(String)`,Replace calls to `java.util.logging.Logger.log(Level.SEVERE String)` with `Logger.severe(String)`.
|
||||
org.openrewrite.java.logging.jul.LoggerLevelArgumentToMethodRecipes$LogLevelWarningSupplierToMethodRecipe,Replace JUL `Logger.log(Level.WARNING Supplier<String>)` with `Logger.warning(Supplier<String>)`,Replace calls to `java.util.logging.Logger.log(Level.WARNING Supplier<String>)` with `Logger.warning(Supplier<String>)`.
|
||||
org.openrewrite.java.logging.jul.LoggerLevelArgumentToMethodRecipes$LogLevelWarningToMethodRecipe,Replace JUL `Logger.log(Level.WARNING String)` with `Logger.warning(String)`,Replace calls to `java.util.logging.Logger.log(Level.WARNING String)` with `Logger.warning(String)`.
|
||||
org.openrewrite.java.logging.log4j.ConvertJulEntering,Rewrites JUL's Logger#entering method to Log4j API,Replaces JUL's Logger#entering method calls to Log4j API Logger#traceEntry calls.
|
||||
org.openrewrite.java.logging.log4j.ConvertJulExiting,Rewrites JUL's Logger#exiting method to Log4j API,Replaces JUL's Logger#exiting method calls to Log4j API Logger#traceEntry calls.
|
||||
org.openrewrite.java.logging.log4j.LoggerSetLevelToConfiguratorRecipe,Convert Log4j `Logger.setLevel` to Log4j2 `Configurator.setLevel`,Converts `org.apache.log4j.Logger.setLevel` to `org.apache.logging.log4j.core.config.Configurator.setLevel`.
|
||||
org.openrewrite.java.logging.logback.ConfigureLoggerLevel,Configure logback logger level,Within logback.xml configuration files sets the specified log level for a particular class. Will not create a logback.xml if one does not already exist.
|
||||
org.openrewrite.java.logging.logback.Log4jAppenderToLogback,Migrate Log4j 2.x Appender to logback-classic equivalents,Migrates custom Log4j 2.x Appender components to `logback-classic`. This recipe operates on the following assumptions: 1.) The contents of the `append()` method remains unchanged. 2.) The `requiresLayout()` method is not used in logback and can be removed. 3.) In logback the `stop()` method is the equivalent of log4j's close() method. For more details see this page from logback: [`Migration from log4j`](http://logback.qos.ch/manual/migrationFromLog4j.html).
|
||||
org.openrewrite.java.logging.logback.Log4jLayoutToLogback,Migrate Log4j 2.x Layout to logback-classic equivalents,Migrates custom Log4j 2.x Layout components to `logback-classic`. This recipe operates on the following assumptions: 1. A logback-classic layout must extend the `LayoutBase<ILoggingEvent>` class. 2. log4j's `format()` is renamed to `doLayout()` in a logback-classic layout. 3. LoggingEvent `getRenderedMessage()` is converted to LoggingEvent `getMessage()`. 4. The log4j ignoresThrowable() method is not needed and has no equivalent in logback-classic. 5. The activateOptions() method merits further discussion. In log4j a layout will have its activateOptions() method invoked by log4j configurators that is PropertyConfigurator or DOMConfigurator just after all the options of the layout have been set. Thus the layout will have an opportunity to check that its options are coherent and if so proceed to fully initialize itself. 6. In logback-classic layouts must implement the LifeCycle interface which includes a method called start(). The start() method is the equivalent of log4j's activateOptions() method. For more details see this page from logback: [`Migration from log4j`](http://logback.qos.ch/manual/migrationFromLog4j.html).
|
||||
org.openrewrite.java.logging.slf4j.ChangeLogLevel,Change SLF4J log level,Change the log level of SLF4J log statements.
|
||||
org.openrewrite.java.logging.slf4j.JulGetLoggerToLoggerFactoryRecipes,Replace JUL Logger creation with SLF4J LoggerFactory,Replace calls to `Logger.getLogger` with `LoggerFactory.getLogger`.
|
||||
org.openrewrite.java.logging.slf4j.JulGetLoggerToLoggerFactoryRecipes$GetLoggerClassCanonicalNameToLoggerFactoryRecipe,Replace JUL `Logger.getLogger(Some.class.getCanonicalName())` with SLF4J's `LoggerFactory.getLogger(Some.class)`,Replace calls to `java.util.logging.Logger.getLogger(Some.class.getCanonicalName())` with `org.slf4j.LoggerFactory.getLogger(Some.class)`.
|
||||
org.openrewrite.java.logging.slf4j.JulGetLoggerToLoggerFactoryRecipes$GetLoggerClassNameToLoggerFactoryRecipe,Replace JUL `Logger.getLogger(Some.class.getName())` with SLF4J's `LoggerFactory.getLogger(Some.class)`,Replace calls to `java.util.logging.Logger.getLogger(Some.class.getName())` with `org.slf4j.LoggerFactory.getLogger(Some.class)`.
|
||||
org.openrewrite.java.logging.slf4j.JulIsLoggableToIsEnabledRecipes,Replace JUL active Level check with corresponding SLF4J method calls,Replace calls to `Logger.isLoggable(Level)` with the corresponding SLF4J method calls.
|
||||
org.openrewrite.java.logging.slf4j.JulIsLoggableToIsEnabledRecipes$LoggerIsLoggableLevelAllRecipe,Replace JUL `Logger.isLoggable(Level.ALL)` with SLF4J's `Logger.isTraceEnabled`,Replace calls to `java.util.logging.Logger.isLoggable(Level.ALL)` with `org.slf4j.Logger.isTraceEnabled()`.
|
||||
org.openrewrite.java.logging.slf4j.JulIsLoggableToIsEnabledRecipes$LoggerIsLoggableLevelConfigRecipe,Replace JUL `Logger.isLoggable(Level.CONFIG)` with SLF4J's `Logger.isInfoEnabled()`,Replace calls to `java.util.logging.Logger.isLoggable(Level.CONFIG)` with `org.slf4j.Logger.isInfoEnabled()`.
|
||||
org.openrewrite.java.logging.slf4j.JulIsLoggableToIsEnabledRecipes$LoggerIsLoggableLevelFineRecipe,Replace JUL `Logger.isLoggable(Level.FINE)` with SLF4J's `Logger.isDebugEnabled()`,Replace calls to `java.util.logging.Logger.isLoggable(Level.FINE)` with `org.slf4j.Logger.isDebugEnabled()`.
|
||||
org.openrewrite.java.logging.slf4j.JulIsLoggableToIsEnabledRecipes$LoggerIsLoggableLevelFinerRecipe,Replace JUL `Logger.isLoggable(Level.FINER)` with SLF4J's `Logger.isTraceEnabled()`,Replace calls to `java.util.logging.Logger.isLoggable(Level.FINER)` with `org.slf4j.Logger.isTraceEnabled()`.
|
||||
org.openrewrite.java.logging.slf4j.JulIsLoggableToIsEnabledRecipes$LoggerIsLoggableLevelFinestRecipe,Replace JUL `Logger.isLoggable(Level.FINEST)` with SLF4J's `Logger.isTraceEnabled`,Replace calls to `java.util.logging.Logger.isLoggable(Level.FINEST)` with `org.slf4j.Logger.isTraceEnabled()`.
|
||||
org.openrewrite.java.logging.slf4j.JulIsLoggableToIsEnabledRecipes$LoggerIsLoggableLevelInfoRecipe,Replace JUL `Logger.isLoggable(Level.INFO)` with SLF4J's `Logger.isInfoEnabled()`,Replace calls to `java.util.logging.Logger.isLoggable(Level.INFO)` with `org.slf4j.Logger.isInfoEnabled()`.
|
||||
org.openrewrite.java.logging.slf4j.JulIsLoggableToIsEnabledRecipes$LoggerIsLoggableLevelSevereRecipe,Replace JUL `Logger.isLoggable(Level.SEVERE)` with SLF4J's `Logger.isErrorEnabled()`,Replace calls to `java.util.logging.Logger.isLoggable(Level.SEVERE)` with `org.slf4j.Logger.isErrorEnabled()`.
|
||||
org.openrewrite.java.logging.slf4j.JulIsLoggableToIsEnabledRecipes$LoggerIsLoggableLevelWarningRecipe,Replace JUL `Logger.isLoggable(Level.WARNING)` with SLF4J's `Logger.isWarnEnabled()`,Replace calls to `java.util.logging.Logger.isLoggable(Level.WARNING)` with `org.slf4j.Logger.isWarnEnabled()`.
|
||||
org.openrewrite.java.logging.slf4j.JulLevelAllToTraceRecipe,Replace JUL `Level.ALL` logging with SLF4J's trace level,Replace `java.util.logging.Logger#log(Level.ALL String)` with `org.slf4j.Logger#trace(String)`.
|
||||
org.openrewrite.java.logging.slf4j.JulParameterizedArguments,Replace parameterized JUL level call with corresponding SLF4J method calls,Replace calls to parameterized `Logger.log(LevelString…)` call with the corresponding slf4j method calls transforming the formatter and parameter lists.
|
||||
|
@@ -0,0 +1,31 @@
|
||||
Fully Qualified Recipe Name,Recipe Name,Description
|
||||
io.moderne.cryptography.FindSecurityModifications,Find Security class modifications,Finds invocations of java.security.Security methods that modify security configuration such as removeProvider addProvider insertProviderAt setProperty and removeProperty.
|
||||
io.moderne.cryptography.FindSecuritySetProperties,Find `Security.setProperty(..)` calls for certain properties,There is a defined set of properties that should not be set using `Security.setProperty(..)` as they can lead to security vulnerabilities.
|
||||
org.openrewrite.analysis.java.security.FindSecurityVulnerabilities,Find security vulnerabilities using taint analysis,Identifies potential security vulnerabilities where untrusted data from sources flows to sensitive sinks without proper sanitization.
|
||||
org.openrewrite.analysis.java.security.FindCommandInjection,Find command injection vulnerabilities,Detects when user-controlled input flows into system command execution methods like Runtime.exec() or ProcessBuilder which could allow attackers to execute arbitrary commands.
|
||||
org.openrewrite.analysis.java.security.FindLdapInjection,Find LDAP injection vulnerabilities,Finds LDAP injection vulnerabilities by tracking tainted data flow from user input to LDAP queries.
|
||||
org.openrewrite.analysis.java.security.FindPathTraversal,Find path traversal vulnerabilities,Detects potential path traversal vulnerabilities where user input flows to file system operations without proper validation.
|
||||
org.openrewrite.analysis.java.security.FindSqlInjection,Find SQL injection vulnerabilities,Detects potential SQL injection vulnerabilities where user input flows to SQL execution methods without proper sanitization.
|
||||
org.openrewrite.analysis.java.security.FindUnencryptedPiiStorage,Find unencrypted PII storage,Identifies when personally identifiable information (PII) is stored in databases files or other persistent storage without encryption.
|
||||
org.openrewrite.analysis.java.security.FindXssVulnerability,Find XSS vulnerabilities,Detects potential cross-site scripting vulnerabilities where user input flows to output methods without proper sanitization.
|
||||
org.openrewrite.analysis.java.security.FindXxeVulnerability,Find XXE vulnerabilities,Locates XML parsers that are not configured to prevent XML External Entity (XXE) attacks.
|
||||
io.moderne.vulncheck.FixVulnCheckVulnerabilities,Use [VulnCheck Exploit Intelligence](https://docs.vulncheck.com/products/exploit-and-vulnerability-intelligence/exploit-intelligence) to fix vulnerabilities,This software composition analysis (SCA) tool detects and upgrades dependencies with publicly disclosed vulnerabilities. This recipe both generates a report of vulnerable dependencies and upgrades to newer versions with fixes. This recipe by default only upgrades to the latest **patch** version. If a minor or major upgrade is required to reach the fixed version this can be controlled using the `maximumUpgradeDelta` option. Vulnerability information comes from VulnCheck Vulnerability Intelligence. The recipe has an option to limit fixes to only those vulnerabilities that have evidence of exploitation at various levels of severity.
|
||||
org.openrewrite.xml.security.AddOwaspDateBoundSuppressions,Add date bounds to OWASP suppressions,Adds an expiration date to all OWASP suppressions in order to ensure that they are periodically reviewed. For use with the OWASP `dependency-check` tool. More details: https://jeremylong.github.io/DependencyCheck/general/suppression.html.
|
||||
org.openrewrite.xml.security.IsOwaspSuppressionsFile,Find OWASP vulnerability suppression XML files,These files are used to suppress false positives in OWASP [Dependency Check](https://jeremylong.github.io/DependencyCheck).
|
||||
org.openrewrite.xml.security.RemoveOwaspSuppressions,Remove out-of-date OWASP suppressions,Remove all OWASP suppressions with a suppression end date in the past as these are no longer valid. For use with the OWASP `dependency-check` tool. More details on OWASP suppression files can be found [here](https://jeremylong.github.io/DependencyCheck/general/suppression.html).
|
||||
org.openrewrite.xml.security.UpdateOwaspSuppressionDate,Update OWASP suppression date bounds,Updates the expiration date for OWASP suppressions having a matching cve tag. For use with the OWASP `dependency-check` tool. More details: https://jeremylong.github.io/DependencyCheck/general/suppression.html.
|
||||
org.openrewrite.github.security.InsecureCommandsRecipe,Find insecure commands configuration,Detects when insecure workflow commands are enabled via `ACTIONS_ALLOW_UNSECURE_COMMANDS`. This environment variable enables dangerous workflow commands that can lead to code injection vulnerabilities. Based on [zizmor's insecure-commands audit](https://github.com/woodruffw/zizmor/blob/main/crates/zizmor/src/audit/insecure_commands.rs).
|
||||
org.openrewrite.github.security.TemplateInjectionRecipe,Find template injection vulnerabilities,Find GitHub Actions workflows vulnerable to template injection attacks. These occur when user-controllable input (like pull request titles issue bodies or commit messages) is used directly in `run` commands or `script` inputs without proper escaping. Attackers can exploit this to execute arbitrary code. Based on [zizmor's `template-injection` audit](https://github.com/woodruffw/zizmor/blob/main/crates/zizmor/src/audit/template_injection.rs).
|
||||
org.openrewrite.java.security.PartialPathTraversalVulnerability,Partial path traversal vulnerability,"Replaces `dir.getCanonicalPath().startsWith(parent.getCanonicalPath()` which is vulnerable to partial path traversal attacks with the more secure `dir.getCanonicalFile().toPath().startsWith(parent.getCanonicalFile().toPath())`. To demonstrate this vulnerability consider `""/usr/outnot"".startsWith(""/usr/out"")`. The check is bypassed although `/outnot` is not under the `/out` directory. It's important to understand that the terminating slash may be removed when using various `String` representations of the `File` object. For example on Linux `println(new File(""/var""))` will print `/var` but `println(new File(""/var"" ""/"")` will print `/var/`; however `println(new File(""/var"" ""/"").getCanonicalPath())` will print `/var`."
|
||||
org.openrewrite.java.security.marshalling.InsecureJmsDeserialization,Insecure JMS deserialization,JMS `Object` messages depend on Java Serialization for marshalling/unmarshalling of the message payload when `ObjectMessage#getObject` is called. Deserialization of untrusted data can lead to security flaws.
|
||||
org.openrewrite.java.security.servlet.CookieSetSecure,Insecure cookies,Check for use of insecure cookies. Cookies should be marked as secure. This ensures that the cookie is sent only over HTTPS to prevent cross-site scripting attacks.
|
||||
org.openrewrite.java.security.XmlParserXXEVulnerability,XML parser XXE vulnerability,Avoid exposing dangerous features of the XML parser by updating certain factory settings.
|
||||
org.openrewrite.java.security.spring.CsrfProtection,Enable CSRF attack prevention,Cross-Site Request Forgery (CSRF) is a type of attack that occurs when a malicious web site email blog instant message or program causes a user's web browser to perform an unwanted action on a trusted site when the user is authenticated. See the full [OWASP cheatsheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html).
|
||||
org.openrewrite.java.security.OwaspTopTen,Remediate vulnerabilities from the OWASP Top Ten,[OWASP](https://owasp.org) publishes a list of the most impactful common security vulnerabilities. These recipes identify and remediate vulnerabilities from the OWASP Top Ten.
|
||||
org.openrewrite.java.security.OwaspA01,Remediate OWASP A01:2021 Broken access control,OWASP [A01:2021](https://owasp.org/Top10/A01_2021-Broken_Access_Control/) describes failures related to broken access control.
|
||||
org.openrewrite.java.security.OwaspA02,Remediate OWASP A02:2021 Cryptographic failures,OWASP [A02:2021](https://owasp.org/Top10/A02_2021-Cryptographic_Failures/) describes failures related to cryptography (or lack thereof) which often lead to exposure of sensitive data. This recipe seeks to remediate these vulnerabilities.
|
||||
org.openrewrite.java.security.OwaspA03,Remediate OWASP A03:2021 Injection,OWASP [A03:2021](https://owasp.org/Top10/A03_2021-Injection/) describes failures related to user-supplied data being used to influence program state to operate outside of its intended bounds. This recipe seeks to remediate these vulnerabilities.
|
||||
org.openrewrite.java.security.OwaspA05,Remediate OWASP A05:2021 Security misconfiguration,OWASP [A05:2021](https://owasp.org/Top10/A05_2021-Security_Misconfiguration/) describes failures related to security misconfiguration.
|
||||
org.openrewrite.java.security.OwaspA06,Remediate OWASP A06:2021 Vulnerable and outdated components,OWASP [A06:2021](https://owasp.org/Top10/A06_2021-Vulnerable_and_Outdated_Components/) describes failures related to vulnerable and outdated components.
|
||||
org.openrewrite.java.security.OwaspA08,Remediate OWASP A08:2021 Software and data integrity failures,OWASP [A08:2021](https://owasp.org/Top10/A08_2021-Software_and_Data_Integrity_Failures/) software and data integrity failures.
|
||||
org.openrewrite.java.spring.security6.PropagateAuthenticationServiceExceptions,Remove calls matching `AuthenticationEntryPointFailureHandler.setRethrowAuthenticationServiceException(true)`,Remove any calls matching `AuthenticationEntryPointFailureHandler.setRethrowAuthenticationServiceException(true)`. See the corresponding [Sprint Security 6.0 migration step](https://docs.spring.io/spring-security/reference/6.0.0/migration/servlet/authentication.html#_propagate_authenticationserviceexceptions) for details.
|
||||
|
@@ -0,0 +1,61 @@
|
||||
Fully Qualified Recipe Name,Recipe Name,Description
|
||||
io.moderne.java.spring.boot3.ConditionalOnAvailableEndpointMigrationSpring34,Migrate `ConditionalOnAvailableEndpoint` for Spring Boot 3.4,Migrate `@ConditionalOnAvailableEndpoint(EndpointExposure.CLOUD_FOUNDRY)` to `@ConditionalOnAvailableEndpoint(EndpointExposure.WEB)` for Spring Boot 3.4.
|
||||
io.moderne.java.spring.boot3.MigrateEndpointAnnotationAccessValueSpring34,Migrate `@Endpoint`s `defaultAccess` value,Since Spring Boot 3.4 the `@Endpoint` access configuration values are no longer `true|false` but `none|read-only|unrestricted`.
|
||||
io.moderne.java.spring.boot.MigrateSpringFrameworkDependenciesToSpringBoot,Migrate Spring Framework Dependencies to Spring Boot,Migrate Spring Framework Dependencies to Spring Boot.
|
||||
io.moderne.java.spring.boot3.SpringBootProperties_3_4,Migrate `@Endpoint` Security properties to 3.4,Migrate the settings for Spring Boot Management Endpoint Security from `true`|`false` to `read-only`|`none`.
|
||||
io.moderne.java.spring.boot3.UpgradeSpringBoot_3_5,Migrate to Spring Boot 3.5,Migrate applications to the latest Spring Boot 3.5 release. This recipe will modify an application's build files make changes to deprecated/preferred APIs and migrate configuration settings that have changes between versions. This recipe will also chain additional framework migrations (Spring Framework Spring Data etc) that are required as part of the migration to Spring Boot 3.5.
|
||||
io.moderne.java.spring.boot4.SpringBootProperties_4_0,Migrate Spring Boot properties to 4.0,Migrate properties found in `application.properties` and `application.yml`.
|
||||
io.moderne.java.spring.boot3.UpgradeSpringKafka_3_3,Migrate to Spring Kafka 3.3,Migrate applications to the latest Spring Kafka 3.3 release.
|
||||
io.moderne.java.spring.boot3.SpringBoot3BestPractices,Spring Boot 3.5 best practices,Applies best practices to Spring Boot 3.5+ applications.
|
||||
io.moderne.java.spring.boot.SpringToSpringBoot,Migrate Spring to Spring Boot,Migrate non Spring Boot applications to the latest compatible Spring Boot release. This recipe will modify an application's build files introducing Maven dependency management for Spring Boot or adding the Gradle Spring Boot build plugin.
|
||||
io.moderne.java.spring.boot3.SpringBoot35Deprecations,Migrate Spring Boot 3.5 deprecated classes and methods,Migrate deprecated classes and methods that have been marked for removal in Spring Boot 3.5.
|
||||
io.moderne.java.spring.boot3.UpgradeSpringBoot_3_4,Migrate to Spring Boot 3.4,Migrate applications to the latest Spring Boot 3.4 release. This recipe will modify an application's build files make changes to deprecated/preferred APIs and migrate configuration settings that have changes between versions. This recipe will also chain additional framework migrations (Spring Framework Spring Data etc) that are required as part of the migration to Spring Boot 3.4.
|
||||
io.moderne.java.spring.boot3.UpgradeGradle7Spring34,Upgrade Gradle to 7.6.4+ for Spring Boot 3.4,Spring Boot 3.4 requires Gradle 7.6.4.
|
||||
io.moderne.java.spring.boot3.UpgradeGradle8Spring34,Upgrade Gradle 8 to 8.4+ for Spring Boot 3.4,Spring Boot 3.4 requires Gradle 8.4+.
|
||||
io.moderne.java.spring.boot3.UpgradeMyBatisToSpringBoot_3_4,Upgrade MyBatis to Spring Boot 3.4,Upgrade MyBatis Spring modules to a version corresponding to Spring Boot 3.4.
|
||||
io.moderne.java.spring.boot3.UpgradeSpringCloudAWSToSpringBoot_3_4,Upgrade Spring Cloud AWS to Spring Boot 3.4 compatible version,Upgrade the Spring Cloud AWS dependency to a version compatible with Spring Boot 3.4.
|
||||
org.openrewrite.java.dropwizard.MigrateDropwizardToSpringBoot,Migrate Dropwizard to Spring Boot,Apply various changes to migrate Dropwizard applications to Spring Boot.
|
||||
org.openrewrite.java.spring.boot2.AddConfigurationAnnotationIfBeansPresent,Add missing `@Configuration` annotation,Class having `@Bean` annotation over any methods but missing `@Configuration` annotation over the declaring class would have `@Configuration` annotation added.
|
||||
org.openrewrite.java.spring.boot2.ConditionalOnBeanAnyNestedCondition,Migrate multi-condition `@ConditionalOnBean` annotations,Migrate multi-condition `@ConditionalOnBean` annotations to `AnyNestedCondition`.
|
||||
org.openrewrite.java.spring.boot2.MigrateActuatorMediaTypeToApiVersion,Migrate deprecated `ActuatorMediaType` to `ApiVersion#getProducedMimeType`,Spring Boot `ActuatorMediaType` was deprecated in 2.5 in favor of `ApiVersion#getProducedMimeType()`. Replace `MediaType.parseMediaType(ActuatorMediaType.Vx_JSON)` with `MediaType.asMediaType(ApiVersion.Vx.getProducedMimeType())`.
|
||||
org.openrewrite.java.spring.boot2.MigrateHsqlEmbeddedDatabaseConnection,Migrate deprecated Spring-Boot `EmbeddedDatabaseConnection.HSQL`,Spring-Boot `EmbeddedDatabaseConnection.HSQL` was deprecated in favor of `EmbeddedDatabaseConnection.HSQLDB` in 2.4.
|
||||
org.openrewrite.java.spring.boot2.MigrateLoggingSystemPropertyConstants,Migrate to recommended constants in `LogbackLoggingSystemProperties` from deprecated values in `LoggingSystemProperties`,Replaces field and static access of deprecated fields in `LoggingSystemProperties` with the recommendations from `LogbackLoggingSystemProperties`. Deprecated in 2.4.x and removed in 2.6.0.
|
||||
org.openrewrite.java.spring.boot2.OutputCaptureExtension,Migrate `@OutputCaptureRule` to `@ExtendWith(OutputCaptureExtension.class)`,Use the JUnit Jupiter extension instead of JUnit 4 rule.
|
||||
org.openrewrite.java.spring.boot2.RestTemplateBuilderRequestFactory,Migrate `RestTemplateBuilder`,Migrate `RestTemplateBuilder#requestFactory` calls to use a `Supplier`. See the [migration guide](https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Migration-Guide#resttemplatebuilder) for more.
|
||||
org.openrewrite.java.spring.boot3.AddValidToNestedConfigProperties,Add `@Valid` to nested properties in `@ConfigurationProperties`,Adds `@Valid` annotation to fields in `@ConfigurationProperties` classes that contain nested properties with validation constraints.
|
||||
org.openrewrite.java.spring.boot3.ConfigurationOverEnableSecurity,Add `@Configuration` to classes with `@EnableXXXSecurity` annotations,Prior to Spring Security 6 `@EnableXXXSecurity` implicitly had `@Configuration`. `Configuration` was removed from the definitions of the `@EnableSecurity` definitions in Spring Security 6. Consequently classes annotated with `@EnableXXXSecurity` coming from pre-Boot 3 should have `@Configuration` annotation added.
|
||||
org.openrewrite.java.spring.boot3.MigrateWebMvcTagsToObservationConvention,Migrate `WebMvcTagsProvider` to `DefaultServerRequestObservationConvention`,Migrate `WebMvcTagsProvider` to `DefaultServerRequestObservationConvention` as part of Spring Boot 3.2 removals.
|
||||
org.openrewrite.maven.spring.UpgradeExplicitSpringBootDependencies,Upgrade Spring dependencies,Upgrades dependencies according to the specified version of spring boot. Spring boot has many direct and transitive dependencies. When a module has an explicit dependency on one of these it may also need to be upgraded to match the version used by spring boot.
|
||||
org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_2,Migrate to Spring Boot 3.2,Migrate applications to the latest Spring Boot 3.2 release. This recipe will modify an application's build files make changes to deprecated/preferred APIs and migrate configuration settings that have changes between versions. This recipe will also chain additional framework migrations (Spring Framework Spring Data etc) that are required as part of the migration to Spring Boot 3.1.
|
||||
org.openrewrite.java.spring.boot3.UpgradeMyBatisToSpringBoot_3_2,Upgrade MyBatis to Spring Boot 3.2,Upgrade MyBatis Spring modules to a version corresponding to Spring Boot 3.2.
|
||||
org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_3,Migrate to Spring Boot 2.3,Migrate applications to the latest Spring Boot 2.3 release. This recipe will modify an application's build files make changes to deprecated/preferred APIs and migrate configuration settings that have changes between versions. This recipe will also chain additional framework migrations (Spring Framework Spring Data etc) that are required as part of the migration to Spring Boot 2.3.
|
||||
org.openrewrite.java.spring.boot3.UpgradeMyBatisToSpringBoot_2_3,Upgrade MyBatis to Spring Boot 2.3,Upgrade MyBatis Spring modules to a version corresponding to Spring Boot 2.3.
|
||||
org.openrewrite.java.spring.boot3.SpringBootProperties_3_5,Migrate Spring Boot properties to 3.5,Migrate properties found in `application.properties` and `application.yml`.
|
||||
org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_3,Migrate to Spring Boot 3.3,Migrate applications to the latest Spring Boot 3.3 release. This recipe will modify an application's build files make changes to deprecated/preferred APIs and migrate configuration settings that have changes between versions. This recipe will also chain additional framework migrations (Spring Framework Spring Data etc) that are required as part of the migration to Spring Boot 3.2.
|
||||
org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_4,Migrate to Spring Boot 2.4,Migrate applications to the latest Spring Boot 2.4 release. This recipe will modify an application's build files make changes to deprecated/preferred APIs and migrate configuration settings that have changes between versions. This recipe will also chain additional framework migrations (Spring Framework Spring Data etc) that are required as part of the migration to Spring Boot 2.4.
|
||||
org.openrewrite.java.spring.boot2.SpringBoot2JUnit4to5Migration,Migrate Spring Boot 2.x projects to JUnit 5 from JUnit 4,This recipe will migrate a Spring Boot application's tests from JUnit 4 to JUnit 5. This spring-specific migration includes conversion of Spring Test runners to Spring Test extensions and awareness of the composable Spring Test annotations.
|
||||
org.openrewrite.java.spring.boot3.UpgradeMyBatisToSpringBoot_2_4,Upgrade MyBatis to Spring Boot 2.4,Upgrade MyBatis Spring modules to a version corresponding to Spring Boot 2.4.
|
||||
org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_2,Migrate to Spring Boot 2.2,Migrate applications to the latest Spring Boot 2.2 release. This recipe will modify an application's build files make changes to deprecated/preferred APIs and migrate configuration settings that have changes between versions. This recipe will also chain additional framework migrations (Spring Framework Spring Data etc) that are required as part of the migration to Spring Boot 2.2.
|
||||
org.openrewrite.java.spring.boot3.UpgradeMyBatisToSpringBoot_2_2,Upgrade MyBatis to Spring Boot 2.2,Upgrade MyBatis Spring modules to a version corresponding to Spring Boot 2.2.
|
||||
org.openrewrite.java.spring.boot2.SpringBootProperties_2_5,Migrate Spring Boot properties to 2.5,Migrate properties found in `application.properties` and `application.yml`.
|
||||
org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_1,Migrate to Spring Boot 3.1,Migrate applications to the latest Spring Boot 3.1 release. This recipe will modify an application's build files make changes to deprecated/preferred APIs and migrate configuration settings that have changes between versions. This recipe will also chain additional framework migrations (Spring Framework Spring Data etc) that are required as part of the migration to Spring Boot 3.0.
|
||||
org.openrewrite.java.spring.boot2.SpringBootProperties_2_1,Migrate Spring Boot properties to 2.1,Migrate properties found in `application.properties` and `application.yml`.
|
||||
org.openrewrite.java.spring.boot2.SpringBootProperties_2_6,Migrate Spring Boot properties to 2.6,Migrate properties found in `application.properties` and `application.yml`.
|
||||
org.openrewrite.java.spring.boot3.SpringBootProperties_3_4,Migrate Spring Boot properties to 3.4,Migrate properties found in `application.properties` and `application.yml`.
|
||||
org.openrewrite.java.spring.boot3.SpringBootProperties_3_4_EnabledToAccess,Migrate Enabled to Access Spring Boot Properties,Migrate properties found in `application.properties` and `application.yml` specifically converting 'enabled' to 'access'
|
||||
org.openrewrite.java.spring.boot3.SpringBootProperties_3_2,Migrate Spring Boot properties to 3.2,Migrate properties found in `application.properties` and `application.yml`.
|
||||
org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_6,Migrate to Spring Boot 2.6,Migrate applications to the latest Spring Boot 2.6 release. This recipe will modify an application's build files make changes to deprecated/preferred APIs and migrate configuration settings that have changes between versions. This recipe will also chain additional framework migrations (Spring Framework Spring Data etc) that are required as part of the migration to Spring Boot 2.6.
|
||||
org.openrewrite.java.spring.boot3.UpgradeMyBatisToSpringBoot_2_6,Upgrade MyBatis to Spring Boot 2.6,Upgrade MyBatis Spring modules to a version corresponding to Spring Boot 2.6.
|
||||
org.openrewrite.java.spring.boot3.SpringBoot33BestPractices,Spring Boot 3.3 best practices,Applies best practices to Spring Boot 3 applications.
|
||||
org.openrewrite.java.spring.boot3.SpringBoot3BestPracticesOnly,Spring Boot 3.3 best practices (only),Applies best practices to Spring Boot 3 applications without chaining in upgrades to Spring Boot.
|
||||
org.openrewrite.java.spring.boot2.SpringBootProperties_2_0,Migrate Spring Boot properties to 2.0,Migrate properties found in `application.properties` and `application.yml`.
|
||||
org.openrewrite.java.spring.boot3.SpringBootProperties_3_3,Migrate Spring Boot properties to 3.3,Migrate properties found in `application.properties` and `application.yml`.
|
||||
org.openrewrite.java.spring.boot3.SpringBootProperties_3_0,Migrate Spring Boot properties to 3.0,Migrate properties found in `application.properties` and `application.yml`.
|
||||
org.openrewrite.java.spring.boot2.SpringBootProperties_2_2,Migrate Spring Boot properties to 2.2,Migrate properties found in `application.properties` and `application.yml`.
|
||||
org.openrewrite.java.spring.boot2.SpringBootProperties_2_4,Migrate Spring Boot properties to 2.4,Migrate properties found in `application.properties` and `application.yml`.
|
||||
org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_0,Migrate from Spring Boot 1.x to 2.0,Migrate Spring Boot 1.x applications to the latest Spring Boot 2.0 release. This recipe will modify an application's build files make changes to deprecated/preferred APIs and migrate configuration settings that have changes between versions. This recipe will also chain additional framework migrations (Spring Framework Spring Data etc) that are required as part of the migration to Spring Boot 2.0.
|
||||
org.openrewrite.java.spring.boot3.UpgradeMyBatisToSpringBoot_2_0,Upgrade MyBatis to Spring Boot 2.0,Upgrade MyBatis Spring modules to a version corresponding to Spring Boot 2.0.
|
||||
org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_7,Migrate to Spring Boot 2.7,Upgrade to Spring Boot 2.7.
|
||||
org.openrewrite.java.spring.boot3.UpgradeMyBatisToSpringBoot_2_7,Upgrade MyBatis to Spring Boot 2.7,Upgrade MyBatis Spring modules to a version corresponding to Spring Boot 2.7.
|
||||
org.openrewrite.java.spring.boot2.SpringBootProperties_2_7,Migrate Spring Boot properties to 2.7,Migrate properties found in `application.properties` and `application.yml`.
|
||||
org.openrewrite.java.spring.boot2.SpringBootProperties_2_3,Migrate Spring Boot properties to 2.3,Migrate properties found in `application.properties` and `application.yml`.
|
||||
|
@@ -0,0 +1,51 @@
|
||||
Fully Qualified Recipe Name,Recipe Name,Description
|
||||
io.moderne.cryptography.FindRSAKeyGenParameters,Find RSA key generation parameters,Finds RSAKeyGenParameterSpec instantiations and extracts their parameter values into a data table.
|
||||
io.moderne.cryptography.FindSSLSocketParameters,Find SSL socket configuration parameters,Finds SSLSocket setter method invocations and extracts their parameter values into a data table.
|
||||
io.moderne.cryptography.FindSecurityModifications,Find Security class modifications,Finds invocations of java.security.Security methods that modify security configuration such as removeProvider addProvider insertProviderAt setProperty and removeProperty.
|
||||
io.moderne.cryptography.FindSecuritySetProperties,Find `Security.setProperty(..)` calls for certain properties,There is a defined set of properties that should not be set using `Security.setProperty(..)` as they can lead to security vulnerabilities.
|
||||
io.moderne.hibernate.search.FindJPQLDefinitions,Find JPQL definitions,Find Java Persistence Query Language definitions in the codebase.
|
||||
org.openrewrite.analysis.java.FindNullPointerIssues,Find null pointer issues,Detects potential null pointer dereferences using path-sensitive analysis to distinguish between definite NPEs possible NPEs and safe dereferences.
|
||||
org.openrewrite.analysis.java.controlflow.FindUnusedDefinitions,Find unused variable definitions,Identifies variable assignments whose values are never used before being overwritten.
|
||||
org.openrewrite.analysis.java.controlflow.search.FindCyclomaticComplexity,Find cyclomatic complexity,Calculates the cyclomatic complexity of methods and produces a data table containing the class name method name argument types complexity value and complexity threshold.
|
||||
org.openrewrite.analysis.java.controlflow.search.FindUnreachableCode,Find unreachable code,Uses control flow analysis to identify statements that can never be executed.
|
||||
org.openrewrite.analysis.java.dataflow.FindDeadStores,Find dead stores,Identifies variable assignments whose values are never used before being overwritten or going out of scope.
|
||||
org.openrewrite.analysis.java.security.FindSecurityVulnerabilities,Find security vulnerabilities using taint analysis,Identifies potential security vulnerabilities where untrusted data from sources flows to sensitive sinks without proper sanitization.
|
||||
org.openrewrite.analysis.java.datalineage.TrackDataLineage,Track data lineage,Tracks the flow of data from database sources (JDBC queries JPA entities) to API sinks (REST endpoints GraphQL mutations) to understand data dependencies and support compliance requirements.
|
||||
org.openrewrite.analysis.java.privacy.FindPiiExposure,Find PII exposure in logs and external APIs,Detects when Personally Identifiable Information (PII) is exposed through logging statements or sent to external APIs without proper sanitization. This helps prevent data leaks and ensures compliance with privacy regulations like GDPR and CCPA.
|
||||
org.openrewrite.analysis.java.security.FindCommandInjection,Find command injection vulnerabilities,Detects when user-controlled input flows into system command execution methods like Runtime.exec() or ProcessBuilder which could allow attackers to execute arbitrary commands.
|
||||
org.openrewrite.analysis.java.security.FindLdapInjection,Find LDAP injection vulnerabilities,Finds LDAP injection vulnerabilities by tracking tainted data flow from user input to LDAP queries.
|
||||
org.openrewrite.analysis.java.security.FindPathTraversal,Find path traversal vulnerabilities,Detects potential path traversal vulnerabilities where user input flows to file system operations without proper validation.
|
||||
org.openrewrite.analysis.java.security.FindSqlInjection,Find SQL injection vulnerabilities,Detects potential SQL injection vulnerabilities where user input flows to SQL execution methods without proper sanitization.
|
||||
org.openrewrite.analysis.java.security.FindUnencryptedPiiStorage,Find unencrypted PII storage,Identifies when personally identifiable information (PII) is stored in databases files or other persistent storage without encryption.
|
||||
org.openrewrite.analysis.java.security.FindXssVulnerability,Find XSS vulnerabilities,Detects potential cross-site scripting vulnerabilities where user input flows to output methods without proper sanitization.
|
||||
org.openrewrite.analysis.java.security.FindXxeVulnerability,Find XXE vulnerabilities,Locates XML parsers that are not configured to prevent XML External Entity (XXE) attacks.
|
||||
io.moderne.vulncheck.FixVulnCheckVulnerabilities,Use [VulnCheck Exploit Intelligence](https://docs.vulncheck.com/products/exploit-and-vulnerability-intelligence/exploit-intelligence) to fix vulnerabilities,This software composition analysis (SCA) tool detects and upgrades dependencies with publicly disclosed vulnerabilities. This recipe both generates a report of vulnerable dependencies and upgrades to newer versions with fixes. This recipe by default only upgrades to the latest **patch** version. If a minor or major upgrade is required to reach the fixed version this can be controlled using the `maximumUpgradeDelta` option. Vulnerability information comes from VulnCheck Vulnerability Intelligence. The recipe has an option to limit fixes to only those vulnerabilities that have evidence of exploitation at various levels of severity.
|
||||
org.openrewrite.FindCollidingSourceFiles,Find colliding source files,Finds source files which share a path with another source file. There should always be exactly one source file per path within a repository. This is a diagnostic for finding problems in OpenRewrite parsers/build plugins.
|
||||
org.openrewrite.FindDeserializationErrors,Find deserialization errors,Produces a data table collecting all deserialization errors of serialized LSTs.
|
||||
org.openrewrite.FindLstProvenance,Find LST provenance,Produces a data table showing what versions of OpenRewrite/Moderne tooling was used to produce a given LST.
|
||||
org.openrewrite.FindParseFailures,Find source files with `ParseExceptionResult` markers,This recipe explores parse failures after an LST is produced for classifying the types of failures that can occur and prioritizing fixes according to the most common problems.
|
||||
org.openrewrite.FindQuarks,Find instances of type `Quark`,`Quark` source files are pointers to the existence of a file without capturing any of the contents of the file.
|
||||
org.openrewrite.FindSourceFiles,Find files,Find files by source path. Paths are always interpreted as relative to the repository root.
|
||||
org.openrewrite.search.FindBuildMetadata,Find build metadata,Find source files with matching build metadata.
|
||||
org.openrewrite.search.FindCommitters,Find committers on repositories,List the committers on a repository.
|
||||
org.openrewrite.search.FindParseToPrintInequality,Find parse to print inequality,OpenRewrite `Parser` implementations should produce `SourceFile` objects whose `printAll()` method should be byte-for-byte equivalent with the original source file. When this isn't true recipes can still run on the `SourceFile` and even produce diffs but the diffs would fail to apply as a patch to the original source file. Most `Parser` use `Parser#requirePrintEqualsInput` to produce a `ParseError` when they fail to produce a `SourceFile` that is print idempotent.
|
||||
org.openrewrite.search.RepositoryContainsFile,Repository contains file,Intended to be used primarily as a precondition for other recipes this recipe checks if a repository contains a specific file or files matching a pattern. If present all files in the repository are marked with a `SearchResult` marker. If you want to get only the matching file as a search result use `FindSourceFiles` instead.
|
||||
org.openrewrite.text.Find,Find text,Textual search optionally using Regular Expression (regex) to query.
|
||||
org.openrewrite.text.FindAndReplace,Find and replace,Textual find and replace optionally interpreting the search query as a Regular Expression (regex). When operating on source files that are language-specific Lossless Semantic Tree such as Java or XML this operation converts the source file to plain text for the rest of the recipe run. So if you are combining this recipe with language-specific recipes in a single recipe run put all the language-specific recipes before this recipe.
|
||||
org.openrewrite.gradle.search.FindDependency,Find Gradle dependency,"Finds dependencies declared in gradle build files. See the [reference](https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_configurations_graph) on Gradle configurations or the diagram below for a description of what configuration to use. A project's compile and runtime classpath is based on these configurations. <img alt=""Gradle compile classpath"" src=""https://docs.gradle.org/current/userguide/img/java-library-ignore-deprecated-main.png"" width=""200px""/> A project's test classpath is based on these configurations. <img alt=""Gradle test classpath"" src=""https://docs.gradle.org/current/userguide/img/java-library-ignore-deprecated-test.png"" width=""200px""/>."
|
||||
org.openrewrite.gradle.search.FindDependencyHandler,Find Gradle `dependencies` blocks,Find the dependency handler containing any number of dependency definitions.
|
||||
org.openrewrite.gradle.search.FindGradleProject,Find Gradle projects,Gradle projects are those with `build.gradle` or `build.gradle.kts` files.
|
||||
org.openrewrite.gradle.search.FindGradleWrapper,Find Gradle wrappers,Find Gradle wrappers.
|
||||
org.openrewrite.gradle.search.FindJVMTestSuites,Find Gradle JVMTestSuite plugin configuration,Find Gradle JVMTestSuite plugin configurations and produce a data table.
|
||||
org.openrewrite.gradle.search.FindPlugins,Find Gradle plugin,Find a Gradle plugin by id and/or class name. For best results both should be specified as one cannot automatically be used to infer the other.
|
||||
org.openrewrite.gradle.search.FindRepository,Find Gradle repository,Find a Gradle repository by url.
|
||||
org.openrewrite.hcl.search.FindAndReplaceLiteral,Find and replace literals in HCL files,Find and replace literal values in HCL files. This recipe parses the source files on which it runs as HCL meaning you can execute HCL language-specific recipes before and after this recipe in a single recipe run.
|
||||
org.openrewrite.hcl.search.FindContent,Find content,Find HCL content by path.
|
||||
org.openrewrite.java.search.FindAnnotations,Find annotations,Find all annotations matching the annotation pattern.
|
||||
org.openrewrite.java.search.FindClassHierarchy,Find class hierarchy,Discovers all class declarations within a project recording which files they appear in their superclasses and interfaces. That information is then recorded in a data table.
|
||||
org.openrewrite.java.search.FindComments,Find within comments and literals,"Find regular expression matches within comments and literals. ""Literals"" includes string literals character literals and numeric literals."
|
||||
org.openrewrite.java.search.FindCompileErrors,Find compile errors,Compile errors result in a particular LST structure that can be searched for.
|
||||
org.openrewrite.java.search.FindDeprecatedClasses,Find uses of deprecated classes,Find uses of deprecated classes optionally ignoring those classes that are inside deprecated scopes.
|
||||
org.openrewrite.java.search.FindDeprecatedFields,Find uses of deprecated fields,Find uses of deprecated fields in any API.
|
||||
org.openrewrite.java.search.FindDeprecatedMethods,Find uses of deprecated methods,Find uses of deprecated methods in any API.
|
||||
org.openrewrite.java.search.FindDeprecatedUses,Find uses of deprecated classes methods and fields,Find deprecated uses of methods fields and types. Optionally ignore those classes that are inside deprecated scopes.
|
||||
|
@@ -0,0 +1,61 @@
|
||||
Fully Qualified Recipe Name,Recipe Name,Description
|
||||
org.openrewrite.java.spring.test.SpringRulesToJUnitExtension,Replace `SpringClassRule` and `SpringMethodRule` with JUnit 5 `SpringExtension`,Replace JUnit 4's `SpringClassRule` and `SpringMethodRule` with JUnit 5's `SpringExtension` or rely on an existing `@SpringBootTest`.
|
||||
org.openrewrite.java.spring.boot2.SpringBoot2JUnit4to5Migration,Migrate Spring Boot 2.x projects to JUnit 5 from JUnit 4,This recipe will migrate a Spring Boot application's tests from JUnit 4 to JUnit 5. This spring-specific migration includes conversion of Spring Test runners to Spring Test extensions and awareness of the composable Spring Test annotations.
|
||||
org.openrewrite.java.testing.assertj.AdoptAssertJDurationAssertions,Adopt AssertJ Duration assertions,Adopt AssertJ `DurationAssert` assertions for more expressive messages.
|
||||
org.openrewrite.java.testing.assertj.CollapseConsecutiveAssertThatStatements,Collapse consecutive `assertThat` statements,Collapse consecutive `assertThat` statements into single `assertThat` chained statement. This recipe ignores `assertThat` statements that have method invocation as parameter.
|
||||
org.openrewrite.java.testing.assertj.IsEqualToIgnoringMillisToIsCloseToRecipe,Replace `AbstractDateAssert#isEqualToIgnoringMillis(java.util.Date)` by `by isCloseTo(Date long)`,`isEqualToIgnoringMillis()` is deprecated in favor of `isCloseTo()`.
|
||||
org.openrewrite.java.testing.assertj.JUnitAssertArrayEqualsToAssertThat,JUnit `assertArrayEquals` to assertJ,Convert JUnit-style `assertArrayEquals()` to AssertJ's `assertThat().contains()` equivalents.
|
||||
org.openrewrite.java.testing.assertj.JUnitAssertEqualsToAssertThat,JUnit `assertEquals` to AssertJ,Convert JUnit-style `assertEquals()` to AssertJ's `assertThat().isEqualTo()`.
|
||||
org.openrewrite.java.testing.assertj.JUnitAssertFalseToAssertThat,JUnit `assertFalse` to AssertJ,Convert JUnit-style `assertFalse()` to AssertJ's `assertThat().isFalse()`.
|
||||
org.openrewrite.java.testing.assertj.JUnitAssertInstanceOfToAssertThat,JUnit `assertInstanceOf` to AssertJ,Convert JUnit-style `assertInstanceOf()` to AssertJ's `assertThat().isInstanceOf()`.
|
||||
org.openrewrite.java.testing.assertj.JUnitAssertNotEqualsToAssertThat,JUnit `assertNotEquals` to AssertJ,Convert JUnit-style `assertNotEquals()` to AssertJ's `assertThat().isNotEqualTo()`.
|
||||
org.openrewrite.java.testing.assertj.JUnitAssertNotNullToAssertThat,JUnit `assertNotNull` to AssertJ,Convert JUnit-style `assertNotNull()` to AssertJ's `assertThat().isNotNull()`.
|
||||
org.openrewrite.java.testing.assertj.JUnitAssertNullToAssertThat,JUnit `assertNull` to AssertJ,Convert JUnit-style `assertNull()` to AssertJ's `assertThat().isNull()`.
|
||||
org.openrewrite.java.testing.assertj.JUnitAssertSameToAssertThat,JUnit `assertSame` to AssertJ,Convert JUnit-style `assertSame()` to AssertJ's `assertThat().isSameAs()`.
|
||||
org.openrewrite.java.testing.assertj.JUnitAssertThrowsToAssertExceptionType,JUnit AssertThrows to AssertJ exceptionType,Convert `JUnit#AssertThrows` to `AssertJ#assertThatExceptionOfType` to allow for chained assertions on the thrown exception.
|
||||
org.openrewrite.java.testing.assertj.JUnitAssertTrueToAssertThat,JUnit `assertTrue` to AssertJ,Convert JUnit-style `assertTrue()` to AssertJ's `assertThat().isTrue()`.
|
||||
org.openrewrite.java.testing.assertj.JUnitFailToAssertJFail,JUnit fail to AssertJ,Convert JUnit-style `fail()` to AssertJ's `fail()`.
|
||||
org.openrewrite.java.testing.assertj.JUnitTryFailToAssertThatThrownBy,Convert try-catch-fail blocks to AssertJ's assertThatThrownBy,Replace try-catch blocks where the try block ends with a `fail()` statement and the catch block optionally contains assertions with AssertJ's `assertThatThrownBy()`.
|
||||
org.openrewrite.java.testing.assertj.SimplifyAssertJAssertion,Simplify AssertJ assertions with literal arguments,Simplify AssertJ assertions by replacing them with more expressive dedicated assertions.
|
||||
org.openrewrite.java.testing.assertj.SimplifyChainedAssertJAssertion,Simplify AssertJ chained assertions,Many AssertJ chained assertions have dedicated assertions that function the same. It is best to use the dedicated assertions.
|
||||
org.openrewrite.java.testing.assertj.SimplifyHasSizeAssertion,Simplify AssertJ assertions with `hasSize` argument,Simplify AssertJ assertions by replacing `hasSize` with `hasSameSizeAs` dedicated assertions.
|
||||
org.openrewrite.java.testing.assertj.SimplifyRedundantAssertJChains,Simplify redundant AssertJ assertion chains,Removes redundant AssertJ assertions when chained methods already provide the same or stronger guarantees.
|
||||
org.openrewrite.java.testing.cleanup.AssertEqualsBooleanToAssertBoolean,Replace JUnit `assertEquals(false <boolean>)` to `assertFalse(<boolean>)` / `assertTrue(<boolean>)`,Using `assertFalse` or `assertTrue` is simpler and more clear.
|
||||
org.openrewrite.java.testing.cleanup.AssertEqualsNullToAssertNull,`assertEquals(a null)` to `assertNull(a)`,Using `assertNull(a)` is simpler and more clear.
|
||||
org.openrewrite.java.testing.cleanup.AssertFalseEqualsToAssertNotEquals,Replace JUnit `assertFalse(a.equals(b))` to `assertNotEquals(ab)`,Using `assertNotEquals(ab)` is simpler and more clear.
|
||||
org.openrewrite.java.testing.cleanup.AssertFalseNegationToAssertTrue,Replace JUnit `assertFalse(!<boolean>)` to `assertTrue(<boolean>)`,Using `assertTrue` is simpler and more clear.
|
||||
org.openrewrite.java.testing.cleanup.AssertFalseNullToAssertNotNull,Replace JUnit `assertFalse(a == null)` to `assertNotNull(a)`,Using `assertNotNull(a)` is simpler and more clear.
|
||||
org.openrewrite.java.testing.cleanup.AssertLiteralBooleanRemovedRecipe,Remove JUnit `assertTrue(true)` and `assertFalse(false)`,These assertions are redundant and do not provide any value. They can be safely removed.
|
||||
org.openrewrite.java.testing.cleanup.AssertLiteralBooleanToFailRecipes,"Replace JUnit `assertTrue(false ""reason"")` and `assertFalse(true ""reason"")` with `fail(""reason"")`",Using fail is more direct and clear.
|
||||
org.openrewrite.java.testing.cleanup.AssertNotEqualsBooleanToAssertBoolean,Replace JUnit `assertNotEquals(false <boolean>)` to `assertFalse(<boolean>)` / `assertTrue(<boolean>)`,Using `assertFalse` or `assertTrue` is simpler and more clear.
|
||||
org.openrewrite.java.testing.cleanup.AssertTrueComparisonToAssertEquals,Junit `assertTrue(a == b)` to `assertEquals(ab)`,Using `assertEquals(ab)` is simpler and more clear.
|
||||
org.openrewrite.java.testing.cleanup.AssertTrueEqualsToAssertEquals,Replace JUnit `assertTrue(a.equals(b))` to `assertEquals(ab)`,Using `assertEquals(ab)` is simpler and more clear.
|
||||
org.openrewrite.java.testing.cleanup.AssertTrueNegationToAssertFalse,Replace JUnit `assertTrue(!<boolean>)` to `assertFalse(<boolean>)`,Using `assertFalse` is simpler and more clear.
|
||||
org.openrewrite.java.testing.cleanup.AssertTrueNullToAssertNull,Replace JUnit `assertTrue(a == null)` to `assertNull(a)`,Using `assertNull(a)` is simpler and more clear.
|
||||
org.openrewrite.java.testing.cleanup.AssertionsArgumentOrder,Assertion arguments should be passed in the correct order,Assertions such as `org.junit.Assert.assertEquals` expect the first argument to be the expected value and the second argument to be the actual value; for `org.testng.Assert` it’s the other way around. This recipe detects `J.Literal` `J.NewArray` and `java.util.Iterable` arguments swapping them if necessary so that the error messages won't be confusing.
|
||||
org.openrewrite.java.testing.cleanup.RemoveEmptyTests,Remove empty tests without comments,Removes empty methods with a `@Test` annotation if the body does not have comments.
|
||||
org.openrewrite.java.testing.cleanup.RemoveTestPrefix,Remove `test` prefix from JUnit 5 tests,Remove `test` from methods with `@Test` `@ParameterizedTest` `@RepeatedTest` or `@TestFactory`. They no longer have to prefix test to be usable by JUnit 5.
|
||||
org.openrewrite.java.testing.cleanup.SimplifyTestThrows,Simplify `throws` statements of tests,Replace all thrown exception classes of test method signatures by `Exception`.
|
||||
org.openrewrite.java.testing.cleanup.TestMethodsShouldBeVoid,Test methods should have void return type,Test methods annotated with `@Test` `@ParameterizedTest` `@RepeatedTest` `@TestTemplate` should have `void` return type. Non-void return types can cause test discovery issues and warnings as of JUnit 5.13+. This recipe changes the return type to `void` and removes `return` statements.
|
||||
org.openrewrite.java.testing.cleanup.TestsShouldIncludeAssertions,Include an assertion in tests,For tests not having any assertions wrap the statements with JUnit Jupiter's `Assertions#assertDoesNotThrow(..)`.
|
||||
org.openrewrite.java.testing.dbrider.ExecutionListenerToDbRiderAnnotation,Migrate the `DBRiderTestExecutionListener` to the `@DBRider` annotation,Migrate the `DBRiderTestExecutionListener` to the `@DBRider` annotation. This recipe is useful when migrating from JUnit 4 `dbrider-spring` to JUnit 5 `dbrider-junit5`.
|
||||
org.openrewrite.java.testing.easymock.EasyMockVerifyToMockitoVerify,Replace EasyMock `verify` calls with Mockito `verify` calls,Replace `EasyMock.verify(dependency)` with individual `Mockito.verify(dependency).method()` calls based on expected methods.
|
||||
org.openrewrite.java.testing.easymock.RemoveExtendsEasyMockSupport,Migrate Test classes that extend `org.easymock.EasyMockSupport` to use Mockito,Modify test classes by removing extends EasyMockSupport and replacing EasyMock methods with Mockito equivalents.
|
||||
org.openrewrite.java.testing.hamcrest.AssertThatBooleanToAssertJ,Migrate Hamcrest `assertThat(boolean Matcher)` to AssertJ,Replace Hamcrest `assertThat(String boolean)` with AssertJ `assertThat(boolean).as(String).isTrue()`.
|
||||
org.openrewrite.java.testing.hamcrest.HamcrestInstanceOfToJUnit5,Migrate from Hamcrest `instanceOf` matcher to JUnit 5,Migrate from Hamcrest `instanceOf` and `isA` matcher to JUnit5 `assertInstanceOf` assertion.
|
||||
org.openrewrite.java.testing.hamcrest.HamcrestIsMatcherToAssertJ,Migrate Hamcrest `is(Object)` to AssertJ,Migrate Hamcrest `is(Object)` to AssertJ `Assertions.assertThat(..)`.
|
||||
org.openrewrite.java.testing.hamcrest.HamcrestMatcherToAssertJ,Migrate from Hamcrest `Matcher` to AssertJ,Migrate from Hamcrest `Matcher` to AssertJ assertions.
|
||||
org.openrewrite.java.testing.hamcrest.HamcrestMatcherToJUnit5,Migrate from Hamcrest `Matcher` to JUnit 5,Migrate from Hamcrest `Matcher` to JUnit 5 assertions.
|
||||
org.openrewrite.java.testing.hamcrest.HamcrestNotMatcherToAssertJ,Migrate Hamcrest `not(Matcher)` to AssertJ,Migrate from Hamcrest `not(Matcher)` to AssertJ assertions.
|
||||
org.openrewrite.java.testing.hamcrest.HamcrestOfMatchersToAssertJ,Migrate `anyOf` Hamcrest Matcher to AssertJ,Migrate the `anyOf` Hamcrest Matcher to AssertJ's `satisfiesAnyOf` assertion.
|
||||
org.openrewrite.java.testing.jmockit.JMockitAnnotatedArgumentToMockito,Convert JMockit `@Mocked` and `@Injectable` annotated arguments,Convert JMockit `@Mocked` and `@Injectable` annotated arguments into Mockito statements.
|
||||
org.openrewrite.java.testing.jmockit.JMockitBlockToMockito,Rewrite JMockit Expectations NonStrictExpectations Verifications VerificationsInOrder FullVerifications,Rewrites JMockit `Expectations NonStrictExpectations Verifications VerificationsInOrder FullVerifications` blocks to Mockito statements.
|
||||
org.openrewrite.java.testing.jmockit.JMockitMockUpToMockito,Rewrite JMockit MockUp to Mockito statements,Rewrites JMockit `MockUp` blocks to Mockito statements. This recipe will not rewrite private methods in MockUp.
|
||||
org.openrewrite.java.testing.junit5.AddMissingNested,JUnit 5 inner test classes should be annotated with `@Nested`,Adds `@Nested` to inner classes that contain JUnit 5 tests.
|
||||
org.openrewrite.java.testing.junit5.AddMissingTestBeforeAfterAnnotations,Add missing `@BeforeEach` `@AfterEach` `@Test` to overriding methods,Adds `@BeforeEach` `@AfterEach` `@Test` to methods overriding superclass methods if the annotations are present on the superclass method.
|
||||
org.openrewrite.java.testing.junit5.AddParameterizedTestAnnotation,Add missing `@ParameterizedTest` annotation when `@ValueSource` is used or replace `@Test` with `@ParameterizedTest`,Add missing `@ParameterizedTest` annotation when `@ValueSource` is used or replace `@Test` with `@ParameterizedTest`.
|
||||
org.openrewrite.java.testing.junit5.AssertThrowsOnLastStatement,Applies JUnit 5 `assertThrows` on last statement in lambda block only,Applies JUnit 5 `assertThrows` on last statement in lambda block only. In rare cases may cause compilation errors if the lambda uses effectively non final variables. In some cases tests might fail if earlier statements in the lambda block throw exceptions.
|
||||
org.openrewrite.java.testing.junit5.AssertToAssertions,JUnit 4 `Assert` To JUnit Jupiter `Assertions`,Change JUnit 4's `org.junit.Assert` into JUnit Jupiter's `org.junit.jupiter.api.Assertions`.
|
||||
org.openrewrite.java.testing.junit5.AssertTrueInstanceofToAssertInstanceOf,assertTrue(x instanceof y) to assertInstanceOf(y.class x),Migration of JUnit4 (or potentially JUnit5) test case in form of assertTrue(x instanceof y) to assertInstanceOf(y.class x).
|
||||
org.openrewrite.java.testing.junit5.CleanupJUnitImports,Cleanup JUnit imports,Removes unused `org.junit` import symbols.
|
||||
org.openrewrite.java.testing.junit5.EnvironmentVariables,Migrate JUnit 4 environmentVariables rule to JUnit 5 system stubs extension,Replaces usage of the JUnit 4 `@Rule EnvironmentVariables` with the JUnit 5-compatible `SystemStubsExtension` and `@SystemStub EnvironmentVariables` from the System Stubs library.
|
||||
|
@@ -0,0 +1,51 @@
|
||||
Fully Qualified Recipe Name,Recipe Name,Description
|
||||
org.openrewrite.DeleteSourceFiles,Delete files,Delete files by source path.
|
||||
org.openrewrite.MoveFile,Move a file,Move a file to a different directory. The file name will remain the same.
|
||||
org.openrewrite.RenameFile,Rename a file,Rename a file while keeping it in the same directory.
|
||||
org.openrewrite.SetFilePermissions,Set file permission attributes,Set a file's read write and executable permission attributes.
|
||||
org.openrewrite.text.AppendToTextFile,Append to text file,Appends or replaces content of an existing plain text file or creates a new one if it doesn't already exist. Please note that this recipes requires existing plain text files' format to be successfully parsable by OpenRewrite. If a file is left unchanged it might be parsed as a `Quark` rather than plain text. In such case use the `plainTextMask` option. See the [Gradle](https://docs.openrewrite.org/reference/gradle-plugin-configuration#configuring-the-rewrite-dsl) or [Maven](https://openrewrite.github.io/rewrite-maven-plugin/run-mojo.html#plainTextMasks) plugin configuration page.
|
||||
org.openrewrite.text.ChangeText,Change text,Completely replaces the contents of the text file with other text. Use together with a `FindSourceFiles` precondition to limit which files are changed.
|
||||
org.openrewrite.text.FindAndReplace,Find and replace,Textual find and replace optionally interpreting the search query as a Regular Expression (regex). When operating on source files that are language-specific Lossless Semantic Tree such as Java or XML this operation converts the source file to plain text for the rest of the recipe run. So if you are combining this recipe with language-specific recipes in a single recipe run put all the language-specific recipes before this recipe.
|
||||
org.openrewrite.java.AddCommentToImport,Add comment to import statement,Add a comment to an import statement in a Java source file.
|
||||
org.openrewrite.java.AddCommentToMethod,Add comment to method declarations,Add a comment to method declarations in a Java source file.
|
||||
org.openrewrite.java.AddCommentToMethodInvocations,Add comment to method invocations,Add a comment to method invocations in a Java source file.
|
||||
org.openrewrite.java.AddLicenseHeader,Add license header,Adds license headers to Java source files when missing. Does not override existing license headers.
|
||||
org.openrewrite.java.AddLiteralMethodArgument,Add a literal method argument,Add a literal `String` or `int` argument to method invocations.
|
||||
org.openrewrite.java.AddMethodParameter,Add method parameter to a method declaration,Adds a new method parameter to an existing method declaration.
|
||||
org.openrewrite.java.AddNullMethodArgument,Add a `null` method argument,Add a `null` argument to method invocations.
|
||||
org.openrewrite.java.AddOrUpdateAnnotationAttribute,Add or update annotation attribute,Some annotations accept arguments. This recipe sets an existing argument to the specified value or adds the argument if it is not already set.
|
||||
org.openrewrite.java.ChangeAnnotationAttributeName,Change annotation attribute name,Some annotations accept arguments. This recipe renames an existing attribute.
|
||||
org.openrewrite.java.ChangeMethodAccessLevel,Change method access level,Change the access level (public protected private package private) of a method.
|
||||
org.openrewrite.java.ChangeMethodInvocationReturnType,Change method invocation return type,Changes the return type of a method invocation.
|
||||
org.openrewrite.java.ChangeMethodName,Change method name,Rename a method.
|
||||
org.openrewrite.java.ChangeMethodTargetToStatic,Change method target to static,Change method invocations to static method calls.
|
||||
org.openrewrite.java.ChangeMethodTargetToVariable,Change method target to variable,Change method invocations to method calls on a variable.
|
||||
org.openrewrite.java.ChangePackage,Rename package name,A recipe that will rename a package name in package statements imports and fully-qualified types.
|
||||
org.openrewrite.java.ChangePackageInStringLiteral,Rename package name in String literals,A recipe that will rename a package name in String literals.
|
||||
org.openrewrite.java.ChangeStaticFieldToMethod,Change static field access to static method access,Migrate accesses to a static field to invocations of a static method.
|
||||
org.openrewrite.java.ChangeType,Change type,Change a given type to another.
|
||||
org.openrewrite.java.ChangeTypeInStringLiteral,Change type in String literals,Change a given type to another when used in a String literal.
|
||||
org.openrewrite.java.DeleteMethodArgument,Delete method argument,Delete an argument from method invocations.
|
||||
org.openrewrite.java.NoStaticImport,Remove static import,Removes static imports and replaces them with qualified references. For example `emptyList()` becomes `Collections.emptyList()`.
|
||||
org.openrewrite.java.RemoveAnnotation,Remove annotation,Remove matching annotations wherever they occur.
|
||||
org.openrewrite.java.RemoveAnnotationAttribute,Remove annotation attribute,Some annotations accept arguments. This recipe removes an existing attribute.
|
||||
org.openrewrite.java.RemoveImplements,Remove interface implementations,Removes `implements` clauses from classes implementing the specified interface. Removes `@Overrides` annotations from methods which no longer override anything.
|
||||
org.openrewrite.java.RemoveMethodInvocations,Remove method invocations,Remove method invocations if syntactically safe.
|
||||
org.openrewrite.java.RemoveUnusedImports,Remove unused imports,Remove imports for types that are not referenced. As a precaution against incorrect changes no imports will be removed from any source where unknown types are referenced. The most common cause of unknown types is the use of annotation processors not supported by OpenRewrite such as lombok.
|
||||
org.openrewrite.java.ReplaceAnnotation,Replace annotation,Replace an Annotation with another one if the annotation pattern matches. Only fixed parameters can be set in the replacement.
|
||||
org.openrewrite.java.ReplaceConstant,Replace constant with literal value,Replace a named constant with a literal value when you wish to remove the old constant. A `String` literal must include escaped quotes.
|
||||
org.openrewrite.java.ReplaceConstantWithAnotherConstant,Replace constant with another constant,Replace a constant with another constant adding/removing import on class if needed.
|
||||
org.openrewrite.java.ReplaceMethodInvocationWithConstant,Replace method invocation with constant,Replace all method invocations matching the method pattern with the specified constant.
|
||||
org.openrewrite.java.ReplaceStringLiteralValue,Replace `String` literal,Replace the value of a complete `String` literal.
|
||||
org.openrewrite.java.ReplaceStringLiteralWithConstant,Replace String literal with constant,Replace String literal with constant adding import on class if needed.
|
||||
org.openrewrite.java.ShortenFullyQualifiedTypeReferences,Add imports for fully qualified references to types,Any fully qualified references to Java types will be replaced with corresponding simple names and import statements provided that it doesn't result in any conflicts with other imports or types declared in the local compilation unit.
|
||||
org.openrewrite.text.CreateTextFile,Create text file,Creates a new plain text file.
|
||||
org.openrewrite.java.CreateEmptyJavaClass,Create Java class,Create a new empty Java class.
|
||||
org.openrewrite.json.CreateJsonFile,Create JSON file,Create a new JSON file.
|
||||
org.openrewrite.properties.CreatePropertiesFile,Create Properties file,Create a new Properties file.
|
||||
org.openrewrite.toml.CreateTomlFile,Create TOML file,Create a new TOML file.
|
||||
org.openrewrite.xml.CreateXmlFile,Create XML file,Create a new XML file.
|
||||
org.openrewrite.yaml.ChangePropertyValue,Change YAML property,Change a YAML property. Expects dot notation for nested YAML mappings similar to how Spring Boot interprets `application.yml` files.
|
||||
org.openrewrite.yaml.CoalesceProperties,Coalesce YAML properties,Simplify nested map hierarchies into their simplest dot separated property form similar to how Spring Boot interprets `application.yml` files.
|
||||
org.openrewrite.yaml.MergeYaml,Merge YAML snippet,Merge a YAML snippet with an existing YAML document.
|
||||
org.openrewrite.yaml.UnfoldProperties,Unfold YAML properties,Transforms dot-separated property keys in YAML files into nested map hierarchies to enhance clarity and readability or for compatibility with tools expecting structured YAML.
|
||||
|
@@ -0,0 +1,51 @@
|
||||
Fully Qualified Recipe Name,Recipe Name,Description
|
||||
org.openrewrite.java.logging.containerized.ContainerizeLog4j2PropertiesConfiguration,Containerize Log4j2 Properties configuration,Transforms Log4j2 Properties configuration to write logs to stdout instead of files suitable for containerized environments.
|
||||
org.openrewrite.java.logging.containerized.ContainerizeLog4j2XmlConfiguration,Containerize Log4j2 XML configuration,Transforms Log4j2 XML configuration to write logs to stdout instead of files suitable for containerized environments.
|
||||
org.openrewrite.java.logging.containerized.ContainerizeLog4j2YamlConfiguration,Containerize Log4j2 YAML configuration,Transforms Log4j2 YAML configuration to write logs to stdout instead of files suitable for containerized environments. (Implementation in progress)
|
||||
io.moderne.kafka.RemoveDeprecatedKafkaProperties,Remove deprecated Kafka property,Removes a specific Kafka property that is no longer supported in Kafka 4.0.
|
||||
org.openrewrite.gradle.AddProperty,Add Gradle property,Add a property to the `gradle.properties` file.
|
||||
org.openrewrite.json.AddKeyValue,Add value to JSON Object,Adds a `value` at the specified `keyPath` with the specified `key` if the key doesn't already exist.
|
||||
org.openrewrite.json.ChangeKey,Change key,Change a JSON mapping entry key while leaving the value intact.
|
||||
org.openrewrite.json.ChangeValue,Change value,Change a JSON mapping entry value leaving the key intact.
|
||||
org.openrewrite.json.DeleteKey,Delete key,Delete a JSON mapping entry key.
|
||||
org.openrewrite.json.format.AutoFormat,Format JSON,Format JSON code using a standard comprehensive set of JSON formatting recipes.
|
||||
org.openrewrite.json.format.Indents,JSON indent,Format tabs and indents in JSON.
|
||||
org.openrewrite.json.format.WrappingAndBraces,JSON new lines,Split members into separate lines in JSON.
|
||||
org.openrewrite.json.search.FindKey,Find JSON object members,Find JSON object members by JsonPath expression.
|
||||
org.openrewrite.json.CreateJsonFile,Create JSON file,Create a new JSON file.
|
||||
org.openrewrite.maven.AddProfile,Add Maven profile,Add a maven profile to a `pom.xml` file.
|
||||
org.openrewrite.maven.ChangePropertyValue,Change Maven project property value,Changes the specified Maven project property value leaving the key intact.
|
||||
org.openrewrite.maven.RemoveProperty,Remove Maven project property,Removes the specified Maven project property from the pom.xml.
|
||||
org.openrewrite.maven.search.FindScm,Find SCM tag,Finds any `<scm>` tag directly inside the `<project>` root of a Maven pom.xml file.
|
||||
org.openrewrite.properties.AddProperty,Add a new property,Adds a new property to a property file. Attempts to place the new property in alphabetical order by the property keys. Whitespace before and after the `=` must be included in the property and value.
|
||||
org.openrewrite.properties.AddPropertyComment,Add comment before property key,Add a new comment before a property key if not already present optionally commenting out the property.
|
||||
org.openrewrite.properties.ChangePropertyKey,Change property key,Change a property key leaving the value intact.
|
||||
org.openrewrite.properties.ChangePropertyValue,Change property value,Change a property value leaving the key intact.
|
||||
org.openrewrite.properties.DeleteProperty,Delete property by key,Deletes key/value pairs from properties files as well as any comments that immediately precede the key/value pair. Comments separated by two or more newlines from the deleted key/value pair are preserved.
|
||||
org.openrewrite.properties.search.FindProperties,Find property,Finds occurrences of a property key.
|
||||
org.openrewrite.properties.CreatePropertiesFile,Create Properties file,Create a new Properties file.
|
||||
org.openrewrite.xml.AddCommentToXmlTag,Add a comment to an XML tag,Adds a comment as the first element in an XML tag.
|
||||
org.openrewrite.xml.AddOrUpdateChildTag,Add or update child tag,Adds or updates a child element below the parent(s) matching the provided `parentXPath` expression. If a child with the same name already exists it will be replaced by default. Otherwise a new child will be added. This ensures idempotent behaviour.
|
||||
org.openrewrite.xml.AddTagAttribute,Add new XML attribute for an Element,Add new XML attribute with value on a specified element.
|
||||
org.openrewrite.xml.ChangeNamespaceValue,Change XML attribute of a specific resource version,Alters XML Attribute value within specified element of a specific resource versions.
|
||||
org.openrewrite.xml.ChangeTagAttribute,Change XML attribute,Alters XML attribute value on a specified element.
|
||||
org.openrewrite.xml.ChangeTagName,Change XML tag name,Alters the name of XML tags matching the provided expression.
|
||||
org.openrewrite.xml.ChangeTagValue,Change XML tag value,Alters the value of XML tags matching the provided expression. When regex is enabled the replacement happens only for text nodes provided the pattern matches.
|
||||
org.openrewrite.xml.RemoveEmptyXmlTags,Remove empty XML Tag,Removes XML tags that do not have attributes or children including self closing tags.
|
||||
org.openrewrite.xml.RemoveTrailingWhitespace,Remove trailing whitespace,Remove any extra trailing whitespace from the end of each line.
|
||||
org.openrewrite.xml.RemoveXmlTag,Remove XML tag,Removes XML tags matching the provided expression.
|
||||
org.openrewrite.xml.XsltTransformation,XSLT transformation,Apply the specified XSLT transformation on matching files. Note that there are no format matching guarantees when running this recipe.
|
||||
org.openrewrite.xml.format.AutoFormat,Format XML,Indents XML using the most common indentation size and tabs or space choice in use in the file.
|
||||
org.openrewrite.xml.format.LineBreaks,Blank lines,Add line breaks at appropriate places between XML syntax elements.
|
||||
org.openrewrite.xml.format.NormalizeFormat,Normalize format,Move whitespace to the outermost LST element possible.
|
||||
org.openrewrite.xml.format.NormalizeLineBreaks,Normalize line breaks,Consistently use either Windows style (CRLF) or Linux style (LF) line breaks. If no `GeneralFormatStyle` is specified this will use whichever style of line endings are more common.
|
||||
org.openrewrite.xml.format.NormalizeTabsOrSpaces,Normalize to tabs or spaces,Consistently use either tabs or spaces in indentation.
|
||||
org.openrewrite.xml.format.TabsAndIndents,Tabs and indents,Format tabs and indents in XML code.
|
||||
org.openrewrite.xml.search.DoesNotUseNamespaceUri,Find files without Namespace URI,Find XML root elements that do not have a specific Namespace URI optionally restricting the search by an XPath expression.
|
||||
org.openrewrite.xml.search.FindNamespacePrefix,Find XML namespace prefixes,Find XML namespace prefixes optionally restricting the search by a XPath expression.
|
||||
org.openrewrite.xml.search.FindTags,Find XML tags,Find XML tags by XPath expression.
|
||||
org.openrewrite.xml.search.HasNamespaceUri,Find XML namespace URIs,Find XML namespace URIs optionally restricting the search by a XPath expression.
|
||||
org.openrewrite.xml.security.AddOwaspDateBoundSuppressions,Add date bounds to OWASP suppressions,Adds an expiration date to all OWASP suppressions in order to ensure that they are periodically reviewed. For use with the OWASP `dependency-check` tool. More details: https://jeremylong.github.io/DependencyCheck/general/suppression.html.
|
||||
org.openrewrite.xml.security.IsOwaspSuppressionsFile,Find OWASP vulnerability suppression XML files,These files are used to suppress false positives in OWASP [Dependency Check](https://jeremylong.github.io/DependencyCheck).
|
||||
org.openrewrite.xml.security.RemoveOwaspSuppressions,Remove out-of-date OWASP suppressions,Remove all OWASP suppressions with a suppression end date in the past as these are no longer valid. For use with the OWASP `dependency-check` tool. More details on OWASP suppression files can be found [here](https://jeremylong.github.io/DependencyCheck/general/suppression.html).
|
||||
org.openrewrite.xml.security.UpdateOwaspSuppressionDate,Update OWASP suppression date bounds,Updates the expiration date for OWASP suppressions having a matching cve tag. For use with the OWASP `dependency-check` tool. More details: https://jeremylong.github.io/DependencyCheck/general/suppression.html.
|
||||
|
151
skills/writing-openrewrite-recipes/scripts/categorize_recipes.py
Normal file
151
skills/writing-openrewrite-recipes/scripts/categorize_recipes.py
Normal file
@@ -0,0 +1,151 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Script to categorize recipes from recipes-all.csv into separate category files.
|
||||
"""
|
||||
|
||||
import csv
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Define categories and their matching patterns (keywords in id, name, or description)
|
||||
CATEGORIES = {
|
||||
'java-basic': {
|
||||
'keywords': [
|
||||
'ChangeType', 'ChangeMethodName', 'ChangePackage', 'AddAnnotation', 'RemoveAnnotation',
|
||||
'ChangeMethodAccessLevel', 'AddImport', 'RemoveImport', 'AddMethodParameter',
|
||||
'DeleteMethodArgument', 'ReplaceConstant', 'ReplaceStringLiteral',
|
||||
'org.openrewrite.java.ChangeType', 'org.openrewrite.java.ChangeMethod',
|
||||
'org.openrewrite.java.ChangePackage', 'org.openrewrite.java.AddComment',
|
||||
'org.openrewrite.java.ReplaceAnnotation', 'org.openrewrite.java.ShortenFullyQualifiedTypeReferences'
|
||||
],
|
||||
'description': 'Basic Java refactoring operations for types, methods, packages, and annotations'
|
||||
},
|
||||
'spring-boot': {
|
||||
'keywords': [
|
||||
'spring.boot', 'SpringBoot', 'spring-boot', 'UpgradeSpringBoot'
|
||||
],
|
||||
'description': 'Spring Boot migrations, upgrades, and best practices'
|
||||
},
|
||||
'security': {
|
||||
'keywords': [
|
||||
'security', 'vulnerability', 'injection', 'XSS', 'XXE', 'SQL injection',
|
||||
'command injection', 'path traversal', 'LDAP injection', 'unencrypted',
|
||||
'FindSqlInjection', 'FindXss', 'FindCommandInjection', 'OWASP'
|
||||
],
|
||||
'description': 'Security vulnerability detection and fixes'
|
||||
},
|
||||
'testing': {
|
||||
'keywords': [
|
||||
'junit', 'JUnit', 'test', 'Test', 'mockito', 'Mockito', 'assertj', 'AssertJ',
|
||||
'@Test', 'TestNG'
|
||||
],
|
||||
'description': 'Testing framework migrations and best practices'
|
||||
},
|
||||
'dependencies': {
|
||||
'keywords': [
|
||||
'maven', 'Maven', 'gradle', 'Gradle', 'dependency', 'Dependency',
|
||||
'UpgradeDependency', 'ChangeDependency', 'AddDependency', 'RemoveDependency',
|
||||
'pom.xml', 'build.gradle'
|
||||
],
|
||||
'description': 'Maven and Gradle dependency management'
|
||||
},
|
||||
'logging': {
|
||||
'keywords': [
|
||||
'log4j', 'Log4j', 'logback', 'Logback', 'slf4j', 'SLF4J', 'logging',
|
||||
'Logging', 'logger', 'Logger'
|
||||
],
|
||||
'description': 'Logging framework configuration and migrations'
|
||||
},
|
||||
'file-operations': {
|
||||
'keywords': [
|
||||
'CreateFile', 'DeleteFile', 'MoveFile', 'RenameFile', 'FindAndReplace',
|
||||
'ChangeText', 'AppendToTextFile', 'CreateTextFile', 'org.openrewrite.text',
|
||||
'org.openrewrite.DeleteSourceFiles', 'org.openrewrite.MoveFile'
|
||||
],
|
||||
'description': 'File and text manipulation operations'
|
||||
},
|
||||
'framework-migrations': {
|
||||
'keywords': [
|
||||
'MigrateTo', 'UpgradeTo', 'Kafka', 'Hibernate', 'Elasticsearch', 'Quarkus',
|
||||
'Jakarta', 'javax', 'migration'
|
||||
],
|
||||
'description': 'Major framework and library migrations'
|
||||
},
|
||||
'xml-yaml-json': {
|
||||
'keywords': [
|
||||
'xml', 'XML', 'yaml', 'YAML', 'json', 'JSON', 'properties', 'Properties',
|
||||
'ChangePropertyValue', 'MergeYaml', 'CreateXmlFile'
|
||||
],
|
||||
'description': 'Configuration file operations for XML, YAML, JSON, and properties files'
|
||||
},
|
||||
'static-analysis': {
|
||||
'keywords': [
|
||||
'Find', 'Search', 'Analysis', 'complexity', 'unused', 'unreachable',
|
||||
'dead code', 'null pointer', 'FindNullPointer', 'FindUnused'
|
||||
],
|
||||
'description': 'Code analysis and search recipes for finding patterns and issues'
|
||||
}
|
||||
}
|
||||
|
||||
def matches_category(recipe_id, recipe_name, recipe_desc, keywords):
|
||||
"""Check if a recipe matches any of the keywords for a category."""
|
||||
text_to_search = f"{recipe_id} {recipe_name} {recipe_desc}".lower()
|
||||
return any(keyword.lower() in text_to_search for keyword in keywords)
|
||||
|
||||
def main():
|
||||
script_dir = Path(__file__).parent
|
||||
references_dir = script_dir.parent / 'references'
|
||||
input_file = references_dir / 'recipes-all.csv'
|
||||
|
||||
# Dictionary to store recipes for each category
|
||||
categorized_recipes = {cat: [] for cat in CATEGORIES.keys()}
|
||||
|
||||
print(f"Reading recipes from {input_file}...")
|
||||
|
||||
# Read and categorize recipes
|
||||
with open(input_file, 'r', encoding='utf-8') as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
recipe_id = row['id']
|
||||
recipe_name = row['name']
|
||||
recipe_desc = row['description']
|
||||
|
||||
# Skip C#, DevCenter, COBOL, and AWS SDK migration recipes globally
|
||||
if 'csharp' in recipe_id.lower() or '.csharp.' in recipe_id.lower():
|
||||
continue
|
||||
if 'io.moderne.devcenter' in recipe_id.lower():
|
||||
continue
|
||||
if 'cobol' in recipe_id.lower():
|
||||
continue
|
||||
if 'software.amazon.awssdk' in recipe_id.lower():
|
||||
continue
|
||||
|
||||
# Check each category
|
||||
for category, config in CATEGORIES.items():
|
||||
if matches_category(recipe_id, recipe_name, recipe_desc, config['keywords']):
|
||||
categorized_recipes[category].append({
|
||||
'id': recipe_id,
|
||||
'name': recipe_name,
|
||||
'description': recipe_desc
|
||||
})
|
||||
|
||||
# Write categorized CSV files
|
||||
for category, recipes in categorized_recipes.items():
|
||||
if recipes:
|
||||
output_file = references_dir / f'recipes-{category}.csv'
|
||||
print(f"Writing {len(recipes)} recipes to {output_file.name}...")
|
||||
|
||||
with open(output_file, 'w', encoding='utf-8', newline='') as f:
|
||||
writer = csv.writer(f)
|
||||
writer.writerow(['Fully Qualified Recipe Name', 'Recipe Name', 'Description'])
|
||||
|
||||
for recipe in recipes:
|
||||
writer.writerow([recipe['id'], recipe['name'], recipe['description']])
|
||||
|
||||
# Print summary
|
||||
print("\n=== Summary ===")
|
||||
for category, recipes in sorted(categorized_recipes.items(), key=lambda x: len(x[1]), reverse=True):
|
||||
print(f"{category:25} {len(recipes):4} recipes - {CATEGORIES[category]['description']}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,413 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Script to create curated "common" versions of large recipe categories.
|
||||
Selects the most practical and commonly used recipes (30-75 each).
|
||||
"""
|
||||
|
||||
import csv
|
||||
from pathlib import Path
|
||||
|
||||
def read_recipes(file_path):
|
||||
"""Read recipes from a CSV file."""
|
||||
recipes = []
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
recipes.append(row)
|
||||
return recipes
|
||||
|
||||
def write_recipes(file_path, recipes):
|
||||
"""Write recipes to a CSV file."""
|
||||
with open(file_path, 'w', encoding='utf-8', newline='') as f:
|
||||
writer = csv.writer(f)
|
||||
writer.writerow(['Fully Qualified Recipe Name', 'Recipe Name', 'Description'])
|
||||
for recipe in recipes:
|
||||
writer.writerow([
|
||||
recipe['Fully Qualified Recipe Name'],
|
||||
recipe['Recipe Name'],
|
||||
recipe['Description']
|
||||
])
|
||||
|
||||
def curate_testing(recipes):
|
||||
"""Select most useful testing recipes - prioritize broad recipes over specific variations."""
|
||||
curated = []
|
||||
seen = set()
|
||||
|
||||
for recipe in recipes:
|
||||
recipe_id = recipe['Fully Qualified Recipe Name']
|
||||
recipe_name = recipe['Recipe Name']
|
||||
|
||||
# Skip overly specific sub-recipes (inner classes with $)
|
||||
if '$' in recipe_id:
|
||||
continue
|
||||
|
||||
# Exclude overly specific assertion patterns for individual numeric types
|
||||
if any(pattern in recipe_name for pattern in [
|
||||
'Byte Assert', 'Integer Assert', 'Long Assert', 'Float Assert',
|
||||
'Double Assert', 'Short Assert', 'BigInteger Assert', 'BigDecimal Assert'
|
||||
]):
|
||||
continue
|
||||
|
||||
# Prioritize broad testing migrations and frameworks
|
||||
is_useful = (
|
||||
# JUnit migrations
|
||||
'junit' in recipe_id.lower() and any(keyword in recipe_name.lower() for keyword in [
|
||||
'junit 5', 'junit5', 'migration', 'upgrade', 'best practices'
|
||||
]) or
|
||||
# Mockito
|
||||
'mockito' in recipe_id.lower() or
|
||||
# AssertJ (but only high-level)
|
||||
('assertj' in recipe_id.lower() and 'adopt' in recipe_name.lower() and
|
||||
not any(num in recipe_name for num in ['Byte', 'Integer', 'Long', 'Float', 'Double'])) or
|
||||
# TestNG
|
||||
'testng' in recipe_id.lower() or
|
||||
# General testing best practices
|
||||
any(keyword in recipe_name.lower() for keyword in [
|
||||
'test', 'assert', 'mock', 'verify', 'cleanup'
|
||||
]) and 'org.openrewrite.java.testing' in recipe_id
|
||||
)
|
||||
|
||||
if is_useful and recipe_name not in seen:
|
||||
curated.append(recipe)
|
||||
seen.add(recipe_name)
|
||||
|
||||
if len(curated) >= 60:
|
||||
break
|
||||
|
||||
return curated[:60]
|
||||
|
||||
def curate_framework_migrations(recipes):
|
||||
"""Select most useful framework migration recipes - prioritize framework diversity over multiple versions."""
|
||||
from collections import defaultdict
|
||||
|
||||
# Group recipes by framework
|
||||
framework_recipes = defaultdict(list)
|
||||
|
||||
for recipe in recipes:
|
||||
recipe_id = recipe['Fully Qualified Recipe Name']
|
||||
recipe_name = recipe['Recipe Name']
|
||||
|
||||
# Identify the framework
|
||||
framework = None
|
||||
if 'kafka' in recipe_id.lower() or 'kafka' in recipe_name.lower():
|
||||
framework = 'kafka'
|
||||
elif 'hibernate' in recipe_id.lower() or 'hibernate' in recipe_name.lower():
|
||||
framework = 'hibernate'
|
||||
elif 'quarkus' in recipe_id.lower() or 'quarkus' in recipe_name.lower():
|
||||
framework = 'quarkus'
|
||||
elif 'elasticsearch' in recipe_id.lower() or 'elasticsearch' in recipe_name.lower():
|
||||
framework = 'elasticsearch'
|
||||
elif 'spring.boot' in recipe_id.lower() or ('spring boot' in recipe_name.lower() and 'upgrade' in recipe_name.lower()):
|
||||
framework = 'spring-boot'
|
||||
elif 'spring.security' in recipe_id.lower() or 'spring security' in recipe_name.lower():
|
||||
framework = 'spring-security'
|
||||
elif 'spring.cloud' in recipe_id.lower() or 'spring cloud' in recipe_name.lower():
|
||||
framework = 'spring-cloud'
|
||||
elif 'spring.data' in recipe_id.lower() or 'spring data' in recipe_name.lower():
|
||||
framework = 'spring-data'
|
||||
elif 'jakarta' in recipe_id.lower() or 'javax' in recipe_id.lower():
|
||||
framework = 'jakarta-ee'
|
||||
elif 'micronaut' in recipe_id.lower() or 'micronaut' in recipe_name.lower():
|
||||
framework = 'micronaut'
|
||||
elif 'camel' in recipe_id.lower():
|
||||
framework = 'camel'
|
||||
elif 'vertx' in recipe_id.lower() or 'vert.x' in recipe_name.lower():
|
||||
framework = 'vertx'
|
||||
elif 'dropwizard' in recipe_id.lower():
|
||||
framework = 'dropwizard'
|
||||
elif 'guava' in recipe_id.lower():
|
||||
framework = 'guava'
|
||||
elif 'junit' in recipe_id.lower() or 'junit' in recipe_name.lower():
|
||||
framework = 'junit'
|
||||
|
||||
# Only include migration/upgrade recipes
|
||||
if framework and ('MigrateTo' in recipe_id or 'Upgrade' in recipe_id or
|
||||
'Migrate' in recipe_name or 'Upgrade' in recipe_name):
|
||||
framework_recipes[framework].append(recipe)
|
||||
|
||||
# Select top 1-2 versions per framework, prioritizing latest versions
|
||||
curated = []
|
||||
seen_names = set()
|
||||
|
||||
# Sort frameworks by recipe count to ensure we get diverse coverage
|
||||
for framework in sorted(framework_recipes.keys()):
|
||||
framework_list = framework_recipes[framework]
|
||||
|
||||
# For each framework, prefer recipes with higher version numbers (assumed to be more recent)
|
||||
# and avoid duplicate recipe names
|
||||
added_for_framework = 0
|
||||
max_per_framework = 2 # Keep at most 2 versions per framework
|
||||
|
||||
for recipe in framework_list:
|
||||
recipe_name = recipe['Recipe Name']
|
||||
if recipe_name not in seen_names and added_for_framework < max_per_framework:
|
||||
curated.append(recipe)
|
||||
seen_names.add(recipe_name)
|
||||
added_for_framework += 1
|
||||
|
||||
return curated[:50]
|
||||
|
||||
def curate_dependencies(recipes):
|
||||
"""Select most useful dependency management recipes - prefer Maven+Gradle over build-tool-specific."""
|
||||
curated = []
|
||||
seen = set()
|
||||
|
||||
# First pass: Prioritize org.openrewrite.java.dependencies (works for both Maven and Gradle)
|
||||
for recipe in recipes:
|
||||
recipe_id = recipe['Fully Qualified Recipe Name']
|
||||
recipe_name = recipe['Recipe Name']
|
||||
|
||||
# Exclude C# and DevCenter recipes
|
||||
if 'csharp' in recipe_id.lower() or 'devcenter' in recipe_id.lower():
|
||||
continue
|
||||
|
||||
# Prioritize org.openrewrite.java.dependencies (works for both Maven and Gradle)
|
||||
if 'org.openrewrite.java.dependencies' in recipe_id and recipe_name not in seen:
|
||||
curated.append(recipe)
|
||||
seen.add(recipe_name)
|
||||
|
||||
# Second pass: Add common Maven operations
|
||||
for recipe in recipes:
|
||||
recipe_id = recipe['Fully Qualified Recipe Name']
|
||||
recipe_name = recipe['Recipe Name']
|
||||
|
||||
if 'csharp' in recipe_id.lower() or 'devcenter' in recipe_id.lower():
|
||||
continue
|
||||
|
||||
# Include Maven recipes for common operations
|
||||
if 'org.openrewrite.maven' in recipe_id and recipe_name not in seen:
|
||||
is_common_maven = any(keyword in recipe_name for keyword in [
|
||||
'Change dependency', 'Add dependency', 'Remove dependency',
|
||||
'Upgrade dependency', 'parent', 'BOM', 'managed', 'plugin'
|
||||
])
|
||||
|
||||
if is_common_maven:
|
||||
curated.append(recipe)
|
||||
seen.add(recipe_name)
|
||||
|
||||
if len(curated) >= 35:
|
||||
break
|
||||
|
||||
# Third pass: Add common Gradle operations (but fewer since Maven is covered)
|
||||
for recipe in recipes:
|
||||
recipe_id = recipe['Fully Qualified Recipe Name']
|
||||
recipe_name = recipe['Recipe Name']
|
||||
|
||||
if 'csharp' in recipe_id.lower() or 'devcenter' in recipe_id.lower():
|
||||
continue
|
||||
|
||||
# Include Gradle recipes for operations not covered by Maven
|
||||
if 'org.openrewrite.gradle' in recipe_id and recipe_name not in seen:
|
||||
is_essential_gradle = any(keyword in recipe_name for keyword in [
|
||||
'Change dependency', 'Add dependency', 'Remove dependency',
|
||||
'Upgrade version', 'wrapper', 'plugin'
|
||||
])
|
||||
|
||||
if is_essential_gradle:
|
||||
curated.append(recipe)
|
||||
seen.add(recipe_name)
|
||||
|
||||
if len(curated) >= 50:
|
||||
break
|
||||
|
||||
return curated[:50]
|
||||
|
||||
def curate_xml_yaml_json(recipes):
|
||||
"""Select most useful configuration file recipes."""
|
||||
curated = []
|
||||
seen = set()
|
||||
|
||||
for recipe in recipes:
|
||||
recipe_id = recipe['Fully Qualified Recipe Name']
|
||||
recipe_name = recipe['Recipe Name']
|
||||
|
||||
# Include recipes from core packages for YAML, XML, JSON, Properties, TOML
|
||||
is_config_operation = (
|
||||
'org.openrewrite.yaml' in recipe_id or
|
||||
'org.openrewrite.xml' in recipe_id or
|
||||
'org.openrewrite.json' in recipe_id or
|
||||
'org.openrewrite.properties' in recipe_id or
|
||||
'org.openrewrite.toml' in recipe_id
|
||||
)
|
||||
|
||||
# Also include common operations by name
|
||||
has_config_keywords = any(keyword in recipe_name for keyword in [
|
||||
'YAML', 'XML', 'JSON', 'Properties', 'TOML', 'property', 'tag',
|
||||
'attribute', 'value', 'file'
|
||||
])
|
||||
|
||||
if (is_config_operation or has_config_keywords) and recipe_name not in seen:
|
||||
curated.append(recipe)
|
||||
seen.add(recipe_name)
|
||||
|
||||
if len(curated) >= 50:
|
||||
break
|
||||
|
||||
return curated[:50]
|
||||
|
||||
def curate_static_analysis(recipes):
|
||||
"""Select most useful static analysis recipes."""
|
||||
curated = []
|
||||
seen = set()
|
||||
|
||||
for recipe in recipes:
|
||||
recipe_id = recipe['Fully Qualified Recipe Name']
|
||||
recipe_name = recipe['Recipe Name']
|
||||
|
||||
# Include Find* and Search* recipes from core packages
|
||||
is_search_recipe = (
|
||||
recipe_name.startswith('Find') or
|
||||
recipe_name.startswith('Search') or
|
||||
'org.openrewrite.search' in recipe_id or
|
||||
'org.openrewrite.analysis' in recipe_id
|
||||
)
|
||||
|
||||
# Prioritize security-related searches
|
||||
is_security = any(keyword in recipe_name.lower() for keyword in [
|
||||
'security', 'vulnerability', 'injection', 'xss', 'xxe'
|
||||
])
|
||||
|
||||
if (is_search_recipe or is_security) and recipe_name not in seen:
|
||||
curated.append(recipe)
|
||||
seen.add(recipe_name)
|
||||
|
||||
if len(curated) >= 50:
|
||||
break
|
||||
|
||||
return curated[:50]
|
||||
|
||||
def curate_spring_boot(recipes):
|
||||
"""Select most useful Spring Boot recipes."""
|
||||
curated = []
|
||||
seen = set()
|
||||
|
||||
for recipe in recipes:
|
||||
recipe_id = recipe['Fully Qualified Recipe Name']
|
||||
recipe_name = recipe['Recipe Name']
|
||||
|
||||
# Prioritize major upgrade recipes and common operations
|
||||
is_major_upgrade = any(version in recipe_name for version in [
|
||||
'3.5', '3.4', '3.3', '3.2', '3.1', '3.0', '2.7'
|
||||
])
|
||||
|
||||
is_common_operation = any(keyword in recipe_name for keyword in [
|
||||
'Upgrade', 'Migrate', 'Best Practices', 'Properties',
|
||||
'Actuator', 'Configuration', 'Deprecat'
|
||||
])
|
||||
|
||||
# Avoid overly specific internal changes
|
||||
is_specific = any(keyword in recipe_name.lower() for keyword in [
|
||||
'replace', 'remove', 'use', 'comment', 'add @valid'
|
||||
])
|
||||
|
||||
if (is_major_upgrade or is_common_operation) and not is_specific and recipe_name not in seen:
|
||||
curated.append(recipe)
|
||||
seen.add(recipe_name)
|
||||
|
||||
if len(curated) >= 60:
|
||||
break
|
||||
|
||||
return curated[:60]
|
||||
|
||||
def curate_security(recipes):
|
||||
"""Select most useful security recipes."""
|
||||
curated = []
|
||||
seen = set()
|
||||
|
||||
for recipe in recipes:
|
||||
recipe_id = recipe['Fully Qualified Recipe Name']
|
||||
recipe_name = recipe['Recipe Name']
|
||||
|
||||
# Prioritize high-impact security issues
|
||||
is_high_impact = any(keyword in recipe_name.lower() for keyword in [
|
||||
'sql injection', 'xss', 'xxe', 'command injection',
|
||||
'path traversal', 'ldap injection', 'vulnerability',
|
||||
'unencrypted', 'insecure', 'csrf', 'authentication'
|
||||
])
|
||||
|
||||
# Include general security finding recipes
|
||||
is_finding_recipe = recipe_name.startswith('Find') and any(keyword in recipe_name.lower() for keyword in [
|
||||
'security', 'vulnerability', 'injection', 'exposure'
|
||||
])
|
||||
|
||||
# Include OWASP related
|
||||
is_owasp = 'owasp' in recipe_id.lower() or 'owasp' in recipe_name.lower()
|
||||
|
||||
if (is_high_impact or is_finding_recipe or is_owasp) and recipe_name not in seen:
|
||||
curated.append(recipe)
|
||||
seen.add(recipe_name)
|
||||
|
||||
if len(curated) >= 60:
|
||||
break
|
||||
|
||||
return curated[:60]
|
||||
|
||||
def curate_logging(recipes):
|
||||
"""Select most useful logging recipes."""
|
||||
curated = []
|
||||
seen = set()
|
||||
|
||||
for recipe in recipes:
|
||||
recipe_id = recipe['Fully Qualified Recipe Name']
|
||||
recipe_name = recipe['Recipe Name']
|
||||
|
||||
# Prioritize common logging operations
|
||||
is_common_logging = any(keyword in recipe_name for keyword in [
|
||||
'Parameterize', 'SLF4J', 'Log4j', 'Logback', 'System.out',
|
||||
'System.err', 'printStackTrace', 'Containerize', 'Migration',
|
||||
'logger', 'Logger'
|
||||
])
|
||||
|
||||
# Exclude overly specific internal operations
|
||||
is_specific = 'internal' in recipe_name.lower()
|
||||
|
||||
if is_common_logging and not is_specific and recipe_name not in seen:
|
||||
curated.append(recipe)
|
||||
seen.add(recipe_name)
|
||||
|
||||
if len(curated) >= 50:
|
||||
break
|
||||
|
||||
return curated[:50]
|
||||
|
||||
def main():
|
||||
script_dir = Path(__file__).parent
|
||||
references_dir = script_dir.parent / 'references'
|
||||
|
||||
# Categories to curate (those with >150 recipes or too large to be useful)
|
||||
categories = {
|
||||
'testing': curate_testing,
|
||||
'framework-migrations': curate_framework_migrations,
|
||||
'dependencies': curate_dependencies,
|
||||
'xml-yaml-json': curate_xml_yaml_json,
|
||||
'static-analysis': curate_static_analysis,
|
||||
'spring-boot': curate_spring_boot,
|
||||
'security': curate_security,
|
||||
'logging': curate_logging,
|
||||
}
|
||||
|
||||
print("Creating curated 'common' versions of large categories...\n")
|
||||
|
||||
for category, curate_func in categories.items():
|
||||
input_file = references_dir / f'recipes-{category}.csv'
|
||||
output_file = references_dir / f'recipes-{category}-common.csv'
|
||||
|
||||
if not input_file.exists():
|
||||
print(f"Warning: {input_file.name} not found, skipping...")
|
||||
continue
|
||||
|
||||
# Read all recipes
|
||||
all_recipes = read_recipes(input_file)
|
||||
|
||||
# Curate selection
|
||||
curated_recipes = curate_func(all_recipes)
|
||||
|
||||
# Write curated file
|
||||
write_recipes(output_file, curated_recipes)
|
||||
|
||||
print(f"{category:25} {len(curated_recipes):3} curated from {len(all_recipes):4} total -> {output_file.name}")
|
||||
|
||||
print("\nCurated files created successfully!")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
136
skills/writing-openrewrite-recipes/scripts/upload-skill.sh
Executable file
136
skills/writing-openrewrite-recipes/scripts/upload-skill.sh
Executable file
@@ -0,0 +1,136 @@
|
||||
#!/bin/bash
|
||||
|
||||
# OpenRewrite Recipe Writing Skill - Upload Script
|
||||
# This script creates or updates the skill in Claude's Skills API
|
||||
#
|
||||
# Usage:
|
||||
# Option 1: Use anthropic.key file (recommended)
|
||||
# echo "your-api-key" > anthropic.key
|
||||
# ./upload-skill.sh
|
||||
#
|
||||
# Option 2: Export environment variable
|
||||
# export ANTHROPIC_API_KEY="your-api-key-here"
|
||||
# ./upload-skill.sh
|
||||
|
||||
set -e # Exit on error
|
||||
|
||||
# Change to script directory
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# Try to load API key from anthropic.key file if it exists and ANTHROPIC_API_KEY is not set
|
||||
if [ -z "$ANTHROPIC_API_KEY" ] && [ -f "anthropic.key" ]; then
|
||||
echo "Loading API key from anthropic.key file..."
|
||||
ANTHROPIC_API_KEY=$(cat anthropic.key | tr -d '[:space:]')
|
||||
fi
|
||||
|
||||
# Check if API key is set
|
||||
if [ -z "$ANTHROPIC_API_KEY" ]; then
|
||||
echo "Error: ANTHROPIC_API_KEY not found"
|
||||
echo ""
|
||||
echo "Usage (option 1 - recommended):"
|
||||
echo " echo 'your-api-key' > anthropic.key"
|
||||
echo " ./upload-skill.sh"
|
||||
echo ""
|
||||
echo "Usage (option 2):"
|
||||
echo " export ANTHROPIC_API_KEY='your-api-key-here'"
|
||||
echo " ./upload-skill.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if skill ID file exists
|
||||
SKILL_ID_FILE="skill-id.txt"
|
||||
if [ -f "$SKILL_ID_FILE" ]; then
|
||||
SKILL_ID=$(cat "$SKILL_ID_FILE" | tr -d '[:space:]')
|
||||
ACTION="update"
|
||||
HTTP_METHOD="PATCH"
|
||||
echo "Found existing skill ID: $SKILL_ID"
|
||||
echo "Updating OpenRewrite Recipe Writing skill..."
|
||||
else
|
||||
ACTION="create"
|
||||
HTTP_METHOD="POST"
|
||||
echo "No existing skill ID found."
|
||||
echo "Creating new OpenRewrite Recipe Writing skill..."
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# Skill directory name (must match 'name' field in SKILL.md)
|
||||
SKILL_DIR="openrewrite-recipe-writer"
|
||||
|
||||
# Build curl command based on action
|
||||
if [ "$ACTION" = "create" ]; then
|
||||
# Create new skill
|
||||
response=$(curl -s -w "\n%{http_code}" https://api.anthropic.com/v1/skills \
|
||||
-X POST \
|
||||
-H "x-api-key: $ANTHROPIC_API_KEY" \
|
||||
-H "anthropic-version: 2023-06-01" \
|
||||
-H "anthropic-beta: skills-2025-10-02" \
|
||||
-F "display_title=OpenRewrite Recipe Writing" \
|
||||
-F "files[]=@SKILL.md;filename=$SKILL_DIR/SKILL.md" \
|
||||
-F "files[]=@template-imperative-recipe.java;filename=$SKILL_DIR/template-imperative-recipe.java" \
|
||||
-F "files[]=@template-declarative-recipe.yml;filename=$SKILL_DIR/template-declarative-recipe.yml" \
|
||||
-F "files[]=@template-recipe-test.java;filename=$SKILL_DIR/template-recipe-test.java" \
|
||||
-F "files[]=@example-say-hello-recipe.java;filename=$SKILL_DIR/example-say-hello-recipe.java" \
|
||||
-F "files[]=@example-scanning-recipe.java;filename=$SKILL_DIR/example-scanning-recipe.java" \
|
||||
-F "files[]=@example-declarative-migration.yml;filename=$SKILL_DIR/example-declarative-migration.yml" \
|
||||
-F "files[]=@checklist-recipe-development.md;filename=$SKILL_DIR/checklist-recipe-development.md")
|
||||
else
|
||||
# Update existing skill
|
||||
response=$(curl -s -w "\n%{http_code}" https://api.anthropic.com/v1/skills/$SKILL_ID \
|
||||
-X PATCH \
|
||||
-H "x-api-key: $ANTHROPIC_API_KEY" \
|
||||
-H "anthropic-version: 2023-06-01" \
|
||||
-H "anthropic-beta: skills-2025-10-02" \
|
||||
-F "files[]=@SKILL.md;filename=$SKILL_DIR/SKILL.md" \
|
||||
-F "files[]=@template-imperative-recipe.java;filename=$SKILL_DIR/template-imperative-recipe.java" \
|
||||
-F "files[]=@template-declarative-recipe.yml;filename=$SKILL_DIR/template-declarative-recipe.yml" \
|
||||
-F "files[]=@template-recipe-test.java;filename=$SKILL_DIR/template-recipe-test.java" \
|
||||
-F "files[]=@example-say-hello-recipe.java;filename=$SKILL_DIR/example-say-hello-recipe.java" \
|
||||
-F "files[]=@example-scanning-recipe.java;filename=$SKILL_DIR/example-scanning-recipe.java" \
|
||||
-F "files[]=@example-declarative-migration.yml;filename=$SKILL_DIR/example-declarative-migration.yml" \
|
||||
-F "files[]=@checklist-recipe-development.md;filename=$SKILL_DIR/checklist-recipe-development.md")
|
||||
fi
|
||||
|
||||
# Extract HTTP status code (last line)
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
|
||||
# Extract response body (everything except last line)
|
||||
body=$(echo "$response" | sed '$d')
|
||||
|
||||
# Check status code
|
||||
if [ "$http_code" -eq 200 ]; then
|
||||
if [ "$ACTION" = "create" ]; then
|
||||
echo "✓ Success! Skill created successfully."
|
||||
echo ""
|
||||
echo "Response:"
|
||||
echo "$body" | jq '.' 2>/dev/null || echo "$body"
|
||||
echo ""
|
||||
|
||||
# Extract and save skill ID
|
||||
new_skill_id=$(echo "$body" | jq -r '.id' 2>/dev/null)
|
||||
if [ -n "$new_skill_id" ] && [ "$new_skill_id" != "null" ]; then
|
||||
echo "$new_skill_id" > "$SKILL_ID_FILE"
|
||||
echo "Skill ID saved to $SKILL_ID_FILE for future updates."
|
||||
echo ""
|
||||
echo "Your skill is now available! Use it with:"
|
||||
echo " - Claude API (automatically activates for OpenRewrite recipe questions)"
|
||||
echo " - Claude.ai web interface"
|
||||
else
|
||||
echo "Warning: Could not extract skill ID from response."
|
||||
echo "You may need to save it manually from the response above."
|
||||
fi
|
||||
else
|
||||
echo "✓ Success! Skill updated successfully."
|
||||
echo ""
|
||||
echo "Response:"
|
||||
echo "$body" | jq '.' 2>/dev/null || echo "$body"
|
||||
echo ""
|
||||
echo "The skill has been updated to a new version."
|
||||
fi
|
||||
else
|
||||
echo "✗ Error: $ACTION failed with status code $http_code"
|
||||
echo ""
|
||||
echo "Response:"
|
||||
echo "$body"
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user