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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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