Skip to content

[UNOMI-963] Enrich OpenAPI from Javadoc via openapi-enrich 0.1.0 - #826

Merged
sergehuber merged 3 commits into
masterfrom
UNOMI-963-openapi-javadoc-enrichment
Jul 15, 2026
Merged

[UNOMI-963] Enrich OpenAPI from Javadoc via openapi-enrich 0.1.0#826
sergehuber merged 3 commits into
masterfrom
UNOMI-963-openapi-javadoc-enrichment

Conversation

@sergehuber

@sergehuber sergehuber commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Plain-language summary

Unomi already exposes OpenAPI at /cxs/openapi.json (and Swagger UI), but what CXF generated from JAX-RS annotations alone was a thin skeleton: generic "default response" texts, few usable examples, and schemas that often showed Java internals instead of the JSON clients actually send (for example Condition showing conditionTypeId / nested type objects instead of the wire type + parameterValues shape).

This PR closes that gap by treating Javadoc as the source of truth for OpenAPI. At build time we generate enrichment packs; at runtime CXF merges them into the OpenAPI document. Developers get a Swagger UI and machine-readable contract they can trust when integrating against Unomi—without changing REST behavior.

Toolkit: openapi-enrich (dev.inoyu.openapi:*:0.1.0) — developed for these Unomi needs and open-sourced by Inoyu (Apache-2.0). See the excellent README; published on Maven Central (not vendored in the ASF tree).


Toolkit (Inoyu)

openapi-enrich (dev.inoyu.openapi:*:0.1.0) was built for this Unomi requirement: enrich a CXF + OSGi live OpenAPI from Javadoc, without mass Swagger @Operation / @Schema annotations that would duplicate and drift from existing docs.

Inoyu (inoyu.dev) open-sourced the toolkit under Apache-2.0 on Maven Central. Unomi consumes the published JARs/plugin like any other dependency—it does not vendor the toolkit sources inside the ASF tree.

Gold coverage (definition + scope of work)

What “gold” means

We score each HTTP operation in live /cxs/openapi.json as:

Tier Criteria
Gold Has a named success/error status (e.g. 200 / 204 / 400) with a real description (not empty / "default response"), and the operation includes at least one response example
Partial Has statuses or an example, but not both
Weak Neither usable statuses nor examples

That is the bar where Swagger UI and client codegen stop being guesswork: callers see what can happen and what a valid body looks like.

Result on this branch

  • 179 / 179 gold on the product surface (excluding GET /api-docs/{resource}, skipped on purpose — Swagger helper, not a product API).
  • 0 partial / 0 weak after the final example pass.
  • Schemas checked: Condition/Action wire type + parameterValues; Event profileId / sessionId (no leaked nested/transient junk).

Work that got us there

This was not a thin status-only pass. It covered the full JAX-RS-ish inventory (~180 ops) plus schema correctness:

  1. Toolkit (Inoyu, open-sourced)openapi-enrich 0.1.0: Javadoc/@api.* scan, inheritance, wire aliases, transient suppress, overloads, path-regex normalize, servlet merge; released to Maven Central so CI resolves a release.
  2. Exemplars — Tenant + Health to prove pipeline + tag grammar.
  3. Hot paths — context, eventcollector, profiles (36 ops), rules, segments, privacy — statuses, examples, shared models.
  4. Mid + thin REST + extensions — definitions/campaigns/scoring/goals/events, tasks/scopes/query/cluster/client/patch/userList/test, plus json-schema, lists, geonames, router import/export, groovy, SFDC, healthcheck.
  5. Gold completion pass — every remaining partial (void DELETE/OPTIONS, thin GETs, geonames {items:.*} / query metrics paths) got context-specific @api.example values (entity illustrations, context.js JS snippet, export CSV, booleans/maps where appropriate)—examples are domain-relevant, not filler.

Effort (planning bands from the work tracker): toolkit MVP on the order of ~4–8 person-days; Unomi hot-path content ~4–7 person-days; full Tenant-quality inventory across mid/thin/extensions was an additional multi-day content push, plus the final live gold example sweep.

Why this matters for developers

Pain today After this PR
Swagger shows empty / “default response” Real HTTP status meanings (200 / 204 / 400 / 403 / 404 …) with short prose
“Try it out” bodies are guesswork Realistic examples (profiles, rules with setPropertyAction, context.js payload, CSV export, …)
Schemas disagree with curl/Postman payloads Schemas follow wire JSON (aliases, suppressed @XmlTransient leftovers)
Condition/Action docs teach the wrong field names Documented as type + parameterValues — the shape clients must POST
Docs drift from code Enrichment stays in the same Javadoc as the endpoint; regenerate on build
Client SDK / codegen from OpenAPI is weak Stronger input for OpenAPI Generator, Insomnia, Postman import, etc.

