Skip to content

Collapse OAS customizer signatures onto a single JsonApi4j reference #164

Closed

Description

@MoonWorm

JsonApi4j now encapsulates everything an integration needs — after #162 it carries the root
JsonApi4jProperties, and after #163 a PluginRegistry that resolves a plugin's config by type. The
OAS customizers never caught up and still take their collaborators one by one:

new JsonApiOperationsCustomizer(
        rootPath, domainRegistry, operationsRegistry, oasProperties, validationProperties, pluginRegistry
);

Every one of those six is reachable from a single JsonApi4j — rootPath is
getProperties().rootPath(), validationProperties is getProperties().validation(),
oasProperties is getPluginRegistry().configOf(OasProperties.class). The cost is paid at every call
site: OasServlet pulls a JsonApi4j out of the servlet context and immediately destructures it back
into five fields, and the Spring sample app carries five adapter classes plus five multi-argument
@Bean methods — one of them taking five collaborators — purely to re-assemble what JsonApi4j
already holds. That sample is the integration recipe users copy.

PluginRegistry.configOf(Class) was added in #163 and has zero production callers. This is what it
was for.

Approach

  • OasCustomizer — a one-method interface (void customise(OpenAPI)); all five customizers already
    had exactly that method, so they just implement it.
  • OasDocument.generate(jsonApi4j) — builds the document in one call. OasDocument.customizers(...)
    exposes the ordered list for a host that applies them itself. The order is load-bearing: Common →
    ResponseSchema → RequestBodySchema → Operations → ErrorExamples.
  • Every customizer constructor takes a single JsonApi4j and derives what it needs once.
    ErrorExamplesCustomizer stays no-arg — it has no state.
  • Existing null-tolerance is preserved: configOf returns empty when no OAS plugin is registered,
    which is the situation callers previously expressed by passing null, and
    CommonOpenApiCustomizer still publishes tags from the registries in that case.
  • OasServlet drops five fields; it keeps jsonApi4j plus the oasProperties that gates its 404
    (that one comes from the servlet-context attribute the host initializer sets, possibly before
    JsonApi4j exists).
  • The sample app's five springdoc adapter classes are deleted: springdoc's OpenApiCustomizer is a
    SAM with the identical customise(OpenAPI) signature, so a method reference is the whole adapter.

Verification

The generated document must not change — this only moves where the same values come from. The golden
spec test (OasDocumentTests + expected-oas.json, #159) covers that on all three hosts. The Spring
sample's /v3/api-docs needs a manual check, since no test covers springdoc and its wiring changes.

Notes

  • configOf(OasProperties.class) returns the identical instance the host wired only under Spring
    Boot; Quarkus (toOasProperties()) and the servlet sample each build a second, content-equal
    DefaultOasProperties, which has no equals. The customizers only read values, so content
    equality is sufficient — but nothing may assume identity with the servlet-context attribute.
  • Breaking (unreleased since v1.9.0): all five customizer constructors, and the
    sampleapp.config.swagger.customizers package is gone.

Follow-ups this exposed, not fixed here

  • CompoundDocsFilter.init still does five servlet-context lookups, and CompoundDocsResolverConfig
    is re-projected field-by-field in four places with the same duplicated null-guards
  • DOMAIN_REGISTRY, OPERATION_REGISTRY, PLUGIN_REGISTRY, META_CONTEXT and VALIDATOR_FACTORY
    servlet attributes each have exactly one reader, all inside initJsonApi4j — they are input-only
    channels now
  • JsonApi4jReportGenerator.compoundDocsEnabled() digs jsonapi4j.cd.enabled out of the raw meta
    config map by string key while holding a PluginRegistry that answers
    isActivePlugin("JsonApiCompoundDocsPlugin")
  • Spring mounts the OAS servlet at rootPath + "/oas/*" and ignores jsonapi4j.oas.oasRootPath,
    while Quarkus and the Servlet integration honour it

Activity

  1. added a commit that references this issue on Sep 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions