From f4d9f8759368904bc42d8ea5b297adb6c0c2873a Mon Sep 17 00:00:00 2001 From: Rahul Krishna Date: Fri, 11 Sep 2026 12:06:23 -0400 Subject: [PATCH] fix(artifacts): an unresolved receiver type is not a dispatch site, not a NullPointerException (#265) Set.of(...).contains(null) throws, and a call node's receiver_type is null whenever the receiver did not resolve, so 3.3.0-3.3.2 crashed every unbuilt project with a forward/include/sendRedirect call at every level. --- .../ibm/cldk/artifacts/ViewDispatches.java | 5 +++++ .../cldk/artifacts/ViewDispatchesTest.java | 20 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/main/java/com/ibm/cldk/artifacts/ViewDispatches.java b/src/main/java/com/ibm/cldk/artifacts/ViewDispatches.java index 5c129e30..b32711e2 100644 --- a/src/main/java/com/ibm/cldk/artifacts/ViewDispatches.java +++ b/src/main/java/com/ibm/cldk/artifacts/ViewDispatches.java @@ -166,6 +166,11 @@ private static Site siteOf(String appName, JCallable callable, String localId, J String method = node.getMethodName(); String via; String target; + // An unresolved receiver (an unbuilt project, a missing jar) is null, and Set.of(...) throws + // on contains(null): 3.3.0-3.3.2 crashed every such run at every level (#265). Not a site. + if (receiver == null) { + return null; + } if (node.isConstructorCall() && MODEL_AND_VIEW.equals(receiver)) { if (arg0 == null) { return null; // `new ModelAndView()` names no view; setViewName will diff --git a/src/test/java/com/ibm/cldk/artifacts/ViewDispatchesTest.java b/src/test/java/com/ibm/cldk/artifacts/ViewDispatchesTest.java index 0ee61406..456c5947 100644 --- a/src/test/java/com/ibm/cldk/artifacts/ViewDispatchesTest.java +++ b/src/test/java/com/ibm/cldk/artifacts/ViewDispatchesTest.java @@ -200,4 +200,24 @@ private static JViewDispatchUnresolved unresolved(String site) { + result.unresolved.stream().map(JViewDispatchUnresolved::getSite) .collect(Collectors.toList()))); } + + // ---- an unbuilt project (#265) --------------------------------------------------------------- + + @Test + void anUnresolvableReceiverIsNotADispatchAndDoesNotCrash(@TempDir Path unbuilt) throws Exception { + // No servlet stubs on this tree, so every receiver type here is unresolved. The pass must + // simply see no site, not throw: Set.of(...).contains(null) is the NPE 3.3.0-3.3.2 shipped. + ServletApiStubs.write(unbuilt, "src/main/java/demo/Front.java", + "package demo;\n" + + "import javax.servlet.http.*;\n" + + "public class Front extends HttpServlet {\n" + + " protected void doGet(HttpServletRequest req, HttpServletResponse res) {\n" + + " req.getRequestDispatcher(\"/x.jsp\").forward(req, res);\n" + + " res.sendRedirect(\"/y.jsp\");\n" + + " }\n}\n"); + ServletApiStubs.write(unbuilt, "src/main/webapp/x.jsp", "<%= 1 %>"); + Map mods = L1Extractor.extractAll(unbuilt, APP, null, new LinkedHashMap<>(), 1, 3, "ast"); + ViewDispatches.Result r = ViewDispatches.detect(APP, mods, ArtifactDiscovery.discover(unbuilt, APP, true, 262144)); + assertTrue(r.dispatches.isEmpty() && r.unresolved.isEmpty(), "unresolved receivers are not sites"); + } }