Who benefits: integration engineers building against /cxs/*, contributors validating APIs in Swagger, authors of migration/tools/tests that rely on the published contract, and anyone generating typed clients from openapi.json.


Approach (how it works)

  1. Write normal Javadoc on endpoints/models, plus optional tags:
    • @api.status CODE [array] SchemaFqcn|empty Description
    • @api.example … (response / empty-body illustration)
  2. openapi-enrich-maven-plugin scans sources → pack under META-INF/openapi-enrich/.
  3. EnrichingOpenApiCustomizer (embedded in unomi-rest) merges packs into CXF’s OpenAPI at runtime (core + OSGi extension packs).

Unomi only wires the toolkit and supplies content. Correctness features that made the live doc accurate (aliases, transient suppression, inherited JAX-RS methods, path-regex normalize, subclass override docs) live in the Central library.

Not in scope for enrichment: GET /api-docs/{resource} (Swagger helper, not a product API).


What changed in this PR

  • Reactor pin: ${openapi.enrich.version}0.1.0 (Maven Central — required for CI).
  • Module wiring: Mojo on rest + extension REST modules; embed enricher + model; RestServer registers the customizer.
  • Content: Tenant-quality @api.status / @api.example + schema field docs across hot paths (context, eventcollector, profiles, rules, segments, privacy), mid/thin REST, and extensions (geonames, lists, json-schema, router import/export, groovy, SFDC, healthcheck).
  • No intentional runtime API behavior change — OpenAPI/Swagger documentation only.

Reviewer guide

Prefer reading first Why
Root pom.xml + rest/pom.xml Central 0.1.0 pin, Mojo, Embed-Dependency
rest/.../RestServer.java Customizer wiring
TenantEndpoint.java, ContextJsonEndpoint.java, RulesServiceEndPoint.java Exemplars for the tag grammar
e.g. extensions/geonames/.../GeonamesEndPoint.java Same pattern outside rest

Most other files are mechanical Javadoc following those exemplars—sample a few prefixes rather than reading every line.

Before / after (conceptual)

Before (typical CXF stock):
200"default response", Condition properties include transient/internal names, little or no request/response example.

After (enriched):
Documented statuses (e.g. rule save 204 / invalid body 400), Condition/Action examples using "type":"eventTypeCondition" / "type":"setPropertyAction", field examples on Profile/Event/Query/PartialList, workable Swagger “try it out”.

Live check used for this branch: 179/179 operations gold excluding /api-docs (see Gold coverage above for the definition and work scope).

Test plan

  • Deployed build: /cxs/openapi.json gold excl. /api-docs; Condition/Action wire keys verified
  • Artifacts resolve from Central (cxf-openapi-enricher / openapi-enrich-model / maven-plugin 0.1.0)
  • CI Maven build on this branch
  • Spot-check Swagger UI: /cxs/context.json, /cxs/profiles, /cxs/rules, /cxs/geonames/...
curl -u karaf:karaf http://localhost:8181/cxs/openapi.json \
  | jq '.components.schemas.Condition, .paths["/rules"].post.responses'

curl -sS -o /dev/null -w "%{http_code}\n" \
  https://repo1.maven.org/maven2/dev/inoyu/openapi/cxf-openapi-enricher/0.1.0/cxf-openapi-enricher-0.1.0.pom

References

Wire openapi-enrich into rest/extensions and add @api.status / @api.example
plus schema field docs so /cxs/openapi.json is Client/Swagger-ready (live gold
excl. /api-docs).
Replace 0.1.0-SNAPSHOT so CI can resolve the published toolkit.
@sergehuber

Copy link
Copy Markdown
Contributor Author

Note for reviewers: UNOMI-963’s JIRA summary still said “with Swagger annotations” historically. The implementation (and the ticket rewrite in flight) uses Javadoc + @api.status / @api.example via openapi-enrich 0.1.0not @Operation / @Schema Swagger annotations.

Pin the released Central artifacts and keep JAX-RS startup if enrichment pack loading fails.
@sergehuber
sergehuber merged commit d4aa562 into master Jul 15, 2026
8 of 9 checks passed
@sergehuber
sergehuber deleted the UNOMI-963-openapi-javadoc-enrichment branch July 15, 2026 11:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant