Skip to content

Commit

Permalink
fix: Add DelegatingRecipe to find underlying recipe for loading optio…
Browse files Browse the repository at this point in the history
…ns (#4286)

* fix: Add method to determine recipe class that can be overwritten in wrappers.

Fixes a problem where RecipeDescriptor does not have the options on it when a recipe has preconditions.

* Add test and use (sort of) interface

* convert to interface

* Update DeclarativeRecipeTest.java

* Also use for ScanningRecipe
  • Loading branch information
pstreef authored Jun 28, 2024
1 parent 6b65911 commit 5f8c839
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 8 deletions.
20 changes: 14 additions & 6 deletions rewrite-core/src/main/java/org/openrewrite/Recipe.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import lombok.Setter;
import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.Nls;
import org.openrewrite.config.DataTableDescriptor;
import org.openrewrite.config.OptionDescriptor;
import org.openrewrite.config.RecipeDescriptor;
Expand Down Expand Up @@ -131,7 +130,7 @@ public String getInstanceName() {
return getDisplayName() + " " + suffix;
}

List<OptionDescriptor> options = new ArrayList<>(getOptionDescriptors(getClass()));
List<OptionDescriptor> options = new ArrayList<>(getOptionDescriptors());
options.removeIf(opt -> !opt.isRequired());
if (options.isEmpty()) {
return getDisplayName();
Expand Down Expand Up @@ -209,7 +208,7 @@ public final RecipeDescriptor getDescriptor() {
}

protected RecipeDescriptor createRecipeDescriptor() {
List<OptionDescriptor> options = getOptionDescriptors(this.getClass());
List<OptionDescriptor> options = getOptionDescriptors();
List<RecipeDescriptor> recipeList1 = new ArrayList<>();
for (Recipe next : getRecipeList()) {
recipeList1.add(next.getDescriptor());
Expand All @@ -226,14 +225,19 @@ protected RecipeDescriptor createRecipeDescriptor() {
getMaintainers(), getContributors(), getExamples(), recipeSource);
}

private List<OptionDescriptor> getOptionDescriptors(Class<?> recipeClass) {
private List<OptionDescriptor> getOptionDescriptors() {
Recipe recipe = this;
if (this instanceof DelegatingRecipe) {
recipe = ((DelegatingRecipe) this).getDelegate();
}

List<OptionDescriptor> options = new ArrayList<>();

for (Field field : recipeClass.getDeclaredFields()) {
for (Field field : recipe.getClass().getDeclaredFields()) {
Object value;
try {
field.setAccessible(true);
value = field.get(this);
value = field.get(recipe);
} catch (IllegalAccessException e) {
value = null;
}
Expand Down Expand Up @@ -416,4 +420,8 @@ public Object clone() {
throw new RuntimeException(e);
}
}

public interface DelegatingRecipe {
Recipe getDelegate();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ public boolean isAcceptable(SourceFile sourceFile, ExecutionContext ctx) {

@EqualsAndHashCode(callSuper = false)
@Value
static class BellwetherDecoratedRecipe extends Recipe {
static class BellwetherDecoratedRecipe extends Recipe implements DelegatingRecipe {

DeclarativeRecipe.PreconditionBellwether bellwether;
Recipe delegate;
Expand Down Expand Up @@ -206,7 +206,7 @@ public boolean causesAnotherCycle() {

@Value
@EqualsAndHashCode(callSuper = false)
static class BellwetherDecoratedScanningRecipe<T> extends ScanningRecipe<T> {
static class BellwetherDecoratedScanningRecipe<T> extends ScanningRecipe<T> implements DelegatingRecipe {

DeclarativeRecipe.PreconditionBellwether bellwether;
ScanningRecipe<T> delegate;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,36 @@ public PlainText visitText(PlainText text, ExecutionContext ctx) {
);
}

@Test
void addingPreconditionsWithOptions() {
DeclarativeRecipe dr = new DeclarativeRecipe("test", "test", "test", null,
null, null, true, null);
dr.addPrecondition(
toRecipe(() -> new PlainTextVisitor<>() {
@Override
public PlainText visitText(PlainText text, ExecutionContext ctx) {
if ("1".equals(text.getText())) {
return SearchResult.found(text);
}
return text;
}
})
);
dr.addUninitialized(
new ChangeText("2")
);
dr.addUninitialized(
new ChangeText("3")
);
dr.initialize(List.of(), Map.of());
assertThat(dr.getDescriptor().getRecipeList())
.hasSize(3) // precondition + 2 recipes with options
.flatExtracting(RecipeDescriptor::getOptions)
.hasSize(2)
.extracting(OptionDescriptor::getName)
.containsOnly("toText");
}

@Test
void uninitializedFailsValidation() {
DeclarativeRecipe dr = new DeclarativeRecipe("test", "test", "test", null,
Expand Down

0 comments on commit 5f8c839

Please sign in to comment.