OpenRewrite

Automated Refactorings

Java Software Engineer

Line of Business Public

Merlin Bögershausen / @mboegie

Was ist Refactoring?

Refactoring is a controlled technique for improving the design of an existing code base. Its essence is applying a series of small behavior-preserving transformations, each of which "too small to be worth doing".
— Fowler

Multiline Strings

Klassisch

String query =
  "SELECT * FROM\n" +
  "my_table\n" +
  "WHERE something = 1;";

Java 15+

String query = """
  SELECT * FROM
  my_table
  WHERE something = 1;\
  """;

Framework Migration

Spring Boot 2.7 Migration Guide

Migration Types

Komplexitaet verteiling

Automate IT!

Open Rewrite Logo

Let’s dive in!

Screenshot

Configure Plugin

mvn -U org.openrewrite.maven:rewrite-maven-plugin:run
<plugin>
  <groupId>org.openrewrite.maven</groupId>
  <artifactId>rewrite-maven-plugin</artifactId>
  <version>4.45.0</version>
</plugin>

Activate Recipe

-Drewrite.activeRecipes=\
 org.openrewrite.java.RemoveUnusedImports
<configuration>
  <activeRecipes>
    <recipe>
      org.openrewrite.java.RemoveUnusedImports
    </recipe>
  </activeRecipes>
</configuration>

Refactor!

./mvnw rewrite:run
Changes have been made to .github/workflows/maven-build.yml by:
 org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_0
  org.openrewrite.java.spring.boot3.MavenPomUpgrade
   org.openrewrite.java.migrate.JavaVersion17
    org.openrewrite.java.migrate.UpgradeJavaVersion:
      {version=17}
  org.openrewrite.java.migrate.UpgradeToJava17
   org.openrewrite.github.SetupJavaUpgradeJavaVersion

LST

// 0
class A { // 1
  void test() {
    int a;
    a = 0;
  }
}
-J.CompilationUnit // 0
 \-J.ClassDeclaration // 1 - start
   |-J.Identifier | "A"
   \-J.Block // 1 - end
     \-J.MethodDeclaration | "MethodDeclaration{A{name=test,return=void,parameters=[]}}"

Recipe

Recipe ein ausführbares Refactoring

public class MakePublic extends Recipe {
  @Override
  protected JavaVisitor<ExecutionContext> getVisitor() {
    return new MakePublicVisitor(); // 1
  }
  public String getDisplayName() {
    return "Change class visibility to public 🤡";
  }
  private class MakePublicVisitor
    extends JavaVisitor<ExecutionContext> {}
}

Visitor

Bearbeite den LST mit Visitors

class JavaVisitor<P> extends TreeVisitor<J, P> {
  J visitStatement(Statement statement) {}
  J visitAnnotatedType(J.AnnotatedType annotatedType)  {}
  J visitAnnotation(J.Annotation annotation) {}
  J visitAssert(J.Assert azzert) {}
  J visitAssignment(J.Assignment assign) {}
  J visitAssignmentOperation(J.AssignmentOperation assignOp) {}
  //...
}

Visitor Implementation

new JavaIsoVisitor<ExecutionContext> {
  public J.ClassDeclaration visitClassDeclaration(
          J.ClassDeclaration cd, ExecutionContext ctx) { // 1
    cd = super.visitClassDeclaration(cd, ctx);
    List<J.Modifier> modifiers = cd.getModifiers(); // 2
    modifiers.removeIf( //2
            m -> J.Modifier.Type.Private.equals(m.getType()));
    // and Protected & Publicπ
    modifiers.add(PUBLIC_MODIFIER); // 3
    return cd.withModifiers(modifiers); // 4
  }
}

Declarative YAML

---
type: specs.openrewrite.org/v1beta/recipe
name: io.github.mboegers.rewrite.MakePublic
displayName: Change method access level to public
recipeList:
  - org.openrewrite.java.ChangeMethodAccessLevel:
      methodPattern: *
      newAccessLevel: public
      matchOverrides: null

Styles

type: specs.openrewrite.org/v1beta/style
name: io.moderne.spring.style
styleConfigs:
  - org.openrewrite.java.style.NeedBracesStyle:
      allowSingleLineStatement: false
      allowEmptyLoopBody: true
for(int i = 0; i < 10; i++);
if(success()) return false;
for(int i = 0; i < 10; i++);
if(success()){
    return false;
}

Takeaways

600

Moderne.io

700

Abilities

powerOfRewrite

.stretch

.stretch

Image Credits

  • Project Logos from respective Project Page

  • Migration Types from Moderne Prove of Value

  • Moderne UI Screenshot by Author