Agent Skill
2/7/2026

openrewrite

This skill should be used when implementing or modifying OpenRewrite recipes in the Liftwizard project, when the user asks to "create a recipe", "implement a Refaster template", "convert to Refaster", "add an OpenRewrite transformation", or discusses recipe implementation patterns. Provides guidance on Refaster templates, traditional recipe implementation, type safety, and common patterns.

L
liftwizard
14GitHub Stars
1Views
npx skills add liftwizard/liftwizard

SKILL.md

Nameopenrewrite
DescriptionThis skill should be used when implementing or modifying OpenRewrite recipes in the Liftwizard project, when the user asks to "create a recipe", "implement a Refaster template", "convert to Refaster", "add an OpenRewrite transformation", or discusses recipe implementation patterns. Provides guidance on Refaster templates, traditional recipe implementation, type safety, and common patterns.

name: openrewrite description: This skill should be used when implementing or modifying OpenRewrite recipes in the Liftwizard project, when the user asks to "create a recipe", "implement a Refaster template", "convert to Refaster", "add an OpenRewrite transformation", or discusses recipe implementation patterns. Provides guidance on Refaster templates, traditional recipe implementation, type safety, and common patterns.

OpenRewrite Recipe Development

Guidance for implementing and modifying OpenRewrite recipes in the Liftwizard project, based on lessons learned from production experience.

When to Use This Skill

Use this skill when:

  • Implementing new OpenRewrite recipes
  • Converting existing recipes to use Refaster templates
  • Debugging type validation issues in recipes
  • Deciding between Refaster and traditional Recipe implementations

For test-related guidance, see the separate openrewrite-test skill.

Refaster vs. Traditional Recipe Implementation

When to Use Refaster Templates

✅ Good Use Cases:

  • Always prefer Refaster Templates
  • Try to implement with Refaster first always
  • Don't switch to traditional recipes unless the user confirms

❌ Poor Use Cases:

  • Varargs handling (until OpenRewrite issue #4397 adds @Repeated annotation support)
  • Generating method references (they lack proper type information in LST)

Combining Multiple @BeforeTemplate Methods

Rule: Combine multiple @BeforeTemplate methods into one nested class when they produce the same @AfterTemplate output.

Within a single nested class, you can have multiple @BeforeTemplate methods that all share one identical @AfterTemplate. This is useful when semantically different source patterns should transform to the same target pattern:

  • Flipped comparison order: size() == 0 vs 0 == size()isEmpty()
  • Different operators with same meaning: size() < 1 vs size() <= 0isEmpty()
  • Other structures with the same meaning: left == null ? right == null : left.equals(right) vs left == right || (left != null && left.equals(right))Objects.equals(left, right)

When to create separate nested classes:

Create separate nested classes when the @AfterTemplate output differs in any way:

  • Presence/absence of an optional parameter: assertThat(x).isNotEmpty() vs assertThat(x).as(message).isNotEmpty()separate classes
  • Different method calls: foo(x) vs bar(x)separate classes
  • Different parameter types that happen to look similar but aren't actually the same transformation

Refaster Naming Convention

When creating Refaster templates:

  • Main class name: RecipeName (e.g., ECSimplifyNegatedSatisfies)
  • Generated class name (used in tests): RecipeNameRecipes (e.g., ECSimplifyNegatedSatisfiesRecipes)
  • Update YAML recipe files to reference the generated Recipes class

Type Safety and Validation

Using classpath() vs dependsOn()

Prefer classpath() when possible:

  • Add .classpath("eclipse-collections-api") to JavaTemplate builders for real Eclipse Collections types
  • Add .classpath("eclipse-collections") for implementation classes if needed
  • Almost always works and is better than dependsOn()

Use dependsOn() when necessary:

  • Verify class stubs in AssertJ migration tests (eclipse-collections-testutils classpath doesn't work)

Experiment incrementally:

  1. Remove one dependsOn() text block
  2. Run tests - expect failure (missing type information)
  3. Add one classpath() entry to fix
  4. Run tests - should pass if real JAR class works
  5. Stop when tests fail despite class existing in JAR

Removing typeValidationOptions(TypeValidation.none())

Process:

  1. Remove .typeValidationOptions(TypeValidation.none()) line
  2. Run test
  3. If passes, commit
  4. If fails, investigate using OpenRewrite FAQ

Common Fix: Add appropriate classpath() entries to JavaTemplate builders to provide real type information

Fundamental Limitations (cannot remove TypeValidation.none()):

  • Refaster-generated method references lack proper type information
  • These tests must keep .typeValidationOptions(TypeValidation.none())

Common Implementation Patterns

Predicates.not() and Negation Patterns

Add support for both explicit negation (!method()) and Predicates.not() wrapping:

  • !iterable.noneSatisfy(p)iterable.anySatisfy(p)
  • Iterate.noneSatisfy(iterable, Predicates.not(p))Iterate.anySatisfy(iterable, p)
  • Ensure unused Predicates imports are correctly removed

Comparator Support in Sorted Collections

For sorted collection transformations, add overloads that accept a Comparator:

  • TreeSortedSet.newSet(Comparator, Arrays.asList(...))SortedSets.mutable.with(Comparator, ...)
  • Test with both Comparator.naturalOrder() and Comparator.reverseOrder()
  • Create separate arities (1-5) when using Refaster due to varargs limitation

Varargs Handling with Refaster

Until OpenRewrite issue #4397 is resolved:

  • Create separate template classes for each arity (typically 0-5)
  • Or convert to traditional Recipe using JavaIsoVisitor with dynamic placeholder building
  • Document in code that Refaster could be used once @Repeated annotation is supported

Documentation Best Practices

Document Refaster Limitations

When refactoring from traditional Recipe to Refaster, document in class javadoc:

  • What context-aware features were lost (e.g., circular transformation prevention)
  • Why Refaster cannot handle certain cases
  • Reference relevant OpenRewrite issues when applicable

Reference OpenRewrite Issues

  • Issue #4397: Lack of @Repeated annotation for varargs support in Refaster
  • Include issue numbers in comments for future refactoring opportunities

Key Takeaways

  1. Always prefer Refaster templates unless there's a specific limitation
  2. Always prefer classpath() over dependsOn() when it works
  3. Test type safety by removing TypeValidation.none() where possible
  4. Document limitations and trade-offs when converting to Refaster
  5. Traditional Recipe implementation is better when you need varargs handling or method reference generation
Skills Info
Original Name:openrewriteAuthor:liftwizard