Skip to content

Commit

Permalink
Apply best practices and add some more comments
Browse files Browse the repository at this point in the history
  • Loading branch information
timtebeek committed Feb 25, 2024
1 parent 3a47174 commit 7ef8578
Show file tree
Hide file tree
Showing 17 changed files with 380 additions and 188 deletions.
3 changes: 2 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
plugins {
id("org.openrewrite.build.recipe-library") version "latest.release"

// Only needed when you want to apply the OpenRewriteBestPractices recipe to your recipes
// Only needed when you want to apply the OpenRewriteBestPractices recipe to your recipes through
// ./gradlew rewriteRun -Drewrite.activeRecipe=org.openrewrite.recipes.OpenRewriteBestPractices
id("org.openrewrite.rewrite") version "latest.release"
}

Expand Down
46 changes: 32 additions & 14 deletions src/main/java/com/yourorg/AppendToReleaseNotes.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yourorg;

import lombok.EqualsAndHashCode;
import lombok.Value;
import org.openrewrite.*;
import org.openrewrite.internal.lang.Nullable;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.tree.J;
import org.openrewrite.text.PlainText;
import org.openrewrite.text.PlainTextParser;
import org.openrewrite.text.PlainTextVisitor;
import org.openrewrite.yaml.tree.Yaml;

import java.nio.file.Path;
import java.nio.file.Paths;
Expand All @@ -18,10 +30,9 @@
import java.util.stream.Collectors;

@Value
@EqualsAndHashCode(callSuper = true)
@EqualsAndHashCode(callSuper = false)
public class AppendToReleaseNotes extends ScanningRecipe<AppendToReleaseNotes.Accumulator> {


@Override
public String getDisplayName() {
return "Append to release notes";
Expand All @@ -33,10 +44,11 @@ public String getDescription() {
}

@Option(displayName = "Message",
description = "Message to append to the bottom of RELEASE.md.")
description = "Message to append to the bottom of RELEASE.md.",
example = "## 1.0.0\n\n- New feature")
String message;


// The shared state between the scanner and the visitor. The custom class ensures we can easily extend the recipe.
public static class Accumulator {
boolean found;
}
Expand All @@ -50,8 +62,8 @@ public Accumulator getInitialValue(ExecutionContext ctx) {
public TreeVisitor<?, ExecutionContext> getScanner(Accumulator acc) {
return new TreeVisitor<Tree, ExecutionContext>() {
@Override
public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext executionContext) {
if(tree instanceof SourceFile) {
public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) {
if (tree instanceof SourceFile) {
Path sourcePath = ((SourceFile) tree).getSourcePath();
acc.found |= "RELEASE.md".equals(sourcePath.toString());
}
Expand All @@ -62,11 +74,14 @@ public TreeVisitor<?, ExecutionContext> getScanner(Accumulator acc) {

@Override
public Collection<? extends SourceFile> generate(Accumulator acc, ExecutionContext ctx) {
if(acc.found) {
if (acc.found) {
return Collections.emptyList();
}
// If the file was not found, create it
return PlainTextParser.builder().build()
// We start with an empty string that we then append to in the visitor
.parse("")
// Be sure to set the source path for any generated file, so that the visitor can find it
.map(it -> (SourceFile) it.withSourcePath(Paths.get("RELEASE.md")))
.collect(Collectors.toList());
}
Expand All @@ -75,14 +90,17 @@ public Collection<? extends SourceFile> generate(Accumulator acc, ExecutionConte
public TreeVisitor<?, ExecutionContext> getVisitor(Accumulator acc) {
return new PlainTextVisitor<ExecutionContext>() {
@Override
public PlainText visitText(PlainText text, ExecutionContext executionContext) {
PlainText t = super.visitText(text, executionContext);
if(!"RELEASE.md".equals(t.getSourcePath().toString())) {
public PlainText visitText(PlainText text, ExecutionContext ctx) {
PlainText t = super.visitText(text, ctx);
// If the file is not RELEASE.md, don't modify it
if (!"RELEASE.md".equals(t.getSourcePath().toString())) {
return t;
}
if(t.getText().contains(message)) {
// If the file already contains the message, don't append it again
if (t.getText().contains(message)) {
return t;
}
// Append the message to the end of the file
return t.withText(t.getText() + "\n" + message);
}
};
Expand Down
32 changes: 25 additions & 7 deletions src/main/java/com/yourorg/AssertEqualsToAssertThat.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yourorg;

import lombok.EqualsAndHashCode;
Expand All @@ -6,15 +21,18 @@
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.*;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaParser;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.MethodMatcher;
import org.openrewrite.java.search.UsesType;
import org.openrewrite.java.tree.Expression;
import org.openrewrite.java.tree.J;

import java.util.List;

@Value
@EqualsAndHashCode(callSuper = true)
@EqualsAndHashCode(callSuper = false)
public class AssertEqualsToAssertThat extends Recipe {
@Override
public String getDisplayName() {
Expand All @@ -34,15 +52,15 @@ public TreeVisitor<?, ExecutionContext> getVisitor() {
return Preconditions.check(new UsesType<>("org.junit.jupiter.api.Assertions", null),
new JavaIsoVisitor<ExecutionContext>() {
@Override
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext executionContext) {
J.MethodInvocation m = super.visitMethodInvocation(method, executionContext);
if(!MATCHER.matches(m)) {
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
J.MethodInvocation m = super.visitMethodInvocation(method, ctx);
if (!MATCHER.matches(m)) {
return m;
}
List<Expression> arguments = m.getArguments();
maybeAddImport("org.assertj.core.api.Assertions");
maybeRemoveImport("org.junit.jupiter.api.Assertions");
if(arguments.size() == 2) {
if (arguments.size() == 2) {
Expression expected = arguments.get(0);
Expression actual = arguments.get(1);

Expand All @@ -52,7 +70,7 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu
.classpath("assertj-core"))
.build()
.apply(getCursor(), m.getCoordinates().replace(), actual, expected);
} else if(arguments.size() == 3) {
} else if (arguments.size() == 3) {
Expression expected = arguments.get(0);
Expression actual = arguments.get(1);
Expression description = arguments.get(2);
Expand Down
26 changes: 22 additions & 4 deletions src/main/java/com/yourorg/ClassHierarchy.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yourorg;

import com.yourorg.table.ClassHierarchyReport;
Expand All @@ -10,9 +25,8 @@
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;


@Value
@EqualsAndHashCode(callSuper = true)
@EqualsAndHashCode(callSuper = false)
public class ClassHierarchy extends Recipe {

transient ClassHierarchyReport report = new ClassHierarchyReport(this);
Expand All @@ -34,12 +48,16 @@ public TreeVisitor<?, ExecutionContext> getVisitor() {
@Override
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) {
JavaType.FullyQualified type = classDecl.getType();
if(type instanceof JavaType.Class && type.getSupertype() != null) {
// Capture all classes, which all extend java.lang.Object
if (type instanceof JavaType.Class && type.getSupertype() != null) {
JavaType.FullyQualified supertype = type.getSupertype();
report.insertRow(ctx, new ClassHierarchyReport.Row(type.getFullyQualifiedName(),
// Capture the direct superclass
report.insertRow(ctx, new ClassHierarchyReport.Row(
type.getFullyQualifiedName(),
ClassHierarchyReport.Relationship.EXTENDS,
supertype.getFullyQualifiedName()));

// Capture all interfaces
for (JavaType.FullyQualified anInterface : type.getInterfaces()) {
report.insertRow(ctx, new ClassHierarchyReport.Row(
type.getFullyQualifiedName(),
Expand Down
108 changes: 57 additions & 51 deletions src/main/java/com/yourorg/NoGuavaListsNewArrayList.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,14 @@

import lombok.EqualsAndHashCode;
import lombok.Value;
import org.openrewrite.*;
import org.openrewrite.java.*;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.MethodMatcher;
import org.openrewrite.java.TreeVisitingPrinter;
import org.openrewrite.java.search.UsesMethod;
import org.openrewrite.java.tree.J;

Expand All @@ -45,61 +51,61 @@ public String getDescription() {
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return Preconditions.check(
// Any change to the AST made by the preconditions check will lead to the visitor returned by Recipe
// .getVisitor() being applied
// No changes made by the preconditions check will be kept
Preconditions.or(new UsesMethod<>(NEW_ARRAY_LIST),
new UsesMethod<>(NEW_ARRAY_LIST_ITERABLE),
new UsesMethod<>(NEW_ARRAY_LIST_CAPACITY)),
// To avoid stale state persisting between cycles, getVisitor() should always return a new instance of
// its visitor
new JavaVisitor<ExecutionContext>() {
private final JavaTemplate newArrayList = JavaTemplate.builder("new ArrayList<>()")
.imports("java.util.ArrayList")
.build();
// Any change to the AST made by the preconditions check will lead to the visitor returned by Recipe
// .getVisitor() being applied
// No changes made by the preconditions check will be kept
Preconditions.or(new UsesMethod<>(NEW_ARRAY_LIST),
new UsesMethod<>(NEW_ARRAY_LIST_ITERABLE),
new UsesMethod<>(NEW_ARRAY_LIST_CAPACITY)),
// To avoid stale state persisting between cycles, getVisitor() should always return a new instance of
// its visitor
new JavaVisitor<ExecutionContext>() {
private final JavaTemplate newArrayList = JavaTemplate.builder("new ArrayList<>()")
.imports("java.util.ArrayList")
.build();

private final JavaTemplate newArrayListIterable =
JavaTemplate.builder("new ArrayList<>(#{any(java.util.Collection)})")
.imports("java.util.ArrayList")
.build();
private final JavaTemplate newArrayListIterable =
JavaTemplate.builder("new ArrayList<>(#{any(java.util.Collection)})")
.imports("java.util.ArrayList")
.build();

private final JavaTemplate newArrayListCapacity =
JavaTemplate.builder("new ArrayList<>(#{any(int)})")
.imports("java.util.ArrayList")
.build();
private final JavaTemplate newArrayListCapacity =
JavaTemplate.builder("new ArrayList<>(#{any(int)})")
.imports("java.util.ArrayList")
.build();

// This method override is only here to show how to print the AST for debugging purposes.
// You can remove this method if you don't need it.
@Override
public J visitCompilationUnit(J.CompilationUnit cu, ExecutionContext ctx) {
// This is a useful debugging tool if you're ever unsure what the visitor is visiting
String printed = TreeVisitingPrinter.printTree(cu);
System.out.println(printed);
// You must always delegate to the super method to ensure the visitor continues to visit deeper
return super.visitCompilationUnit(cu, ctx);
}
// This method override is only here to show how to print the AST for debugging purposes.
// You can remove this method if you don't need it.
@Override
public J visitCompilationUnit(J.CompilationUnit cu, ExecutionContext ctx) {
// This is a useful debugging tool if you're ever unsure what the visitor is visiting
String printed = TreeVisitingPrinter.printTree(cu);
System.out.printf(printed);
// You must always delegate to the super method to ensure the visitor continues to visit deeper
return super.visitCompilationUnit(cu, ctx);
}

// Visit any method invocation, and replace matches with the new ArrayList instantiation.
@Override
public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
if (NEW_ARRAY_LIST.matches(method)) {
maybeRemoveImport("com.google.common.collect.Lists");
maybeAddImport("java.util.ArrayList");
return newArrayList.apply(getCursor(), method.getCoordinates().replace());
} else if (NEW_ARRAY_LIST_ITERABLE.matches(method)) {
maybeRemoveImport("com.google.common.collect.Lists");
maybeAddImport("java.util.ArrayList");
return newArrayListIterable.apply(getCursor(), method.getCoordinates().replace(),
method.getArguments().get(0));
} else if (NEW_ARRAY_LIST_CAPACITY.matches(method)) {
maybeRemoveImport("com.google.common.collect.Lists");
maybeAddImport("java.util.ArrayList");
return newArrayListCapacity.apply(getCursor(), method.getCoordinates().replace(),
method.getArguments().get(0));
// Visit any method invocation, and replace matches with the new ArrayList instantiation.
@Override
public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
if (NEW_ARRAY_LIST.matches(method)) {
maybeRemoveImport("com.google.common.collect.Lists");
maybeAddImport("java.util.ArrayList");
return newArrayList.apply(getCursor(), method.getCoordinates().replace());
} else if (NEW_ARRAY_LIST_ITERABLE.matches(method)) {
maybeRemoveImport("com.google.common.collect.Lists");
maybeAddImport("java.util.ArrayList");
return newArrayListIterable.apply(getCursor(), method.getCoordinates().replace(),
method.getArguments().get(0));
} else if (NEW_ARRAY_LIST_CAPACITY.matches(method)) {
maybeRemoveImport("com.google.common.collect.Lists");
maybeAddImport("java.util.ArrayList");
return newArrayListCapacity.apply(getCursor(), method.getCoordinates().replace(),
method.getArguments().get(0));
}
return super.visitMethodInvocation(method, ctx);
}
return super.visitMethodInvocation(method, ctx);
}
}
);
}
}
3 changes: 2 additions & 1 deletion src/main/java/com/yourorg/SimplifyTernary.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ boolean before(boolean expr) {

@AfterTemplate
boolean after(boolean expr) {
// We wrap the expression in parentheses as the input expression might be a complex expression
return !(expr);
}
}
}
}
Loading

0 comments on commit 7ef8578

Please sign in to comment.