This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch docs
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/docs by this push:
new ba75ca38dd Add fluent programmatic builder API for REST resources and
mixins
ba75ca38dd is described below
commit ba75ca38dde0500e710aef5194c478663c2eef4e
Author: James Bognar <[email protected]>
AuthorDate: Mon Jun 1 14:57:24 2026 -0400
Add fluent programmatic builder API for REST resources and mixins
Reintroduces a public, fluent builder surface (RestBuilder /
AbstractRestBuilder)
for configuring @Rest resources and mixins programmatically (the Spring
@Bean use
case) with builder-set values winning over @Rest annotation values.
- RestBuilder<SELF> / AbstractRestBuilder<R, SELF>: full self-type CRTP
spine
(the builder is the override bag); 55 @Rest members + mdcAsyncPropagation
+
the generic set() escape hatch.
- Three flavor builders (RestServlet/RestResource/RestMixin) leave SELF
open for
true covariant chaining, each with a concrete DefaultBuilder<R> leaf.
- Constructor trio (no-arg + Foo(RestBuilder) + Foo.Builder) with a
package-private
restBuilder stash; RestContext.Args carries it and RestContext prepends a
synthesized @Rest so builder values beat annotations (rung-1 precedence).
- OQ-11 mirror-and-forward for the worker-backed multi-flavor capabilities
(FaviconMixin -> FaviconProvider, VersionMixin -> VersionProvider) via
composition; WellKnownMixin/SeoMixin re-parented for a uniform surface.
- BeanInstantiator exact-type builder preference (Option D): strict-typed
builder
candidates are preferred and weak supertype-only candidates are declined
when a
usable direct constructor exists, resolving the builder(Class)
autodetection
collision in mixin sub-context instantiation.
Adds RestBuilder_Test and BeanInstantiator_OptionD_Test; updates the
heuristic-
pinning BeanInstantiator_Test.w09 to the new stricter selection. Also adds
constructor-rationale Javadoc to the worker+builder constructors.
---
pages/release-notes/9.5.0.md | 182 ++++++++++++++++++++++++++++++++-----------
1 file changed, 136 insertions(+), 46 deletions(-)
diff --git a/pages/release-notes/9.5.0.md b/pages/release-notes/9.5.0.md
index 1c46e3c3d2..cd60d195bb 100644
--- a/pages/release-notes/9.5.0.md
+++ b/pages/release-notes/9.5.0.md
@@ -6,7 +6,7 @@ title: "Release 9.5.0"
**Date:** TBD
-Juneau 9.5.0 is a minor release with native OpenAPI 3.1 emission (alongside
Swagger v2, composed via the new four-class `org.apache.juneau.rest.docs` mixin
pack — `BasicSwaggerResource` / `BasicSwaggerUiResource` /
`BasicOpenApiResource` / `BasicRedocResource` — that replaces the
previously-considered `apiFormat` string knob), native TOML and YAML support,
BSON (Binary JSON) support for MongoDB-interoperable binary serialization, CBOR
(Concise Binary Object Representation) per RFC 8949 f [...]
+Juneau 9.5.0 is a minor release with native OpenAPI 3.1 emission (alongside
Swagger v2, composed via the new four-class `org.apache.juneau.rest.docs` mixin
pack — `SwaggerMixin` / `SwaggerUiMixin` / `OpenApiMixin` / `RedocMixin` — that
replaces the previously-considered `apiFormat` string knob), native TOML and
YAML support, BSON (Binary JSON) support for MongoDB-interoperable binary
serialization, CBOR (Concise Binary Object Representation) per RFC 8949 for IoT
and constrained environme [...]
### Security
@@ -1451,7 +1451,7 @@ See [YAML Basics](/docs/topics/YamlBasics) for full
documentation.
utest suite (124k+ tests) runs at the same wall-clock as before.
- Acceptance test: the full `BasicRestServlet` OpenAPI 3.1 document (six
api-docs URLs + full
components.schemas set) now round-trips JSON → YAML → JSON cleanly.
Previously
- `OpenApiYamlRoundTrip_Test#c01` had to scope to a single
`BasicOpenApiResource` mount via
+ `OpenApiYamlRoundTrip_Test#c01` had to scope to a single `OpenApiMixin`
mount via
`noInherit={"mixins"}` to dodge the underflow; that workaround has been
removed.
#### Direct Iterator/Iterable/Stream/Enumeration Serialization
@@ -2308,8 +2308,13 @@ capability classes (it is retained only on the
convenience-bundle bases that hav
**New `RestMixin` base (opt-in).** A third base class
`org.apache.juneau.rest.servlet.RestMixin` joins
`RestServlet` and `RestResource` to complete the triad. It is **opt-in** — a
plain `@Rest` POJO remains
fully valid as a mixin or child via annotation-only configuration; extending
`RestMixin` is a
-convenience and does not change composition semantics. (The fluent
`RestBuilder` programmatic-config
-surface from TODO-143 is **not** part of this release and remains deferred.)
+convenience and does not change composition semantics. Beyond the fluent
builder surface it shares with
+`RestServlet` / `RestResource` (see the builder-API entry below), `RestMixin`
adds **`getHostContext()`**,
+which returns the host (mixed-into) resource's `RestContext` — backed by the
mixin sub-context's parent
+linkage, so it is usable at config time and does not depend on an in-flight
request — letting a mixin op
+introspect the host (e.g. enumerate the host's child resources for a
navigation page) rather than its own
+childless sub-context. It returns `null` when a `RestMixin` subclass is
instantiated standalone rather than
+composed via `@Rest(mixins=...)`.
**Op-interfaces deleted; replaced by single-responsibility op-mixins.**
`BasicRestOperations` and
`BasicGroupOperations` are **removed**. Their endpoints are now true
`@Rest(mixins=...)` mixins —
@@ -2324,25 +2329,110 @@ navigation page retains its `@HtmlDocConfig` chrome (a
mixin op runs in its own
lose the host's page decoration).
**Favicon reconciliation.** The legacy `getFavIcon` op (which served
`REST/favicon` → `images/juneau.png`
-through static files) is dropped in favor of the single convention
`FaviconMixin`, which serves a
-classpath ICO (`/juneau-favicon.ico`) with a 30-day `Cache-Control`. This is a
behavior change for the
-default favicon bytes and the configuration key.
-
-**Per-capability flavor fill-in (delegate-bean model).** Capabilities where
standalone or routed-child
-deployment is a real use case gain their missing flavors as **independent
classes** that delegate to a
-shared worker bean / mixin instance (so the forms cannot drift). New
child-resource flavors:
+through static files) is dropped in favor of a `FaviconProvider`-backed flavor
set: the flavor-neutral
+`FaviconProvider` worker bean holds the icon bytes + `Cache-Control` value and
the serve logic, and the
+independent `FaviconMixin` (mixin) / `FaviconResource` (child) /
`FaviconServlet` (servlet) flavors each
+hold a `FaviconProvider` and delegate to it. The default serves a classpath
ICO (`/juneau-favicon.ico`)
+with a 30-day `Cache-Control` (`max-age=2592000, public`). This is a behavior
change for both the default
+favicon bytes and the configuration key.
+
+**Per-capability flavor fill-in (flavor-neutral worker beans).** Capabilities
where standalone or
+routed-child deployment is a real use case gain their missing flavors as
**independent classes** that each
+delegate to a **flavor-neutral worker bean** — never to another flavor — so
the forms cannot drift. The
+new worker beans are `FaviconProvider` / `VersionProvider` (in
`rest.convention`), `AdminProvider` (in
+`rest.ops`), `HealthAggregator` (in `rest.health`), and the four view-engine
raw-template dispatchers
+`JspDispatcher` / `MustacheDispatcher` / `ThymeleafDispatcher` /
`FreemarkerDispatcher`; the static-files
+flavors resolve the existing `StaticFiles` worker bean from the request context
+(`RestContext.getStaticFiles()`) instead of holding a mixin instance. New
child-resource flavors:
`StaticFilesResource`, `VersionResource`, `AdminResource`, `HealthResource`,
plus a `ViewResource`
abstract base and per-engine `JspResource` / `MustacheResource` /
`ThymeleafResource` /
`FreemarkerResource`; new favicon flavors `FaviconServlet` and
`FaviconResource`. `HealthServlet` /
-`HealthMixin` / `HealthResource` all delegate to a shared `HealthAggregator`
worker bean (OQ-5 split of
-the former `BasicHealthResource`). All other capabilities (Swagger, SwaggerUi,
OpenApi, Redoc,
-RouteIndex, Error, Stats, Htdoc, WellKnown, Seo) remain mixin-only.
+`HealthMixin` / `HealthResource` all delegate to a shared `HealthAggregator`
(OQ-5 split of the former
+`BasicHealthResource`). All other capabilities (Swagger, SwaggerUi, OpenApi,
Redoc, RouteIndex, Error,
+Stats, Htdoc, WellKnown, Seo) remain mixin-only.
**`RestRequest.getStaticFiles()` removed.** The request-level forwarder is
deleted; obtain the active
`StaticFiles` bean via `RestContext.getStaticFiles()` (e.g.
`req.getContext().getStaticFiles()`) or
bean-store injection. `FileVar`, `Widget`, and the static-files flavors are
repointed accordingly.
`RestContext.getStaticFiles()` is unchanged.
+**Route-index endpoint now content-negotiated.** `RouteIndexMixin`
(`/options`) returns a
+`RouteDescriptions` POJO instead of writing JSON directly, so the listing is
now content-negotiated
+through the host's configured serializers: `Accept: text/html` renders a
browsable table with clickable
+route links, while `application/json` / `text/xml` clients receive the same
entries in their requested
+format (mirroring `NavigationMixin.getChildren(...)`). Because it now relies
on the host's serializers,
+the host **must have serializers configured** (e.g. via `BasicUniversalConfig`
or a `Basic*` servlet
+base) — a bare `@Rest` host with no serializers can no longer
content-negotiate the listing, whereas the
+former JSON-only op did not require them. The historical `/routes` alias
remains reachable via
+`-Djuneau.routeindex.path=routes`.
+
+#### Fluent programmatic builder API — `RestBuilder` / `AbstractRestBuilder`
self-type CRTP (TODO-143)
+
+A public, fluent builder surface lets a `@Rest` resource, child resource, or
mixin be configured
+**programmatically** — the primary use case being instantiating a configured
resource bean in a Spring
+`@Bean` method — instead of (or layered over) the `@Rest` annotation.
Builder-supplied values take
+**precedence** over the class's own `@Rest` annotation members.
+
+**`RestBuilder<SELF>` config surface + `AbstractRestBuilder<R, SELF>` base
(full self-type CRTP).** The
+public interface `org.apache.juneau.rest.RestBuilder<SELF extends
RestBuilder<SELF>>` declares one fluent
+setter per `@Rest` member, plus the programmatic-only
`mdcAsyncPropagation(boolean)` knob and a
+`set(String, Object)` forward-compat escape hatch. The shared abstract base
+`AbstractRestBuilder<R, SELF extends AbstractRestBuilder<R, SELF>>` implements
every setter once — recording
+into a backing `RestAnnotation.Builder` override bag and returning `self()` —
and leaves the `SELF` self-type
+**open** so a builder subclass's bespoke setters chain with true covariant
returns (Option B / CRTP, aligned
+with the project-wide `SELF` / `self()` convention).
+
+**Per-flavor builders with a concrete `DefaultBuilder<R>` leaf.** Each base
class exposes its own self-typed
+flavor builder — `RestServlet.Builder<R, SELF>`, `RestResource.Builder<R,
SELF>`, and
+`RestMixin.Builder<R, SELF>` — together with a concrete `DefaultBuilder<R>`
leaf. The static factory
+`RestServlet.builder(MyRest.class)` (and the `RestResource` / `RestMixin`
equivalents) returns the
+`DefaultBuilder<R>`, so the common, non-subclassed path never has to spell two
type parameters:
+
+```java
+@Bean
+public MyRest myRest() {
+ return RestServlet.builder(MyRest.class)
+ .path("/foo")
+ .allowedHeaderParams("foo")
+ .build();
+}
+```
+
+A resource may also add a one-line `static Builder<MyRest> builder() { return
RestServlet.builder(MyRest.class); }`
+sugar so callers can write `MyRest.builder().path("/foo")....build()`.
+
+**Constructor trio + builder-beats-annotation precedence.** Every family base
provides the constructor trio:
+a no-arg constructor, a `Foo(RestBuilder)` builder-injection constructor, and
a `Foo.Builder`. `build()`
+stashes the builder onto the produced instance (a package-private
`restBuilder` field read non-reflectively
+via `getRestBuilder()`). At `RestContext` construction the stashed builder's
override bag is turned into a
+**synthetic `@Rest` annotation prepended as the most-derived entry** of the
resource's annotation chain, so
+builder-set values win over the class's own `@Rest` members (rung 1 of the
existing override-resolution
+chain). Collection-valued members **replace** the annotation value rather than
merging.
+
+**Mirror-and-forward builders for worker-backed capabilities (OQ-11).** For a
multi-flavor capability whose
+logic lives in a flavor-neutral worker bean, the flavor builder **mirrors the
worker bean's builder methods on
+its own surface and forwards** into the worker's builder, while inheriting the
full `RestBuilder` surface from
+`RestMixin.Builder`. For example `FaviconMixin.create()` mirrors `bytes` /
`classpath` / `cacheControl` into
+`FaviconProvider.Builder` and inherits `path` / `roleGuard` / etc.;
`VersionMixin` mirrors `VersionProvider`
+the same way. This is how the three flavors share capability config without a
shared flavor-builder base class
+(Java single inheritance forbids one — each flavor builder already extends its
REST builder base):
+
+```java
+@Bean
+FaviconMixin favicon() {
+ return FaviconMixin.create()
+ .classpath("/myapp/icon.ico") // mirrored → FaviconProvider.Builder
+ .path("/branding") // inherited RestBuilder surface
+ .build();
+}
+```
+
+**Bean-instantiation preference (internal).** So the new generic
`builder(Class)` factories don't hijack
+framework default instantiation, `BeanInstantiator` now prefers a builder that
builds the **exact requested
+type** (or a usable direct constructor) over one that only promises a
supertype. A flavor's own `create()` /
+nested `Builder` therefore wins over the inherited generic `builder(Class)`
(whose `build()` erases to a base
+class), and a plain resource/mixin carrying only the inherited builder falls
through to its no-arg constructor.
+
#### Opt-in lazy `@Rest(children=...)` materialization (TODO-121)
Parent resources annotated with `@Rest(lazyChildren=true)` now defer the
construction of each child
@@ -3022,16 +3112,16 @@ The variable map:
| Mixin | SVL variable | Default mount |
|---|---|---|
-| `BasicSwaggerResource` | `${juneau.swagger.path:api}` | `/api/*` |
-| `BasicSwaggerUiResource` | `${juneau.swaggerui.path:swagger}` | `/swagger/*`
|
-| `BasicOpenApiResource` | `${juneau.openapi.path:openapi}` | `/openapi/*`,
`/openapi.json`, `/openapi.yaml` |
-| `BasicRedocResource` | `${juneau.redoc.path:redoc}` | `/redoc/*` |
-| `BasicStaticFilesResource` | `${juneau.staticfiles.path:static}` |
`/static/*` |
-| `BasicVersionResource` | `${juneau.version.path:version}` | `/version` |
-| `BasicEchoResource` | `${juneau.echo.path:echo}` | `/echo/*` |
-| `BasicAdminResource` | `${juneau.admin.path:admin}` | `/admin/threads`,
`/admin/heap`, `/admin/cache/flush`, `/admin/ratelimit` |
-| `BasicRouteIndexResource` | `${juneau.routeindex.path:options}` | `/options`
|
-| `BasicJspResource` | `${juneau.jsp.path:jsp}` | `/jsp/*` |
+| `SwaggerMixin` | `${juneau.swagger.path:api}` | `/api/*` |
+| `SwaggerUiMixin` | `${juneau.swaggerui.path:swagger}` | `/swagger/*` |
+| `OpenApiMixin` | `${juneau.openapi.path:openapi}` | `/openapi/*`,
`/openapi.json`, `/openapi.yaml` |
+| `RedocMixin` | `${juneau.redoc.path:redoc}` | `/redoc/*` |
+| `StaticFilesMixin` | `${juneau.staticfiles.path:static}` | `/static/*` |
+| `VersionMixin` | `${juneau.version.path:version}` | `/version` |
+| `EchoMixin` | `${juneau.echo.path:echo}` | `/echo/*` |
+| `AdminMixin` | `${juneau.admin.path:admin}` | `/admin/threads`,
`/admin/heap`, `/admin/cache/flush`, `/admin/ratelimit` |
+| `RouteIndexMixin` | `${juneau.routeindex.path:options}` | `/options` |
+| `JspMixin` | `${juneau.jsp.path:jsp}` | `/jsp/*` |
Example — relocate the Swagger UI mount to `/docs/swagger-ui`:
@@ -3042,11 +3132,11 @@ java -Djuneau.swaggerui.path=docs/swagger-ui -jar
my-app.jar
Three mixins remain hardcoded because their mount paths are
specification-fixed and a runtime
override would break spec-compliant clients:
-- `BasicFaviconResource` — `/favicon.ico` (browser convention + WHATWG HTML
`rel="icon"` default).
-- `BasicSeoResource` — `/robots.txt` (RFC 9309 Robots Exclusion Protocol) and
`/sitemap.xml`
+- `FaviconMixin` — `/favicon.ico` (browser convention + WHATWG HTML
`rel="icon"` default).
+- `SeoMixin` — `/robots.txt` (RFC 9309 Robots Exclusion Protocol) and
`/sitemap.xml`
(sitemaps.org protocol). The two endpoints sit on separate handler methods,
not a multi-path
array, so they remain individually pinned.
-- `BasicWellKnownResource` — `/.well-known/security.txt` (RFC 8615 well-known
URIs + RFC 9116
+- `WellKnownMixin` — `/.well-known/security.txt` (RFC 8615 well-known URIs +
RFC 9116
security.txt).
**Migration note — multi-path collapse:** four mixins that previously declared
multiple paths
@@ -3057,10 +3147,10 @@ default:
| Mixin | Primary default | Removed secondary alias(es) | Migration |
|---|---|---|---|
-| `BasicStaticFilesResource` | `/static/*` | `/htdocs/*` |
`-Djuneau.staticfiles.path=htdocs` |
-| `BasicVersionResource` | `/version` | `/info`, `/about` |
`-Djuneau.version.path=info` (or `about`) |
-| `BasicEchoResource` | `/echo/*` | `/debug/echo/*` |
`-Djuneau.echo.path=debug/echo` |
-| `BasicRouteIndexResource` | `/options` | `/routes` |
`-Djuneau.routeindex.path=routes` |
+| `StaticFilesMixin` | `/static/*` | `/htdocs/*` |
`-Djuneau.staticfiles.path=htdocs` |
+| `VersionMixin` | `/version` | `/info`, `/about` |
`-Djuneau.version.path=info` (or `about`) |
+| `EchoMixin` | `/echo/*` | `/debug/echo/*` | `-Djuneau.echo.path=debug/echo` |
+| `RouteIndexMixin` | `/options` | `/routes` |
`-Djuneau.routeindex.path=routes` |
Deployers who relied on a secondary default must either set the SVL override
at startup or
compose a second mixin instance with the override. The default
`BasicStaticFiles` classpath
@@ -3120,31 +3210,31 @@ The api-docs surface is now four sibling
`@Rest(mixins=...)` mixins in the new `
| Mixin | Default `paths` | Owns |
|---|---|---|
-| `BasicSwaggerResource` | `/api` | Swagger v2 spec + `SwaggerUI` swap.
Standard content negotiation. |
-| `BasicSwaggerUiResource` | `/swagger` | HTML-first mount;
`@Rest(defaultAccept="text/html")` so bare browser requests render the
Swagger-UI view. Transitively pulls in `BasicSwaggerResource`. |
-| `BasicOpenApiResource` | `/openapi`, `/openapi.json`, `/openapi.yaml` |
OpenAPI 3.1 spec + `RedocUI` swap on `/openapi`. The `.json` and `.yaml` paths
are **format-pinned** — they ignore the request `Accept` header and always emit
the file extension's wire format (implemented via
`RestResponse.getDirectWriter(...)`, not content negotiation, so the pin
survives `Accept: text/html`). Mixin declares
`@Rest(serializers={YamlSerializer.class})` so YAML is available for the
`/openapi` conten [...]
-| `BasicRedocResource` | `/redoc` | HTML-first mount;
`@Rest(defaultAccept="text/html")`. Transitively pulls in
`BasicOpenApiResource`. |
+| `SwaggerMixin` | `/api` | Swagger v2 spec + `SwaggerUI` swap. Standard
content negotiation. |
+| `SwaggerUiMixin` | `/swagger` | HTML-first mount;
`@Rest(defaultAccept="text/html")` so bare browser requests render the
Swagger-UI view. Transitively pulls in `SwaggerMixin`. |
+| `OpenApiMixin` | `/openapi`, `/openapi.json`, `/openapi.yaml` | OpenAPI 3.1
spec + `RedocUI` swap on `/openapi`. The `.json` and `.yaml` paths are
**format-pinned** — they ignore the request `Accept` header and always emit the
file extension's wire format (implemented via
`RestResponse.getDirectWriter(...)`, not content negotiation, so the pin
survives `Accept: text/html`). Mixin declares
`@Rest(serializers={YamlSerializer.class})` so YAML is available for the
`/openapi` content-negoti [...]
+| `RedocMixin` | `/redoc` | HTML-first mount;
`@Rest(defaultAccept="text/html")`. Transitively pulls in `OpenApiMixin`. |
Pick the mixins you want and the URL surface follows. Three common
compositions:
```java
// OpenAPI 3.1 spec only — /openapi, /openapi.json, /openapi.yaml.
-@Rest(path="/api", mixins=BasicOpenApiResource.class)
+@Rest(path="/api", mixins=OpenApiMixin.class)
public class ApiResource extends RestServlet { ... }
-// OpenAPI 3.1 + Redoc UI — pulls BasicOpenApiResource in transitively.
-@Rest(path="/api", mixins=BasicRedocResource.class)
+// OpenAPI 3.1 + Redoc UI — pulls OpenApiMixin in transitively.
+@Rest(path="/api", mixins=RedocMixin.class)
public class ApiResource extends RestServlet { ... }
-// Everything (post-9.5.0 default for BasicRestServlet / BasicRestObject).
-@Rest(path="/api", mixins={BasicSwaggerUiResource.class,
BasicRedocResource.class})
+// Everything (post-9.5.0 default for BasicRestServlet / BasicRestResource).
+@Rest(path="/api", mixins={SwaggerUiMixin.class, RedocMixin.class})
public class ApiResource extends RestServlet { ... }
// Serves: /api, /swagger, /openapi, /openapi.json, /openapi.yaml, /redoc
```
Transitive resolution dedupes by class identity (`LinkedHashSet` in the
framework's `collectRestMixins(...)` walk), so listing both UI mixins doesn't
double-instantiate the spec mixins. Parent-chain aggregation also works — a
child class's `@Rest(mixins=...)` unions with the parent's.
-`BasicRestServlet` and `BasicRestObject` migrated to declare
`@Rest(mixins={BasicSwaggerUiResource.class, BasicRedocResource.class})` so
subclasses get all six api-docs URLs by default. Apps that want to opt out
(e.g. to mount only OpenAPI) can use `@Rest(noInherit={"mixins"}, mixins=...)`
to cut off the inherited docs mixins.
+`BasicRestServlet` and `BasicRestResource` migrated to declare
`@Rest(mixins={SwaggerUiMixin.class, RedocMixin.class})` so subclasses get all
six api-docs URLs by default. Apps that want to opt out (e.g. to mount only
OpenAPI) can use `@Rest(noInherit={"mixins"}, mixins=...)` to cut off the
inherited docs mixins.
**Breaking changes (TODO-74):**
@@ -3154,8 +3244,8 @@ Transitive resolution dedupes by class identity
(`LinkedHashSet` in the framewor
| `juneau.rest.apiFormat` system property | Removed. No replacement — apps
that toggled this at runtime should pick mixins at compile time. |
| `RestContext.getApiFormat()` | Removed. |
| `RestServerConstants.API_FORMAT_SWAGGER` / `_OPENAPI` / `_BOTH` /
`SYSPROP_apiFormat` / `PROPERTY_apiFormat` | Removed. |
-| `BasicRestOperations.getSwagger(...)` / `getOpenApi(...)` | Removed from the
interface. `BasicRestServlet` / `BasicRestObject` mount these via
`BasicSwaggerResource` / `BasicOpenApiResource` instead. |
-| `BasicGroupOperations.getChildrenSwagger(...)` / `getChildrenOpenApi(...)`
(the `?Swagger` / `?OpenApi` query mirrors on group resources) | Removed. Hit
`/api`, `/swagger`, `/openapi`, or `/redoc` directly — they are always mounted
on `BasicRestServletGroup` / `BasicRestObjectGroup`. |
+| `BasicRestOperations.getSwagger(...)` / `getOpenApi(...)` | Removed from the
interface. `BasicRestServlet` / `BasicRestResource` mount these via
`SwaggerMixin` / `OpenApiMixin` instead. |
+| `BasicGroupOperations.getChildrenSwagger(...)` / `getChildrenOpenApi(...)`
(the `?Swagger` / `?OpenApi` query mirrors on group resources) | Removed. Hit
`/api`, `/swagger`, `/openapi`, or `/redoc` directly — they are always mounted
on `BasicRestServletGroup` / `BasicRestResourceGroup`. |
| `BasicGroupOperations.HasSwaggerQueryParam` / `HasOpenApiQueryParam` matcher
inner classes | Removed (no consumers left). |
Migration sketch:
@@ -3166,14 +3256,14 @@ Migration sketch:
public class MyApi extends BasicRestServlet { ... }
// 9.5.0:
-@Rest(noInherit={"mixins"}, mixins=BasicRedocResource.class) // opt out of
Swagger
+@Rest(noInherit={"mixins"}, mixins=RedocMixin.class) // opt out of Swagger
public class MyApi extends BasicRestServlet { ... }
// or extend RestServlet directly and pick what you want:
-@Rest(mixins=BasicRedocResource.class)
+@Rest(mixins=RedocMixin.class)
public class MyApi extends RestServlet implements BasicUniversalConfig { ... }
```
-Apps that subclass `BasicRestServlet` / `BasicRestObject` without setting
`apiFormat` or relying on the query mirrors get the new behavior (six api-docs
URLs instead of one) automatically.
+Apps that subclass `BasicRestServlet` / `BasicRestResource` without setting
`apiFormat` or relying on the query mirrors get the new behavior (six api-docs
URLs instead of one) automatically.
#### Static-Files Mixin (TODO-75)