Module 1: Recipe development environment
If you completed the Introduction to OpenRewrite workshop, you are familiar with how to run recipes and build them in Moderne using the recipe builder. In this module, you will learn how to write your own recipes.
If you get stuck, you can reference the workshop-solutions branch of the starter repo for completed examples (and you’ll also see code embedded inline throughout the steps).
You'll want to have the following installed:
- Java 21, as our RewriteTests use text blocks.
- The
rewrite-recipe-starterproject expects JDK 21. (Temurin JDK 21.0.7 (temurin-21.0.7), for example, has been specified in the.sdkmanrcfile, but other version 21 JDKs may work as well.) - Recipes use Java 8 source level, so they can run on Java 8 and higher.
- The
- IntelliJ IDEA (2025.3+ recommended)
- The OpenRewrite plugin, to run and write YAML recipes.
- The Moderne plugin, for faster recipe development and to help debug recipes.
- The Moderne CLI, to run recipes at scale locally, and debug against serialized LSTs.
If you have not already completed the Introduction to OpenRewrite course, go there first and complete at least Module 1 before continuing. The exercises in this workshop assume that module has been completed - meaning that the Moderne CLI is working and that you have a ~/moderne-workshop directory with the Default org synced.
Exercise 1-1: Create and test your own recipe module
Goals for this exercise
- Set up a new recipe module in your IDE, based on the
rewrite-recipe-starterproject. - Run the unit tests for the recipe module, to ensure everything is set up correctly.
- Install your recipe module to your local Maven repository for debugging later.
Steps
Step 1: Clone and open the project
- Clone or fork the
rewrite-recipe-starterproject or use it as a template. - Open the project in IntelliJ IDEA.
- If prompted, choose Maven or Gradle import (your preference).
- Enable annotation processing if IntelliJ suggests it.
For a better idea about the reference recipes and tests that are included in the starter project, review the README.md there. Many of them will be referenced later in this workshop.
Step 2: Run tests once
- Run all unit tests to confirm your environment is working. To do this in IntelliJ, navigate to the
src/test/javafolder in the Project Tool window and right-click on it. Then select the green play button that says Run 'All Tests' (if you're using Maven), or 'Run Tests in rewrite-recipe-starter' (if you're using Gradle). - Confirm that all tests pass, and you should see a message that the project was successfully built. You can ignore any warnings as long as the build is successful.
- (Optional) If you're using Gradle and tests feel slow, consider updating the way tests run in IntelliJ for faster feedback.
Step 3: (Optional) Customize coordinates
To make the project your own and allow it to be versioned and shared without conflicts, customize the project's group ID and artifact ID in the pom.xml file (Maven), or build.gradle.kts and settings.gradle.kts files (Gradle). You'll also want to update the Java package names to reflect these changes as well. (You may consider using the ChangePackage OpenRewrite recipe or the 'Replace in path' feature of IntelliJ to do a search and replace of com.yourorg across the project.)
For the purposes of this workshop, this step isn't required, so feel free to leave it alone and continue to use com.yourorg.
Step 4: Install and verify locally
- Install the project to your local Maven repository by running one of the following commands from the root of your project, depending on which build tool you prefer:
# Maven
mvn install
# Gradle
./gradlew publishToMavenLocal
- Install the recipe package to the local recipe marketplace with the Moderne CLI:
mod config recipes jar install com.yourorg:rewrite-recipe-starter:LATEST
- To confirm that everything is set up for testing imperative recipes, open the
AssertEqualsToAssertThatclass in IntelliJ, right-click the class name, and select Set Active Recipe. Then open a terminal, navigate to your workshop directory, and run:
cd ~/moderne-workshop
mod run . --active-recipe
This requires the Moderne plugin; if it is not installed, the Set Active Recipe option will not appear. You can still run the recipe with the mod CLI if you refer to the recipe by name (as in the next step).
Takeaways
- The
rewrite-recipe-starterproject is a good starting point for your own recipe module. - There are various types of recipes included in the starter project, to give you a feel for how they're implemented.
- The unit tests in the starter project take in text blocks that assert the state before and after running a recipe.
- You can quickly test recipes against actual repositories with the CLI.
Three types of recipes
It's important to note there are different types of recipes, each with their own trade-offs.
- Declarative recipes are the simplest to write, and are the most common type of recipe. They are written in YAML, and often tie together existing recipe building blocks with some light configuration.
- Refaster rules bring you the benefit of compiler support, and work best for straightforward replacements. They generate recipes that can also be used as a starting point for more complex recipe implementations.
- Imperative recipes are the most powerful, and allow you to write Java code to implement your recipe. By using the
JavaTemplatebuilder, you can keep complexity down, as you define arbitrary code changes.
No matter which method of recipe development you choose, you can (and should) always write unit tests for your recipe. Beyond that, there are best practices for writing recipes, such as ensuring idempotence, and avoiding harmful changes. The remaining modules will explore in more detail how to write and test all three of these types of recipes.