Repository navigation
Description
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
JsonApi4jand derives what it needs once.
ErrorExamplesCustomizerstays no-arg — it has no state. - Existing null-tolerance is preserved:
configOfreturns empty when no OAS plugin is registered,
which is the situation callers previously expressed by passingnull, and
CommonOpenApiCustomizerstill publishes tags from the registries in that case. OasServletdrops five fields; it keepsjsonApi4jplus theoasPropertiesthat gates its 404
(that one comes from the servlet-context attribute the host initializer sets, possibly before
JsonApi4jexists).- The sample app's five springdoc adapter classes are deleted: springdoc's
OpenApiCustomizeris a
SAM with the identicalcustomise(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 noequals. 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.customizerspackage is gone.
Follow-ups this exposed, not fixed here
CompoundDocsFilter.initstill does five servlet-context lookups, andCompoundDocsResolverConfig
is re-projected field-by-field in four places with the same duplicated null-guardsDOMAIN_REGISTRY,OPERATION_REGISTRY,PLUGIN_REGISTRY,META_CONTEXTandVALIDATOR_FACTORY
servlet attributes each have exactly one reader, all insideinitJsonApi4j— they are input-only
channels nowJsonApi4jReportGenerator.compoundDocsEnabled()digsjsonapi4j.cd.enabledout of the raw meta
config map by string key while holding aPluginRegistrythat answers
isActivePlugin("JsonApiCompoundDocsPlugin")- Spring mounts the OAS servlet at
rootPath + "/oas/*"and ignoresjsonapi4j.oas.oasRootPath,
while Quarkus and the Servlet integration honour it
Activity
#164: optimize method signatures for OAS plugin, use just a JsonApi4j…