From 8090f63871b2c0c4f01c4bc281402f5be47a4b79 Mon Sep 17 00:00:00 2001 From: Shannon Pamperl Date: Sun, 28 Jun 2026 21:27:42 -0500 Subject: [PATCH] rpc: remove the by-name fallback in RpcRecipe.getRecipeList() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every RPC server (C#, npm, Python, Go) now returns the whole prepared tree (recipeList), so the host always builds the child tree locally from the prepared child responses. The by-name fallback — which re-prepared each child by name for servers that returned only the root — is no longer reachable, so it is deleted. A missing child tree now fails loudly via requireNonNull rather than silently re-preparing by name. The now-unused OptionDescriptor and Collectors.toMap imports are dropped. --- .../java/org/openrewrite/rpc/RpcRecipe.java | 30 +++++++------------ 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/rewrite-core/src/main/java/org/openrewrite/rpc/RpcRecipe.java b/rewrite-core/src/main/java/org/openrewrite/rpc/RpcRecipe.java index ec48c2919b..760cf5af02 100644 --- a/rewrite-core/src/main/java/org/openrewrite/rpc/RpcRecipe.java +++ b/rewrite-core/src/main/java/org/openrewrite/rpc/RpcRecipe.java @@ -19,7 +19,6 @@ import lombok.RequiredArgsConstructor; import org.jspecify.annotations.Nullable; import org.openrewrite.*; -import org.openrewrite.config.OptionDescriptor; import org.openrewrite.config.RecipeDescriptor; import org.openrewrite.config.RecipeExample; import org.openrewrite.rpc.request.PrepareRecipeResponse; @@ -30,8 +29,8 @@ import java.util.Set; import static java.util.Collections.emptyList; +import static java.util.Objects.requireNonNull; import static java.util.stream.Collectors.toList; -import static java.util.stream.Collectors.toMap; @RequiredArgsConstructor @@ -65,8 +64,8 @@ public class RpcRecipe extends ScanningRecipe { /** * The prepared child recipe responses returned by the server as part of the whole-tree - * prepare response. When non-null and non-empty, {@link #getRecipeList()} builds children - * locally from these nodes instead of making individual PrepareRecipe RPC calls. + * prepare response. {@link #getRecipeList()} builds the children locally from these. Every + * RPC server populates this (an empty list for a leaf), so it is effectively required. */ private final @Nullable List childResponses; @@ -134,22 +133,13 @@ public TreeVisitor getVisitor(Integer acc) { @Override public synchronized List getRecipeList() { if (recipeList == null) { - if (childResponses != null) { - // Whole-tree: children were prepared in the parent's response; build locally, no RPC. - recipeList = childResponses.stream() - .map(rpc::recipeFromPrepareResponse) - .collect(toList()); - } else { - // Fallback: peers whose servers don't yet return a prepared child tree - // (Python/JS/Go until updated). This is the pre-existing by-name path, unchanged. - // TODO(remove-fallback): delete this branch once every RPC server populates - // `recipeList`. The C# server (this change) always takes the branch above. - recipeList = descriptor.getRecipeList().stream() - .map(r -> rpc.prepareRecipe(r.getName(), r.getOptions().stream() - .filter(opt -> opt.getValue() != null) - .collect(toMap(OptionDescriptor::getName, OptionDescriptor::getValue)))) - .collect(toList()); - } + // Every RPC server returns the whole prepared tree, so build the children locally from + // the child responses — no individual PrepareRecipe RPC per child. + recipeList = requireNonNull(childResponses, + "RPC server returned a recipe without a prepared child tree (recipeList)") + .stream() + .map(rpc::recipeFromPrepareResponse) + .collect(toList()); } return recipeList; }