Skip to content

Instantly share code, notes, and snippets.

@Bit-Flipper
Created January 14, 2024 21:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Bit-Flipper/50af8ea183d1c92140853fa6ca60ce2e to your computer and use it in GitHub Desktop.
Save Bit-Flipper/50af8ea183d1c92140853fa6ca60ce2e to your computer and use it in GitHub Desktop.
package org.example;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Value;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaParser;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;
import org.openrewrite.java.tree.Statement;
import org.openrewrite.java.tree.TypeTree;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@Value
@EqualsAndHashCode(callSuper = true)
public class JavaGetterToLombokGetter extends Recipe {
@Override
public String getDisplayName() {
return "Java getter to lombok getter";
}
@Override
public String getDescription() {
return "Replaces simple Java getter methods with lombok @Getter annotations.";
}
private static final String GETTER_METHODS_TO_DELETE_KEY = "GETTER_METHODS_TO_DELETE_KEY";
private static final String GET = "get";
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new JavaIsoVisitor<>() {
@Override
public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations multiVariable, ExecutionContext executionContext) {
multiVariable = super.visitVariableDeclarations(multiVariable, executionContext);
if (multiVariable.getVariables().size() != 1) {
return multiVariable;
}
J.ClassDeclaration classDeclaration = getCursor().dropParentUntil(p -> p instanceof J.ClassDeclaration).getValue();
Set<J.MethodDeclaration> getterDeclarations = classDeclaration.getBody()
.getStatements()
.stream()
.filter(s -> s instanceof J.MethodDeclaration)
.map(s -> (J.MethodDeclaration) s)
.collect(Collectors.toSet());
Optional<J.MethodDeclaration> maybeMethodDeclaration = findMatchingGetterDeclaration(multiVariable, getterDeclarations);
if (maybeMethodDeclaration.isEmpty()) {
return multiVariable;
}
executionContext.putMessageInSet(GETTER_METHODS_TO_DELETE_KEY, maybeMethodDeclaration.get());
maybeAddImport(Getter.class.getTypeName(), false);
return addLombokGetterAnnotationTo(multiVariable);
}
private Optional<J.MethodDeclaration> findMatchingGetterDeclaration(J.VariableDeclarations multiVariable, Set<J.MethodDeclaration> methodDeclarations) {
for (J.MethodDeclaration methodDeclaration : methodDeclarations) {
J.VariableDeclarations.NamedVariable namedVariable = multiVariable.getVariables().get(0);
String simpleMethodName = methodDeclaration.getSimpleName();
String fieldName = simpleMethodName.substring(GET.length());
fieldName = fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
if (!simpleMethodName.startsWith(GET) || !fieldName.equals(namedVariable.getSimpleName())) {
continue;
}
TypeTree returnType = methodDeclaration.getReturnTypeExpression();
if (!multiVariable.getType().equals(returnType.getType())) {
continue;
}
List<Statement> statements = methodDeclaration.getBody().getStatements();
if (statements.size() != 1) {
continue;
}
Statement statement = statements.get(0);
if (!(statement instanceof J.Return) || !(((J.Return) statement).getExpression() instanceof J.Identifier)) {
continue;
}
JavaType.Variable methodFieldReturned = ((J.Identifier) ((J.Return) statement).getExpression()).getFieldType();
JavaType.Variable field = multiVariable.getVariables().get(0).getVariableType();
if (!methodFieldReturned.equals(field)) {
continue;
}
return Optional.of(methodDeclaration);
}
return Optional.empty();
}
private J.VariableDeclarations addLombokGetterAnnotationTo(J.VariableDeclarations multiVariable) {
return JavaTemplate.builder("@Getter")
.javaParser(JavaParser.fromJavaVersion())
.build()
.apply(getCursor(), multiVariable.getCoordinates().addAnnotation(Comparator.comparing(J.Annotation::toString)));
}
@Override
public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext executionContext) {
method = super.visitMethodDeclaration(method, executionContext);
Set<J.MethodDeclaration> methodDeclarationsToDelete = executionContext.getMessage(GETTER_METHODS_TO_DELETE_KEY, Set.of());
if (methodDeclarationsToDelete.contains(method)) {
return null;
}
return method;
}
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment