From 5334208241dd889032b324059f6f030617b6ce04 Mon Sep 17 00:00:00 2001 From: Rahul Krishna Date: Mon, 7 Sep 2026 22:37:46 -0400 Subject: [PATCH] docs: the PyPI install needs a real JDK from -a 2 onwards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The quick-install block said "no system Java needed" and then demonstrated `-a 2` — the first level that cannot work without one. `jdk4py` ships a JRE: `java`, no `javac`. From level 2 the analyzer shells out to the target project's Maven/Gradle wrapper to resolve dependencies and compile it, because WALA reads compiled classes rather than source, and that subprocess does its own JAVA_HOME discovery. The failure is quiet, which is what makes the wrong claim expensive: the run still exits 0, warns on stderr, and hands back declared call edges and the syntactic DDG with the RTA overlay and the L4 semantic DDG missing. A caller reading the exit code sees success and a thinner graph. Changes the example to `-a 1`, states the JRE/JDK split and what silently drops without it, and says `--emit neo4j` needs a JDK too since it always projects at full depth regardless of `-a`. The same correction goes into the wheel's own docstring, which made the claim in the package users actually install. Adds two FAQ entries for the adjacent surprise: `--no-build` does not suppress dependency resolution, so Maven still runs and writes into `/target/_library_dependencies/`, and `No application classes found` under `--no-build` is the flag being taken at its word rather than a bug. Docs only; no behaviour change. --- README.md | 53 ++++++++++++++++++- .../python/src/codeanalyzer_java/__init__.py | 20 ++++--- 2 files changed, 65 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 07668c51..cc9905dd 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,39 @@ and emits them either as the canonical `analysis.json`, or as a **Neo4j property ## Quick install -From PyPI, with a bundled JVM (no system Java needed). Installs a `canjv` launcher: +From PyPI, with a bundled JVM. Installs a `canjv` launcher: ```sh pip install codeanalyzer-java -canjv -i /path/to/project -a 2 -o ./out +canjv -i /path/to/project -a 1 -o ./out ``` +> [!IMPORTANT] +> **The bundled JVM is a JRE, and it is only enough for `-a 1`.** `pip install` pulls +> [`jdk4py`](https://pypi.org/project/jdk4py/), whose runtime has `java` but **no `javac`**. +> +> **`-a 2` and above need a real JDK on `JAVA_HOME`.** From level 2 the analyzer shells out to +> your project's Maven or Gradle wrapper to resolve dependencies and compile the application — +> WALA reads the *compiled classes*, not the source — so a JRE cannot get you a call graph: +> +> ```sh +> export JAVA_HOME=/path/to/a/real/jdk # Java 11+, must contain bin/javac +> canjv -i /path/to/project -a 2 -o ./out +> ``` +> +> **Without it the analyzer still exits 0.** It degrades and says so on stderr, but a caller +> reading only the exit code sees success: +> +> ``` +> [WARN] RTA call graph unavailable (RuntimeException: No application classes found.); emitting declared edges only +> [WARN] L4 semantic ddg unavailable (WALA build failed); emitting the derived SDG vertices and param edges only +> ``` +> +> You get declared call edges and the syntactic DDG; you do not get the RTA overlay or the +> alias-aware `prov: ["points-to"]` edges. Check for those warnings, not just the exit status. +> +> `--emit neo4j` always projects at full depth regardless of `-a`, so it needs a JDK too. + Or grab the latest release jar and a `codeanalyzer` launcher (requires a Java 11+ runtime): ```sh @@ -290,6 +316,29 @@ RUN_CONTAINER_TESTS=1 ./gradlew test The problem should be resolved. +2. I passed `--no-build`, but Maven still ran and wrote jars into my project. + + Expected, and the flag's description undersells it. `--no-build` suppresses the *application* + build that WALA needs — it does not suppress **dependency resolution**, which runs at every + level so that third-party types resolve to qualified names instead of degrading to bare + spellings. That step invokes your project's wrapper: + + ```sh + mvnw --no-transfer-progress -f dependency:copy-dependencies \ + -DoutputDirectory=/target/_library_dependencies -Doverwrite=true --fail-never + ``` + + So it writes into `/target/_library_dependencies/` even under `--no-build`, and + prints `BUILD SUCCESS`. It compiles nothing. + +3. With `--no-build` I get `No application classes found` and no call graph. + + `--no-build` means "I have already built this application" — the analyzer takes you at your + word and skips the compile. WALA then finds no classes under `target/classes`, because + dependency resolution (above) does not produce any. Either build the project first, or drop + `--no-build` and give the analyzer a real JDK (see the note in [Quick install](#quick-install) + — the bundled `jdk4py` runtime has no `javac`). + ## LICENSE ```LICENSE diff --git a/packaging/python/src/codeanalyzer_java/__init__.py b/packaging/python/src/codeanalyzer_java/__init__.py index 38018038..65375429 100644 --- a/packaging/python/src/codeanalyzer_java/__init__.py +++ b/packaging/python/src/codeanalyzer_java/__init__.py @@ -1,12 +1,20 @@ """Prebuilt ``codeanalyzer-java`` backend for CLDK, with a bundled JVM. This package carries the self-contained analyzer JAR and depends on ``jdk4py`` for a -Temurin runtime, so ``pip install codeanalyzer-java`` needs no system Java. CLDK's Python -SDK depends on this package and calls :func:`command` to run the analyzer, exactly as it -imports ``codeanalyzer-python`` and ``codeanalyzer-typescript`` for the other backends. - -The analyzer reads its Java standard-library scope from the JVM it runs on (``jrt:/``), -so no ``JAVA_HOME`` and no ``jmods/`` are required. +Temurin runtime. CLDK's Python SDK depends on this package and calls :func:`command` to run +the analyzer, exactly as it imports ``codeanalyzer-python`` and ``codeanalyzer-typescript`` +for the other backends. + +The analyzer reads its Java standard-library scope from the JVM it runs on (``jrt:/``), so +**level 1 needs no ``JAVA_HOME`` and no ``jmods/``**. + +Levels 2 and above do. ``jdk4py`` ships a JRE — ``java`` but no ``javac`` — and from level 2 +the analyzer shells out to the target project's Maven/Gradle wrapper to resolve dependencies +and compile it, because WALA reads compiled classes rather than source. That subprocess does +its own ``JAVA_HOME`` discovery and needs a real JDK. Without one the run still exits 0 and +warns: the RTA call-graph overlay and the L4 semantic DDG are dropped, leaving declared edges +and the syntactic DDG. Do not describe this package as "no system Java needed" — that is true +only of ``-a 1``. """ from __future__ import annotations