Skip to content

Commit 9fc85c4

Browse files
committed
feat(neo4j): namespace labels, lossless projection, and a driver-free Bolt seam (#154)
Brings the Java Neo4j backend to parity with the Python/TypeScript siblings and makes it a lossless projection of the IR. Namespacing (so a Java graph can share a Neo4j DB with Py*/TS* graphs): - all node labels J-prefixed, all relationship types J_-prefixed, constraint/index names j_-prefixed. - provenance property renamed _unit -> _module (matches the siblings). - --emit schema now writes schema.neo4j.json (matches the checked-in contract); release asset + README updated. - NEO4J_URI/USERNAME/PASSWORD/DATABASE env-var fallback (flag > env > default). Lossless projection (every Lombok entity field is represented): - new first-class nodes :JInitializationBlock, :JCrudOperation, :JCrudQuery, :JComment, with J_HAS_INIT_BLOCK / J_HAS_CRUD_OPERATION / J_HAS_CRUD_QUERY / J_HAS_COMMENT and J_HAS_CALLSITE/J_DECLARES_VAR extended to init blocks. - added scalar props: is_modified, file_path (callable), variable_initializers_json, default_value, argument_expr, is_unspecified, start/end_column on params & vars, docstrings, and source_kind/destination_kind on J_CALLS. - CypherWriter.DESCENDANTS extended so the scoped wipe / orphan prune reach the new containment edges. Packaging seam (lets the GraalVM native image prune the driver): - BoltConfig + BoltSink extracted as driver-free core types; BoltWriter is the only class importing org.neo4j.driver.* and is loaded reflectively by Neo4jEmitter, so the fat jar bundles the driver (live Bolt push works) while native-image, which never statically references it, falls back to writing graph.cypher. Schema contract regenerated (16 node labels, 20 relationship types, 15 constraints); conformance test updated; neo4j-schema.drawio refreshed to the J-prefixed schema with the call graph (J_CALLS / J_RESOLVES_TO) drawn explicitly.
1 parent 47ca72f commit 9fc85c4

18 files changed

Lines changed: 816 additions & 365 deletions

.github/workflows/release.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ jobs:
5252
mkdir -p release-assets
5353
cp build/libs/codeanalyzer-${{ steps.ver.outputs.version }}.jar release-assets/codeanalyzer.jar
5454
cp build/libs/codeanalyzer-${{ steps.ver.outputs.version }}.jar "release-assets/codeanalyzer-${{ steps.ver.outputs.version }}.jar"
55-
java -jar build/libs/codeanalyzer-${{ steps.ver.outputs.version }}.jar --emit schema > release-assets/schema.json
55+
java -jar build/libs/codeanalyzer-${{ steps.ver.outputs.version }}.jar --emit schema > release-assets/schema.neo4j.json
5656
cp packaging/install/codeanalyzer-installer.sh release-assets/codeanalyzer-installer.sh
5757
ls -lh release-assets
5858
@@ -88,7 +88,7 @@ jobs:
8888
echo "| --- | --- |"
8989
echo "| \`codeanalyzer.jar\` | Self-contained analyzer (run with \`java -jar\`) |"
9090
echo "| \`codeanalyzer-installer.sh\` | Installer that fetches the jar and adds a \`codeanalyzer\` launcher |"
91-
echo "| \`schema.json\` | Neo4j graph schema contract (node labels, relationships, DDL) |"
91+
echo "| \`schema.neo4j.json\` | Neo4j graph schema contract (node labels, relationships, DDL) |"
9292
echo
9393
echo "---"
9494
echo
@@ -101,7 +101,7 @@ jobs:
101101
files: |
102102
release-assets/codeanalyzer.jar
103103
release-assets/codeanalyzer-${{ steps.ver.outputs.version }}.jar
104-
release-assets/schema.json
104+
release-assets/schema.neo4j.json
105105
release-assets/codeanalyzer-installer.sh
106106
body_path: release-notes.md
107107
env:

README.md

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -105,18 +105,20 @@ Analyze java application.
105105
-b, --build-cmd=<build> Custom build command. Defaults to auto build.
106106
--no-build Do not build your application (use if already built).
107107
-a, --analysis-level=<n> Level of analysis: 1 (symbol table) or 2 (call graph).
108-
Default: 1. Level 2 adds CALLS edges to the graph.
108+
Default: 1. Level 2 adds J_CALLS edges to the graph.
109109
-t, --target-files=<f>... Restrict analysis to specific files (incremental).
110110
--emit=<emit> Output target: json (analysis.json, default) |
111111
neo4j (graph.cypher or live Bolt push) |
112-
schema (the Neo4j schema.json contract).
113-
--app-name=<name> Logical application name for the graph :Application
112+
schema (the Neo4j schema.neo4j.json contract).
113+
--app-name=<name> Logical application name for the graph :JApplication
114114
anchor (default: input dir name).
115115
--neo4j-uri=<uri> Push the graph to a live Neo4j over Bolt (incremental);
116-
omit to write graph.cypher.
117-
--neo4j-user=<user> Neo4j username (default: neo4j).
118-
--neo4j-password=<pw> Neo4j password (default: neo4j).
119-
--neo4j-database=<db> Neo4j database name (default: server default).
116+
omit to write graph.cypher. Falls back to the
117+
NEO4J_URI environment variable.
118+
--neo4j-user=<user> Neo4j username (env: NEO4J_USERNAME, default: neo4j).
119+
--neo4j-password=<pw> Neo4j password (env: NEO4J_PASSWORD, default: neo4j).
120+
--neo4j-database=<db> Neo4j database name (env: NEO4J_DATABASE, default:
121+
server default).
120122
-v, --verbose Print logs to console.
121123
-h, --help Show this help message and exit.
122124
-V, --version Print version information and exit.
@@ -188,14 +190,20 @@ This will produce print the SDG on the console. Explore other flags to save the
188190
## 4. Neo4j graph output
189191

190192
`codeanalyzer` can project the analysis IR into a [Neo4j](https://neo4j.com/) property graph instead
191-
of `analysis.json`. The graph models the same information — compilation units, types, callables,
192-
fields, parameters, call sites, variables, enum constants, record components, annotations, packages —
193-
as first-class nodes and relationships, and (at `-a 2`) adds `CALLS` edges from the call graph.
193+
of `analysis.json`. The graph is a **lossless** projection of the IR: compilation units, types,
194+
callables, fields, parameters, call sites, variables, enum constants, record components,
195+
initialization blocks, CRUD operations/queries, comments, annotations and packages are all
196+
first-class nodes and relationships, and (at `-a 2`) it adds `J_CALLS` edges from the call graph.
197+
Every field of the Lombok entity model is represented (scalars as node properties — maps such as a
198+
field's per-variable initializers are kept as a `*_json` property since Neo4j has no map type;
199+
comments are `:JComment` nodes in addition to the convenience `docstring` property).
194200

195201
The full contract (node labels, their keys and typed properties, relationship types and endpoints,
196202
plus the constraint/index DDL) lives in [`schema.neo4j.json`](./schema.neo4j.json) and is visualized
197-
in [`neo4j-schema.drawio`](./neo4j-schema.drawio). `SCHEMA_VERSION` is stamped onto the
198-
`:Application` node of every emitted graph.
203+
in [`neo4j-schema.drawio`](./neo4j-schema.drawio). All node labels are `J`-prefixed and relationship
204+
types `J_`-prefixed (e.g. `:JType`, `:JCallable`, `J_CALLS`) so a Java graph can share a Neo4j
205+
database with the Python (`Py*`/`PY_*`) and TypeScript (`TS*`/`TS_*`) backends without colliding.
206+
`SCHEMA_VERSION` is stamped onto the `:JApplication` node of every emitted graph.
199207

200208
### 4.1. Cypher snapshot (no database required)
201209

@@ -223,7 +231,7 @@ compilation unit's `content_hash`, replaces just the changed units' subgraphs (i
223231
### 4.3. Schema contract
224232

225233
```sh
226-
codeanalyzer --emit schema -o ./out # → ./out/schema.json (no project analysis needed)
234+
codeanalyzer --emit schema -o ./out # → ./out/schema.neo4j.json (no project analysis needed)
227235
codeanalyzer --emit schema # → prints the contract to stdout
228236
```
229237

build.gradle

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,10 @@ dependencies {
125125
implementation('com.github.javaparser:javaparser-core:3.26.3')
126126

127127
// Neo4j Bolt driver for `--emit neo4j --neo4j-uri ...` (live incremental graph push).
128-
// 4.4.x retains Java 8/11 compatibility for the GraalVM native-image build.
128+
// Bundled into the fat jar so `java -jar` supports live push out of the box. It is reached ONLY
129+
// reflectively, via the BoltSink seam (see Neo4jEmitter#loadBoltSink), so the GraalVM native image
130+
// prunes BoltWriter and never compiles the driver + Netty into the binary — the native build stays
131+
// small and Netty-metadata-free, and `--neo4j-uri` there falls back to a graph.cypher snapshot.
129132
implementation('org.neo4j.driver:neo4j-java-driver:4.4.12')
130133

131134
// TestContainers

0 commit comments

Comments
 (0)