Skip to content

DeclarativeRecipe doesn't register accumulators for nested ScanningRecipes in OR preconditions #6698

@Jenson3210

Description

@Jenson3210

Problem

When using the OR precondition pattern with ScanningRecipes like ModuleHasDependency or RepositoryContainsFile, the recipes fail with a NullPointerException:

java.lang.NullPointerException: Cannot invoke "java.util.concurrent.atomic.AtomicBoolean.get()" because "acc" is null
    at org.openrewrite.search.RepositoryContainsFile.getVisitor(RepositoryContainsFile.java:73)
    at org.openrewrite.config.DeclarativeRecipe.orVisitors(DeclarativeRecipe.java:483)

Example

---
type: specs.openrewrite.org/v1beta/recipe
name: org.example.ProjectUsesJackson
description: OR precondition - matches if ANY condition is true
recipeList:
  - org.openrewrite.java.dependencies.search.ModuleHasDependency:
      groupIdPattern: com.fasterxml.jackson.core
      artifactIdPattern: jackson-*
  - org.openrewrite.search.RepositoryContainsFile:
      filePattern: "**/jackson-config.json"

---
type: specs.openrewrite.org/v1beta/recipe
name: org.example.AddJacksonAnnotations
preconditions:
  - org.example.ProjectUsesJackson
recipeList:
  - org.openrewrite.java.dependencies.AddDependency:
      groupId: com.fasterxml.jackson.core
      artifactId: jackson-annotations
      version: 2.x

Root Cause

In DeclarativeRecipe.getInitialValue(), only direct preconditions get their accumulators registered:

for (Recipe precondition : preconditions) {
    if (precondition instanceof ScanningRecipe && isScanningRequired(precondition)) {
        acc.recipeToAccumulator.put(precondition, ((ScanningRecipe<?>) precondition).getInitialValue(ctx));
    }
}

When orVisitors() recurses into the nested ScanningRecipes in the wrapper recipe's recipeList, it tries to look them up:

conditions.add(scanning.getVisitor(accumulator.recipeToAccumulator.get(scanning)));

But since they were never registered, get(scanning) returns null.

Suggested Fix

getInitialValue() and getScanner() should recursively register and scan ScanningRecipes that are nested inside precondition recipes' recipeLists.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions