package org.openrewrite.samples;
import java.util.stream.Collectors;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.MethodMatcher;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.J.MethodDeclaration;
import org.openrewrite.java.tree.J.Modifier.Type;
public class ExpandCustomerInfo extends Recipe {
public String getDisplayName() {
return "Expand Customer Info";
public String getDescription() {
return "Expand the `CustomerInfo` class with new fields.";
// OpenRewrite provides a managed environment in which it discovers, instantiates, and wires configuration into Recipes.
// This recipe has no configuration and when it is executed, it will delegate to its visitor.
protected ExpandCustomerInfoVisitor getVisitor() {
return new ExpandCustomerInfoVisitor();
private class ExpandCustomerInfoVisitor extends JavaIsoVisitor<ExecutionContext> {
// Used to identify the method declaration that will be refactored
private final MethodMatcher methodMatcher = new MethodMatcher("com.yourorg.Customer setCustomerInfo(String)");
// Template used to add a method body to "setCustomerInfo()" method declaration.
private final JavaTemplate addMethodBodyTemplate = JavaTemplate.builder(this::getCursor, "")
// Template used to insert two additional parameters into the "setCustomerInfo()" method declaration.
private final JavaTemplate addMethodParametersTemplate = JavaTemplate.builder(this::getCursor, "Date dateOfBirth, String firstName, #{}")
.imports("java.util.Date")
// Template used to add initializing statements to the method body
private final JavaTemplate addStatementsTemplate = JavaTemplate.builder(this::getCursor,
"this.dateOfBirth = dateOfBirth;\n" +
"this.firstName = firstName;\n" +
"this.lastName = lastName;\n")
public MethodDeclaration visitMethodDeclaration(MethodDeclaration m, ExecutionContext c) {
if (!methodMatcher.matches(m.getType())) {
// Remove the abstract modifier from the method.
m = m.withModifiers(m.getModifiers().stream()
.filter(mod -> mod.getType() != Type.Abstract)
.collect(Collectors.toList()));
m = m.withTemplate(addMethodBodyTemplate, m.getCoordinates().replaceBody());
// Add two parameters to the method declaration by inserting them in from of the first argument.
m = m.withTemplate(addMethodParametersTemplate,
m.getCoordinates().replaceParameters(),
m.getParameters().get(0));
// Add an import for java.util.Date to this compilation unit's list of imports.
maybeAddImport("java.util.Date");
// Safe to assert since we just added a body to the method
assert m.getBody() != null;
// Add the assignment statements to the method body
m = m.withTemplate(addStatementsTemplate, m.getBody().getCoordinates().lastStatement());