Skip to content

Instantly share code, notes, and snippets.

@Bit-Flipper
Last active March 2, 2024 09:18
Show Gist options
  • Save Bit-Flipper/696262963a7c2985fb23442783695a76 to your computer and use it in GitHub Desktop.
Save Bit-Flipper/696262963a7c2985fb23442783695a76 to your computer and use it in GitHub Desktop.
package dev.bitflippers;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.openrewrite.Cursor;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Option;
import org.openrewrite.ScanningRecipe;
import org.openrewrite.SourceFile;
import org.openrewrite.Tree;
import org.openrewrite.TreeVisitor;
import org.openrewrite.internal.lang.Nullable;
import org.openrewrite.java.ChangeType;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.tree.J;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Set;
import java.util.UUID;
@Getter
@ToString
@EqualsAndHashCode(callSuper = false)
public class DuplicateClass extends ScanningRecipe<DuplicateClass.Accumulator> {
@JsonIgnore
private static final String NEW_CLASS_PREFIX = "CopyOf";
@Option(displayName = "Package",
description = "Name of the package with the class to be duplicated",
example = "dev.bitflippers")
String packageName;
@Option(displayName = "Class Name",
description = "Name of the class to be duplicated",
example = "ExampleClass")
String simpleClassName;
public DuplicateClass(@JsonProperty("packageName") String packageName, @JsonProperty("simpleClassName") String simpleClassName) {
this.packageName = packageName;
this.simpleClassName = simpleClassName;
}
private String getNewSimpleClassName() {
return NEW_CLASS_PREFIX + simpleClassName;
}
private String getFullyQualifiedClassName() {
return packageName + "." + simpleClassName;
}
private String getNewFullyQualifiedClassName() {
return packageName + "." + getNewSimpleClassName();
}
private String getClassPath() {
return getFullyQualifiedClassName().replace(".", "/");
}
private String getNewClassPath() {
return getNewFullyQualifiedClassName().replace(".", "/");
}
@Override
public String getDisplayName() {
return "Duplicate Java Class";
}
@Override
public String getDescription() {
return "Creates a copy of a given Java class with a new name.";
}
@Getter
@Setter
static class Accumulator {
SourceFile sourceFileToDuplicate;
boolean shouldCreate = true;
}
@Override
public Accumulator getInitialValue(ExecutionContext ctx) {
return new Accumulator();
}
@Override
public TreeVisitor<?, ExecutionContext> getScanner(Accumulator acc) {
return new TreeVisitor<>() {
@Override
public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext executionContext, Cursor parent) {
SourceFile sourceFile = (SourceFile) tree;
String path = sourceFile.getSourcePath().toString();
if (path.contains(getNewClassPath())) {
acc.setShouldCreate(false);
} else if (acc.getSourceFileToDuplicate() == null && path.contains(getClassPath())) {
acc.setSourceFileToDuplicate(sourceFile);
}
return sourceFile;
}
};
}
@Override
public Collection<? extends SourceFile> generate(Accumulator acc, ExecutionContext ctx) {
var sourceFile = acc.getSourceFileToDuplicate();
if (!acc.shouldCreate || sourceFile == null) {
return Set.of();
}
var oldPath = sourceFile.getSourcePath();
var newPath = Path.of(oldPath.toString().replace(getClassPath(), getNewClassPath()));
SourceFile newSourceFile = sourceFile.withSourcePath(newPath)
.withId(UUID.randomUUID());
return Set.of(newSourceFile);
}
@Override
public TreeVisitor<?, ExecutionContext> getVisitor(Accumulator acc) {
return new JavaIsoVisitor<>(){
@Override
public boolean isAcceptable(SourceFile sourceFile, ExecutionContext executionContext) {
return sourceFile.getSourcePath().toString().contains(getNewClassPath());
}
@Override
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext executionContext) {
var changeTypeRecipe = new ChangeType(getFullyQualifiedClassName(),
getNewFullyQualifiedClassName(),
false);
doAfterVisit(changeTypeRecipe.getVisitor());
return super.visitClassDeclaration(classDecl, executionContext);
}
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment