Skip to content

Repository-artifact layer for java — artifact / dependency / config_key nodes #197

Description

@georgesafta

Summary

Implement the repository-artifact layer in codeanalyzer-java — the producer-side evidence a cross-service / whole-application analysis needs but no analyzer emits today. Contract of record: docs/design/specs/repository-artifact-layer.md (committed in codellm-devkit/.github), tracked by epic codellm-devkit/.github#45.

This is the first PR for the Java train, the application-anchored slice, into the canonical schema v2 model (--schema v2, package com.ibm.cldk.schema.*):

  • artifact nodes (JArtifact) — a non-source file inventory with raw-text capture
  • dependency nodes (JDependency) — normalized deps parsed from pom.xml / Gradle coordinates (net-new — today deps are only downloaded as jars, never modeled)
  • config_key nodes (JConfigKey) — normalized keys from structured config files

All three anchor on the application node (stable, no body-node risk). The shared vocabulary (scope enum, artifact_kind enum, @artifact/ id grammar) is coined verbatim per the spec's parity clause, identical to the python/typescript trains.

Two Java-specific divergences (found by inspecting the code, not just the spec)

  1. Neo4j is now available for this layer — the premise this issue was written on is obsolete. When this issue was filed, analyzeV2() rejected --emit neo4j and the Neo4j projector ran entirely off the legacy v1 IR, so a v2 addition could reach analysis.json but never the graph. That is no longer true: PR feat(l4): interprocedural SDG — param_in/param_out, semantic DDG, summary edges, graph 2.1.0 #203 shipped the canonical v2 graph projection (V2GraphProjector, V2SchemaCatalog, graph contract 2.0.0, since bumped to 2.1.0 by the L4 overlay), removed the guard, and made --schema v2 the default. "Roadmap candidate 9", the v1→v2 Neo4j migration this issue deferred to, is done. Whoever picks this up should decide afresh whether to project the artifact layer into the graph in the same PR — the epic's J_USES_CONFIG-only deferral and this issue's broader whole-layer deferral were both consequences of a blocker that no longer exists. Note that V2SchemaCatalog already reserves un-prefixed Artifact and Package labels as cross-language merge targets, declared but not emitted, so the graph vocabulary is partly staked out already.

  2. Artifact discovery needs a new repo-wide walk. The v2 walk (L1Extractor.extractAll) is source-root scoped — it only enumerates .java files under JavaParser source roots and never sees a repo-root pom.xml / application.yml / Dockerfile. The inventory needs its own Files.walk of the project root, homed alongside utils/ProjectDirectoryScanner.java, not hooked into L1Extractor.

Scope

In (this PR):

  • JArtifact / JDependency / JConfigKey Lombok @Data POJOs + JApplication.artifacts map (com.ibm.cldk.schema.*)
  • CanId.artifactId / dependencyId / configKeyId helpers (@artifact/ marker keeps them out of the signatureOf id space)
  • Repo-wide inventory + classification walk (new com.ibm.cldk.artifacts package); other catch-all — a file is never dropped
  • Raw-text capture (utf-8 / binary / over-cap truncation), --artifact-text / --no-artifact-text (default on) + --artifact-text-max-bytes (default 262144); parsing reads a decode buffer independent of capture so the flag drops only the raw-text payload
  • Dependency parse: pom.xml (JDK DOM, on the classpath) with groupId:artifactId identity, version_spec, <scope>/<optional> → shared scope; build.gradle/.kts shallow regex reader; gradle.lockfileresolved_version; ecosystem="maven"
  • Config parse (overlay — failure never drops the artifact): .properties (java.util.Properties), application.yml/.yaml (needs a new YAML dep — see open decision), Jakarta EE .xml descriptors; dotted keys, value, references[] (${VAR}env:VAR)
  • Extend the local conformance schema src/test/resources/schema/analysis.v2.schema.json ($defs + enum constraints + application.artifacts) — the L1 conformance gate validates against it with additionalProperties:false
  • Decision-log entry

Out (follow-ups / other trains):

  • config_use / J_USES_CONFIG edge (follow-up PR; Java is well-positioned — JBodyNode already carries receiverExpr/argumentExpr at L1, so System.getenv reads are visible without a PyCallArgument.value-style extension; @Value/@ConfigurationProperties reads anchor on JDecorator)
  • All Neo4j projection of the artifact layer — rides candidate 9obsolete: candidate 9 landed in PR feat(l4): interprocedural SDG — param_in/param_out, semantic DDG, summary edges, graph 2.1.0 #203. Re-scope when picked up.
  • python / typescript analyzers; python-sdk mirror

Open decisions (resolve before/at review)

  1. YAML dependency: add SnakeYAML to build.gradle now (enables application.yml config-key extraction; needs a reflect-config.json entry for native-image), or ship .yml inventoried-but-unparsed this PR. Recommendation: add now — application.yml is the dominant Spring Boot config surface.
  2. Gradle depth: shallow regex reader misses version-catalog (libs.*) / dynamic deps. Accept as a documented, logged limitation for PR 1 (Maven pom.xml is the complete path), or scope Gradle out of PR 1.

Acceptance

  • application.artifacts emitted as a contained named map of artifact nodes with stable can://…/@artifact/… ids; unrecognized files artifact_kind:"other", never dropped
  • pom.xml (and best-effort Gradle) parsed into dependency nodes with groupId:artifactId identity and correct scope; gradle.lockfile pins resolved_version
  • Structured config exposes config_key nodes with dotted keys and recognized references[]
  • Text-decodable artifacts carry verbatim text + text_encoding/text_truncated; binary/over-cap remain inventoried with path + content_hash
  • --no-artifact-text drops only the text payload; inventory + deps + config overlay unchanged
  • artifacts section byte-identical across -a 1|2|3 (ungated / all-levels)
  • L1ConformanceGateTest green (local v2 schema extended); no null leaves
  • Neo4j untouched: Neo4jSchemaConformanceTest green, schema_version 1.0.0 unchanged, --schema v2 --emit neo4j still errors, no artifact labels in the graph catalogobsolete. The v1 catalog is no longer what --emit schema emits (it now always emits the v2 catalog, currently 2.1.0), and --schema v2 --emit neo4j is the supported default path. Replace with whatever the re-scoping decides.
  • Existing v2 symbol_table/call_graph output byte-identical

Part of epic codellm-devkit/.github#45. Sibling: codeanalyzer-python#152.


Update (2026-08-29): the Neo4j premise above was invalidated by PR #203 (v2 graph projection) and PR #205 (@entry defines the formals). Struck text is left visible rather than deleted so the original reasoning stays auditable. The rest of the scope — application-anchored JArtifact/JDependency/JConfigKey, pom.xml/Gradle coordinate parsing, config-key extraction, and the repo-wide walk L1Extractor cannot do — is unaffected and still accurate.

Metadata

Metadata

Assignees

Labels

javaPull requests that update java codekind/featureFeature

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions