Skip to content

RPC peers: emit empty arrays for descriptor collections, never omit them#7546

Merged
jkschneider merged 4 commits intomainfrom
normalize-rpc-recipe-descriptor
May 1, 2026
Merged

RPC peers: emit empty arrays for descriptor collections, never omit them#7546
jkschneider merged 4 commits intomainfrom
normalize-rpc-recipe-descriptor

Conversation

@jkschneider
Copy link
Copy Markdown
Member

What

Recipe.getDescriptor() on the Java side always returns a descriptor whose collection-valued getters (tags, options, preconditions, recipeList, dataTables, maintainers, contributors, examples) are non-null. Callers across the ecosystem rely on that and iterate the getters directly:

for (RecipeDescriptor precondition : descriptor.getPreconditions()) { ... }
descriptor.getPreconditions().stream().map(...).toList();

When a RecipeDescriptor arrives from a polyglot RPC peer, the JSON that peer emits can omit empty collections — Jackson on the Java side then leaves the corresponding fields null, and downstream code blows up:

Cannot invoke "java.util.List.iterator()" because the return value of
"org.openrewrite.config.RecipeDescriptor.getPreconditions()" is null

How

Fix at the source — each polyglot peer always emits every collection key, even when empty:

Python (rewrite-python/rewrite/src/rewrite/rpc/server.py)
_recipe_descriptor_to_dict now emits preconditions, maintainers, contributors, examples as empty lists. The Python RecipeDescriptor dataclass doesn't model these fields yet, so they're hardcoded [].

TypeScript (rewrite-javascript/rewrite/src/recipe.ts)
Extended the RecipeDescriptor interface with the four missing fields and updated Recipe.descriptor() to populate them. Updates the existing recipe.test.ts snapshot.

C#no change. RecipeDescriptorDto already declares each list/set property with an = [] initializer and Newtonsoft serializes empty collections as [], so the JSON it produces already matches the contract.

Test plan

  • rewrite-python/rewrite/tests/rpc/test_server.py::test_recipe_descriptor_to_dict_emits_all_collection_keys — locks the contract on the Python side.
  • rewrite-javascript/rewrite/test/recipe.test.ts — updated snapshot now asserts the four empty-collection keys.
  • :rewrite-javascript:compileJava :rewrite-csharp:compileJava :rewrite-python:compileJava pass.

`Recipe.getDescriptor()` on the Java side always returns a descriptor
whose collection-valued getters (`tags`, `options`, `preconditions`,
`recipeList`, `dataTables`, `maintainers`, `contributors`, `examples`)
are non-null. Callers across the ecosystem rely on that and iterate the
getters without null checks.

When a `RecipeDescriptor` is produced by a polyglot RPC peer, however,
the JSON those peers emit can omit empty collections — Jackson then
deserializes the corresponding fields as `null`, breaking every
downstream caller (e.g. `descriptor.getPreconditions().iterator()`).

Fix the Python and TypeScript peers to always emit every collection key,
even when empty. The C# peer was already correct: `RecipeDescriptorDto`
declares each list/set property with an `= []` initializer and
Newtonsoft serializes empty collections as `[]`, so the JSON it produces
already matches the contract.

Python (`rewrite/src/rewrite/rpc/server.py`):
  Add `preconditions`, `maintainers`, `contributors`, `examples` as
  empty lists in `_recipe_descriptor_to_dict`. (The Python `RecipeDescriptor`
  dataclass doesn't model these fields yet, so they're hardcoded.)

TypeScript (`rewrite/src/recipe.ts`):
  Extend the `RecipeDescriptor` interface with the four missing fields
  and have `Recipe.descriptor()` populate them. Updates the existing
  `recipe.test.ts` snapshot.
@github-project-automation github-project-automation Bot moved this from In Progress to Ready to Review in OpenRewrite May 1, 2026
@jkschneider jkschneider merged commit 72154fd into main May 1, 2026
1 check passed
@jkschneider jkschneider deleted the normalize-rpc-recipe-descriptor branch May 1, 2026 21:25
@github-project-automation github-project-automation Bot moved this from Ready to Review to Done in OpenRewrite May 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants