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 11eb968c99 Fix docs from TODO-297 audit: mechanical sweep,
examples-rest purge, health-class fabrications
11eb968c99 is described below
commit 11eb968c993ab52897ddaa458789440a28d2f2c1
Author: James Bognar <[email protected]>
AuthorDate: Sun Jul 26 13:22:59 2026 -0400
Fix docs from TODO-297 audit: mechanical sweep, examples-rest purge,
health-class fabrications
Three batches of fixes identified by the TODO-297 documentation accuracy
audit:
- READY-299 (mechanical patterns): stale/incorrect code patterns across
bean-dictionary, JSON/XML/UON/URL-encoding/YAML/JSONL/BSON/CBOR/HOCON
marshalling topics, plus request and form/OIDC authentication topics.
- READY-301 (juneau-examples-rest purge): replaced references to the
removed juneau-examples-rest module with real, existing resources across
the Swagger annotation topics (info/tags/operations/parameters/responses)
and the HtmlDoc config/widget/customization/stylesheet topics.
- READY-303 (health-class fabrications): replaced fabricated
BasicHealthResource/BasicSwaggerResource-style class names with the real
Health class family, and fixed Swagger-mixin fabrications in
10.07.RestServerComposition plus a false noInherit claim in
10.08.RestServerMixinSubContexts.
Co-authored-by: Cursor <[email protected]>
---
pages/topics/03.15.00.BeanDictionaries.md | 4 +-
pages/topics/03.25.00.JsonSupport.md | 2 +-
pages/topics/03.26.00.XmlSupport.md | 2 +-
pages/topics/03.26.07.XmlNamespaces.md | 2 +-
pages/topics/03.28.00.UonSupport.md | 2 +-
pages/topics/03.29.00.UrlEncodingSupport.md | 2 +-
pages/topics/03.36.00.YamlSupport.md | 2 +-
pages/topics/03.39.00.JsonlSupport.md | 4 +-
pages/topics/03.42.Bson.md | 4 +-
pages/topics/03.43.Cbor.md | 4 +-
pages/topics/03.44.HoconSupport.md | 2 +-
pages/topics/10.07.RestServerComposition.md | 92 +++++++++---------
pages/topics/10.08.RestServerMixinSubContexts.md | 39 +++++---
pages/topics/10.09.RestServerStandaloneVsMixin.md | 26 ++++-
pages/topics/10.29.03.BasicSwaggerInfo.md | 53 ++++++-----
pages/topics/10.29.04.SwaggerTags.md | 21 ++--
pages/topics/10.29.05.SwaggerOperations.md | 17 ++--
pages/topics/10.29.06.SwaggerParameters.md | 111 +++++++++++++---------
pages/topics/10.29.07.SwaggerResponses.md | 4 +-
pages/topics/10.31.00.HtmlDocConfigAnnotation.md | 9 +-
pages/topics/10.31.03.HtmlPredefinedWidgets.md | 100 ++++++++++---------
pages/topics/10.31.04.HtmlUiCustomization.md | 5 +-
pages/topics/10.31.05.HtmlStylesheets.md | 40 ++++----
pages/topics/13.09.08.Request.md | 2 +-
pages/topics/13.13.02.AuthenticationForm.md | 2 +-
pages/topics/13.13.03.AuthenticationOIDC.md | 2 +-
pages/topics/16.09.HealthProbes.md | 11 ++-
27 files changed, 322 insertions(+), 242 deletions(-)
diff --git a/pages/topics/03.15.00.BeanDictionaries.md
b/pages/topics/03.15.00.BeanDictionaries.md
index b59c54b0a6..3e9cb9e2e0 100644
--- a/pages/topics/03.15.00.BeanDictionaries.md
+++ b/pages/topics/03.15.00.BeanDictionaries.md
@@ -82,13 +82,13 @@ The bean dictionary setting can consist of any of the
following types:
// Create a parser and tell it which classes to try to resolve.
ReaderParser parser = JsonParser
.create()
- .dictionary(Foo.class, Bar.class)
+ .beanDictionary(Foo.class, Bar.class)
.build();
// Use the predefined HTML5 bean dictionary which is a BeanDictionaryList.
ReaderParser parser = HtmlParser
.create()
- .dictionary(HtmlBeanDictionary.class)
+ .beanDictionary(HtmlBeanDictionary.class)
.build();
```
diff --git a/pages/topics/03.25.00.JsonSupport.md
b/pages/topics/03.25.00.JsonSupport.md
index 4e37914c19..f8e211d535 100644
--- a/pages/topics/03.25.00.JsonSupport.md
+++ b/pages/topics/03.25.00.JsonSupport.md
@@ -47,7 +47,7 @@ Person person = new Person()
.city("Anywhereville")
.state(NY)
.zip(12345)
- .isCurrent(true);
+ .isCurrent(true)
);
```
diff --git a/pages/topics/03.26.00.XmlSupport.md
b/pages/topics/03.26.00.XmlSupport.md
index 98f106c39e..6c1ac31954 100644
--- a/pages/topics/03.26.00.XmlSupport.md
+++ b/pages/topics/03.26.00.XmlSupport.md
@@ -53,7 +53,7 @@ Person person = new Person()
.city("Anywhereville")
.state(NY)
.zip(12345)
- .isCurrent(true);
+ .isCurrent(true)
);
```
diff --git a/pages/topics/03.26.07.XmlNamespaces.md
b/pages/topics/03.26.07.XmlNamespaces.md
index 785bcc3420..edd4ede870 100644
--- a/pages/topics/03.26.07.XmlNamespaces.md
+++ b/pages/topics/03.26.07.XmlNamespaces.md
@@ -66,7 +66,7 @@ Person person = new Person()
.city("Anywhereville")
.state(NY)
.zip(12345)
- .isCurrent(true);
+ .isCurrent(true)
);
// Create a new serializer with readable output, this time with namespaces
enabled.
diff --git a/pages/topics/03.28.00.UonSupport.md
b/pages/topics/03.28.00.UonSupport.md
index 3655540732..130e09b0df 100644
--- a/pages/topics/03.28.00.UonSupport.md
+++ b/pages/topics/03.28.00.UonSupport.md
@@ -53,7 +53,7 @@ Person person = new Person()
.city("Anywhereville")
.state(NY)
.zip(12345)
- .isCurrent(true);
+ .isCurrent(true)
);
```
diff --git a/pages/topics/03.29.00.UrlEncodingSupport.md
b/pages/topics/03.29.00.UrlEncodingSupport.md
index d162724dfc..bc56ab3c2d 100644
--- a/pages/topics/03.29.00.UrlEncodingSupport.md
+++ b/pages/topics/03.29.00.UrlEncodingSupport.md
@@ -54,7 +54,7 @@ Person person = new Person()
.city("Anywhereville")
.state(NY)
.zip(12345)
- .isCurrent(true);
+ .isCurrent(true)
);
```
diff --git a/pages/topics/03.36.00.YamlSupport.md
b/pages/topics/03.36.00.YamlSupport.md
index 2d8cf74ed5..2ef1054fba 100644
--- a/pages/topics/03.36.00.YamlSupport.md
+++ b/pages/topics/03.36.00.YamlSupport.md
@@ -48,7 +48,7 @@ Person person = new Person()
.city("Anywhereville")
.state(NY)
.zip(12345)
- .isCurrent(true);
+ .isCurrent(true)
);
```
diff --git a/pages/topics/03.39.00.JsonlSupport.md
b/pages/topics/03.39.00.JsonlSupport.md
index e8a8032ff5..37ca9ce182 100644
--- a/pages/topics/03.39.00.JsonlSupport.md
+++ b/pages/topics/03.39.00.JsonlSupport.md
@@ -80,9 +80,9 @@ The conversion follows the <a href="https://jsonlines.org/"
target="_blank">JSON
## REST Integration
```java
-// Use BasicJsonlConfig for JSONL-only REST resources
+// Use BasicUniversalConfig for JSONL-only REST resources
@Rest
-public class MyResource extends RestServlet implements BasicJsonlConfig { ... }
+public class MyResource extends RestServlet implements BasicUniversalConfig {
... }
// JSONL is also included in BasicUniversalConfig
@Rest
diff --git a/pages/topics/03.42.Bson.md b/pages/topics/03.42.Bson.md
index 7094065a46..ab099a9eec 100644
--- a/pages/topics/03.42.Bson.md
+++ b/pages/topics/03.42.Bson.md
@@ -82,9 +82,9 @@ byte[] bson = s.write(someObject);
## REST Integration
```java
-// Use BasicBsonConfig for BSON-only REST resources
+// Use BasicUniversalConfig for BSON-only REST resources
@Rest
-public class MyResource extends RestServlet implements BasicBsonConfig { ... }
+public class MyResource extends RestServlet implements BasicUniversalConfig {
... }
// BSON is also included in BasicUniversalConfig
@Rest
diff --git a/pages/topics/03.43.Cbor.md b/pages/topics/03.43.Cbor.md
index b1a0fe95c8..a86bd6f228 100644
--- a/pages/topics/03.43.Cbor.md
+++ b/pages/topics/03.43.Cbor.md
@@ -99,9 +99,9 @@ JsonMap parsed = CborParser.Base64.DEFAULT.read(b64,
JsonMap.class);
## REST Integration
```java
-// Use BasicCborConfig for CBOR-only REST resources
+// Use BasicUniversalConfig for CBOR-only REST resources
@Rest
-public class MyResource extends RestServlet implements BasicCborConfig { ... }
+public class MyResource extends RestServlet implements BasicUniversalConfig {
... }
// CBOR is also included in BasicUniversalConfig
@Rest
diff --git a/pages/topics/03.44.HoconSupport.md
b/pages/topics/03.44.HoconSupport.md
index acf6aaeea6..5406961ee1 100644
--- a/pages/topics/03.44.HoconSupport.md
+++ b/pages/topics/03.44.HoconSupport.md
@@ -99,7 +99,7 @@ public class MyResource extends RestServlet implements
BasicUniversalConfig { ..
// HOCON-only resource
@Rest
-public class HoconResource extends RestServlet implements BasicHoconConfig {
... }
+public class HoconResource extends RestServlet implements BasicUniversalConfig
{ ... }
```
## Round-Trip Notes
diff --git a/pages/topics/10.07.RestServerComposition.md
b/pages/topics/10.07.RestServerComposition.md
index ffa0005d59..8077b25e94 100644
--- a/pages/topics/10.07.RestServerComposition.md
+++ b/pages/topics/10.07.RestServerComposition.md
@@ -25,16 +25,19 @@ Juneau REST servers ship two complementary composition /
mounting primitives on
fighting an app's root `path="/"` mapping.
Both attributes are purely additive — resources that don't declare them keep
their pre-9.5.0
-behavior unchanged. They are also not mutually exclusive: a single class can
declare both at once
-(`BasicHealthResource` ships with both supported), and downstream consumers
pick whichever
-deployment style fits their app.
+behavior unchanged. They are also not mutually exclusive: nothing stops a
single class from
+declaring both `mixins` and `paths` at once. The built-in health-probe family,
however, keeps
+the three deployment flavors as three separate classes — `HealthResource`
(child mount),
+`HealthServlet` (standalone `paths=` mount), and `HealthMixin` (`mixins=`
composition) — rather
+than collapsing them into one dual-purpose class; see
+[Standalone vs Mixin Resources](/docs/topics/RestServerStandaloneVsMixin) for
the rationale.
## Motivation
### Why composition?
Java single-inheritance forces a binary choice when you want to pull in a
built-in resource such
-as `BasicHealthResource`:
+as `HealthMixin`:
- Subclass it — and lose the ability to subclass your own framework type
(`BasicRestServlet`,
`BasicRestResourceGroup`, etc.).
@@ -75,7 +78,7 @@ When the importing resource's `RestContext` is built, the
mixin walk:
path/method collisions — by registration order — so a resource can
selectively override a
single mixin operation without losing the others.
-### Example: mixing in `BasicHealthResource`
+### Example: mixing in `HealthMixin`
The recommended way to wire Kubernetes probes into an existing root servlet:
@@ -87,7 +90,7 @@ import org.apache.juneau.rest.server.servlet.*;
@Rest(
path="/",
- mixins=BasicHealthResource.class
+ mixins=HealthMixin.class
)
public class RootResources extends BasicRestServlet {
@@ -116,12 +119,12 @@ the importing resource's method wins:
```java
@Rest
-public class HealthMixin {
+public class SampleMixin {
@RestGet(path="/same")
public String fromMixin() { return "mixin"; }
}
-@Rest(mixins=HealthMixin.class)
+@Rest(mixins=SampleMixin.class)
public class RootResources extends BasicRestServlet {
@RestGet(path="/same")
public String fromResource() { return "resource"; }
@@ -195,12 +198,12 @@ of **exact-match** URL patterns that all map to the same
`ServletHolder`:
```java
@Rest(paths={"/healthz","/readyz","/livez"})
-public class BasicHealthResource extends BasicRestServlet { ... }
+public class HealthServlet extends BasicRestServlet { ... }
```
The Jetty auto-mount logic (in `JettyServerComponent`) sees the `paths`
attribute and registers
**one** servlet instance with the `ServletContextHandler` under **three**
separate path-spec
-mappings (`/healthz`, `/readyz`, `/livez`). The same `BasicHealthResource`
instance handles
+mappings (`/healthz`, `/readyz`, `/livez`). The same `HealthServlet` instance
handles
every request that lands on any of the three URLs.
Path-spec semantics differ from `path`:
@@ -215,7 +218,7 @@ one (or several) specific URLs and you don't want a
wildcard absorbing sibling r
### Example: probe URLs without a root collision
-The motivating use case. `BasicHealthResource` ships with
`@Rest(paths={"/healthz","/readyz","/livez"})`
+The motivating use case. `HealthServlet` ships with
`@Rest(paths={"/healthz","/readyz","/livez"})`
and is wired in via `HealthProbeConfiguration`:
```java
@@ -257,13 +260,13 @@ After startup, the Jetty container has two top-level
mounts:
| Path spec | Servlet | Source |
|-----------|-------------------------|------------------------------|
| `/*` | `RootResources` | `@Bean Servlet root()` +
`@Rest(path="/")` |
-| `/healthz`| `BasicHealthResource` | `@Bean Servlet healthProbeServlet()` +
`@Rest(paths=...)` |
-| `/readyz` | `BasicHealthResource` | (same instance, second mapping) |
-| `/livez` | `BasicHealthResource` | (same instance, third mapping) |
+| `/healthz`| `HealthServlet` | `@Bean Servlet healthProbeServlet()` +
`@Rest(paths=...)` |
+| `/readyz` | `HealthServlet` | (same instance, second mapping) |
+| `/livez` | `HealthServlet` | (same instance, third mapping) |
The three probe paths are exact-match, so they're matched by the servlet
container *before*
falling through to `RootResources`'s `/*` prefix mount. No collision, no
order-of-registration
-fragility — just three explicit URLs that always land on `BasicHealthResource`.
+fragility — just three explicit URLs that always land on `HealthServlet`.
### Single `ServletHolder`, multiple mappings
@@ -325,12 +328,15 @@ This split lets a resource ship with sensible defaults
for both deployment style
| Mount a separate addon servlet at fixed URLs without prefixes. | `paths`
|
| Override one route on a mixin while keeping the rest. | `mixins` +
local method on importer (importer-wins). |
| Run an addon in isolation (its own context, bean store, etc.). | `paths` —
declare the addon as its own `@Bean Servlet`. |
-| Keep the option open and let downstream pick. | Declare
both on the addon class. `BasicHealthResource` does this. |
+| Keep the option open and let downstream pick. | Declare
both attributes on the same class, or ship separate mixin/standalone flavors
and let the caller choose. |
-The two are not mutually exclusive. `BasicHealthResource` declares
+The two attributes are not mutually exclusive at the framework level — nothing
stops a single
+class from declaring both `mixins`-compatible operations and a `paths` array.
The built-in
+health-probe family instead keeps the flavors as separate classes:
`HealthServlet` declares
`@Rest(paths={"/healthz","/readyz","/livez"})` so it can be auto-mounted
standalone (Option B in
-the probe docs), and downstream apps can additionally pull it in via
-`@Rest(mixins=BasicHealthResource.class)` on their own root resource (Option
A). The mixin path
+the probe docs), while `HealthMixin` is the bare-`@Rest` flavor apps pull in
via
+`@Rest(mixins=HealthMixin.class)` on their own root resource (Option A). Both
delegate to the
+same `HealthAggregator` worker bean, so the two forms can't drift. The mixin
path
ignores the `paths` array — mixin operations are grafted at the importer's URL
space, not the
mixin's own.
@@ -436,7 +442,7 @@ top-level mounts.
```java
@Rest(paths={"/healthz","/readyz"})
-public class TenantHealthResource extends BasicHealthResource {
+public class TenantHealthServlet extends HealthServlet {
@Override
public String[] getPaths() {
var prefix = "/" + tenantId() + "/health";
@@ -446,7 +452,7 @@ public class TenantHealthResource extends
BasicHealthResource {
```
The getter runs at construction time (before the servlet container hits the
resource), so the
-mounted URLs reflect the per-deployment tenant id without recompiling
`BasicHealthResource`.
+mounted URLs reflect the per-deployment tenant id without recompiling
`HealthServlet`.
**Rung 3 — `@Rest(paths={"…"})` with SVL + comma-split:**
@@ -562,7 +568,7 @@ first and the child's appended after. The resulting list is
funneled through a
### Example: parent declares a mixin, child inherits
```java
-@Rest(mixins = BasicRedocResource.class)
+@Rest(mixins = RedocMixin.class)
public abstract class CommonApi extends RestServlet {
@RestGet("/health") public String health() { return "ok"; }
}
@@ -573,38 +579,38 @@ public class TenantApi extends CommonApi {
}
```
-`TenantApi` resolves to mixin set `[BasicOpenApiResource, BasicRedocResource]`
— the parent's
-`BasicRedocResource` flows in via `@Inherited`, and transitive resolution then
walks
-`BasicRedocResource`'s own `@Rest(mixins=BasicOpenApiResource.class)` to bring
in the spec
+`TenantApi` resolves to mixin set `[RedocMixin, OpenApiMixin]` — the parent's
+`RedocMixin` flows in via `@Inherited`, and transitive resolution then walks
+`RedocMixin`'s own `@Rest(mixins=OpenApiMixin.class)` to bring in the spec
mixin. Result: `TenantApi` serves `/health`, `/items`, `/openapi`,
`/openapi.json`,
`/openapi.yaml`, and `/redoc`.
### Example: parent + child both declare mixins (union)
```java
-@Rest(mixins = BasicSwaggerResource.class)
+@Rest(mixins = SwaggerMixin.class)
public abstract class CommonApi extends RestServlet { ... }
-@Rest(mixins = BasicHealthResource.class)
+@Rest(mixins = HealthMixin.class)
public class TenantApi extends CommonApi { ... }
```
-`TenantApi` resolves to mixin set `[BasicSwaggerResource,
BasicHealthResource]` — parent-first
+`TenantApi` resolves to mixin set `[SwaggerMixin, HealthMixin]` — parent-first
ordering preserved, both mixins live, both grafted. The child does not need to
redeclare the
parent's mixin to keep it.
### Example: parent + child declare the same mixin (dedupe)
```java
-@Rest(mixins = BasicHealthResource.class)
+@Rest(mixins = HealthMixin.class)
public abstract class CommonApi extends RestServlet { ... }
-@Rest(mixins = {BasicHealthResource.class, BasicSwaggerResource.class})
+@Rest(mixins = {HealthMixin.class, SwaggerMixin.class})
public class TenantApi extends CommonApi { ... }
```
-`TenantApi` resolves to mixin set `[BasicHealthResource,
BasicSwaggerResource]`. The
-`BasicHealthResource` declaration on the child is harmless — `LinkedHashSet`
dedupes by class
+`TenantApi` resolves to mixin set `[HealthMixin, SwaggerMixin]`. The
+`HealthMixin` declaration on the child is harmless — `LinkedHashSet` dedupes
by class
identity, so the mixin is constructed once and grafted once. The child can
list the parent's
mixin alongside its own without worrying about double-registration.
@@ -615,7 +621,7 @@ substitute a different api-docs surface, or a custom
subclass of `BasicRestServl
only the OpenAPI half:
```java
-@Rest(noInherit = {"mixins"}, mixins = BasicRedocResource.class)
+@Rest(noInherit = {"mixins"}, mixins = RedocMixin.class)
public class OpenApiOnly extends BasicRestServlet {
@RestGet("/items") public List<Item> items() { ... }
}
@@ -646,24 +652,24 @@ order is well-defined:
Worked example:
```java
-@Rest(mixins = BasicOpenApiResource.class)
+@Rest(mixins = OpenApiMixin.class)
public abstract class CommonApi extends RestServlet { ... }
-@Rest(mixins = BasicRedocResource.class)
+@Rest(mixins = RedocMixin.class)
public class TenantApi extends CommonApi { ... }
```
-`TenantApi` resolves to mixin set `[BasicOpenApiResource, BasicRedocResource]`:
+`TenantApi` resolves to mixin set `[OpenApiMixin, RedocMixin]`:
-- Parent contributes `BasicOpenApiResource` directly.
-- Child contributes `BasicRedocResource` directly.
-- Transitive walk visits `BasicRedocResource` and follows its
- `@Rest(mixins=BasicOpenApiResource.class)` — but `BasicOpenApiResource` is
already in the
+- Parent contributes `OpenApiMixin` directly.
+- Child contributes `RedocMixin` directly.
+- Transitive walk visits `RedocMixin` and follows its
+ `@Rest(mixins=OpenApiMixin.class)` — but `OpenApiMixin` is already in the
set, so the dedupe drops the second occurrence on the floor. Net effect: the
spec mixin is
grafted once, mounted at `/openapi/*`, and shared between both UI mounts.
This is the pattern the api-docs mixin pack relies on to make
-`@Rest(mixins={BasicSwaggerUiResource.class, BasicRedocResource.class})` on
`BasicRestServlet`
+`@Rest(mixins={SwaggerUiMixin.class, RedocMixin.class})` on `BasicRestServlet`
work correctly. See [API-Docs Mixin Pack](/docs/topics/ApiDocsMixins) for the
full worked
example, including the `noInherit={"mixins"}` opt-out for users who want to
drop one half of
the inherited pack.
@@ -674,8 +680,8 @@ the inherited pack.
resources entirely in code via `RestBuilder<SELF>` / `AbstractRestBuilder<R,
SELF>`, without `@Rest` annotation
attributes.
- [API-Docs Mixin Pack](/docs/topics/ApiDocsMixins) — the canonical worked
example of mixin
- composition: four single-purpose api-docs mixins (`BasicSwaggerResource`,
- `BasicSwaggerUiResource`, `BasicOpenApiResource`, `BasicRedocResource`)
composed into
+ composition: four single-purpose api-docs mixins (`SwaggerMixin`,
+ `SwaggerUiMixin`, `OpenApiMixin`, `RedocMixin`) composed into
`BasicRestServlet` with transitive resolution + parent-chain aggregation.
- [Mixin Sub-Contexts](/docs/topics/RestServerMixinSubContexts) — the
per-mixin `RestContext`
inheritance model, `noInherit` opt-out, hook dual-firing, flat-inheritance
rule, and
diff --git a/pages/topics/10.08.RestServerMixinSubContexts.md
b/pages/topics/10.08.RestServerMixinSubContexts.md
index 1dbd0f76df..2be916d6fd 100644
--- a/pages/topics/10.08.RestServerMixinSubContexts.md
+++ b/pages/topics/10.08.RestServerMixinSubContexts.md
@@ -194,12 +194,12 @@ whatever serializer chain they had.
**`noInherit={"guards"}`** — the mixin opts out of host guard protection.
```java
-// Health probe mixin: explicitly unguarded even if host has BearerTokenGuard.
+// Example probe mixin: explicitly unguarded even if host has BearerTokenGuard.
@Rest(
paths = {"/healthz", "/readyz", "/livez"},
noInherit = {"guards"}
)
-public class HealthResource extends BasicHealthResource { ... }
+public class UnguardedProbeMixin { ... }
```
Without `noInherit={"guards"}`, the host's `BearerTokenGuard` would also
protect `/healthz` — the
@@ -446,14 +446,30 @@ Guards inherit by default. This is a deliberate "fail
strict" choice:
Concretely: if the host declares `@Rest(guards=BearerTokenGuard.class)`, every
mixin endpoint on
that host is also protected by `BearerTokenGuard` — even if the mixin's class
declares no guards
-itself. The only way to expose a mixin endpoint without the host's guard chain
is to declare
-`@Rest(noInherit={"guards"})` on the mixin's class.
+itself. To expose a mixin endpoint without the host's guard chain, either
declare
+`@Rest(noInherit={"guards"})` on the mixin's own class, or — for a shipped
mixin you can't edit —
+apply the same opt-out from the host side via `@Mixin(...,
noInherit="guards")` (see
+[Host-side overrides with `@Mixin`](#host-side-overrides-with-mixin-1000)
above).
+
+Health probes are the natural real-world case for this opt-out: probes
(`/healthz`, `/readyz`,
+`/livez`) need to be reachable by the load balancer / orchestrator even when
the rest of the API
+requires authentication. The shipped `HealthMixin`
(`org.apache.juneau.rest.server.health`)
+declares no `guards` and no `noInherit` of its own, so composing it into a
guarded host inherits
+that host's guard chain by default, same as any other mixin. To keep the
probes reachable
+without authentication, opt out from the host side:
-`BasicHealthResource` is the canonical example of a deliberately-unguarded
mixin: probes
-(`/healthz`, `/readyz`, `/livez`) need to be reachable by the load balancer /
orchestrator even
-when the rest of the API requires authentication. `BasicHealthResource`
declares
-`@Rest(noInherit={"guards"})` so its endpoints stay unguarded regardless of
what guard chain the
-host carries.
+```java
+@Rest(
+ guards = BearerTokenGuard.class,
+ mixinDefs = @Mixin(type = HealthMixin.class, noInherit = "guards")
+)
+public class RootResources extends BasicRestServlet { ... }
+```
+
+Alternatively, mount probes via the standalone `HealthServlet` flavor instead
of the mixin —
+it's a separate servlet with its own `RestContext`, so the host's guard chain
never applies to
+it at all. See [Health / Readiness / Liveness
Probes](/docs/topics/HealthProbes) for both
+options.
The asymmetry — host adds a guard, mixin endpoints become protected unless the
mixin opts out —
is intentional. Accidentally protected is recoverable (the user sees a
401/403, the mixin
@@ -469,8 +485,9 @@ before anyone notices).
isolation (not inheritance) is what you want.
- [REST Server — Children vs Mixins](/docs/topics/RestServerChildrenVsMixins)
— the full
same-vs-different matrix for choosing between the two.
-- [Health / Readiness / Liveness Probes](/docs/topics/HealthProbes) — the
canonical
- `noInherit={"guards"}` mixin in the codebase.
+- [Health / Readiness / Liveness Probes](/docs/topics/HealthProbes) — the
mixin, standalone,
+ and child flavors of the built-in probe resource, and the host-side
`noInherit={"guards"}`
+ opt-out pattern for the mixin flavor.
- [REST Server — Logging and
Debugging](/docs/topics/RestServerLoggingAndDebugging) —
per-mixin `callLogger` / `debugEnablement` override patterns.
- [REST Server — SVL Variables](/docs/topics/RestServerSvlVariables) — context
for the
diff --git a/pages/topics/10.09.RestServerStandaloneVsMixin.md
b/pages/topics/10.09.RestServerStandaloneVsMixin.md
index 5ecb98ac72..ced9cbf286 100644
--- a/pages/topics/10.09.RestServerStandaloneVsMixin.md
+++ b/pages/topics/10.09.RestServerStandaloneVsMixin.md
@@ -84,12 +84,28 @@ to the matching mixin instance so there is a single source
of truth.
> `RawTemplateDispatcher` covers the *raw* file-serving path (serving a
> template directly by its
> trailing request path). A view mixin implements both.
-## Why `BasicHealthResource` has no companion
+## Health probes: three flavors, not a mixin/companion pair
-`BasicHealthResource` is intentionally left without a `Basic*Servlet`. It
already extends
-`BasicRestServlet` — it *is* a standalone-capable servlet — and it mounts at
fixed absolute paths
-(`/healthz`, `/readyz`, `/livez`) that don't suffer the prefix-doubling
problem the `/<token>/*`
-mixins do. Adding a companion would be redundant.
+The built-in health/readiness/liveness probe capability
+(`org.apache.juneau.rest.server.health`) is not a
`Basic*Resource`/`Basic*Servlet` dual-use pair
+like the ones in the catalog above — it doesn't need a "companion" because it
was designed from
+the start as **three independent classes**, one per composition primitive, all
delegating to the
+same `HealthAggregator` worker bean so the forms can't drift from each other:
+
+| Class | Flavor | Composition primitive | Mount |
+| --- | --- | --- | --- |
+| `HealthMixin` | Mixin | `@Rest(mixins=HealthMixin.class)` | Grafted into the
host's own URL space at `/healthz`, `/readyz`, `/livez`. |
+| `HealthServlet` | Standalone |
`@Rest(paths={"/healthz","/readyz","/livez"})` | Auto-mounted at those exact
URLs — the `Servlet` bean `HealthProbeConfiguration.healthProbeServlet()`
returns one. |
+| `HealthResource` | Child | `@Rest(path="/health")`, composed via
`@Rest(children=HealthResource.class)` | Under a parent's `/health` subtree,
e.g. `/health/healthz`. |
+
+Where the dual-use catalog above retrofits a thin standalone `Basic*Servlet`
onto an existing
+mixin so both `mixins=` and `paths=` are covered by one delegation pair, the
health family
+instead maps each of the three composition primitives this topic and
+[Mixins and Multi-Mount Paths](/docs/topics/RestServerComposition) document —
`mixins=`,
+`paths=`, and `children=` — onto its own dedicated class. There's no gap to
fill with a
+companion; picking the flavor that matches how you want to compose probes into
your app *is*
+the API. See [Health / Readiness / Liveness Probes](/docs/topics/HealthProbes)
for the worked
+examples of the mixin and standalone options.
## See also
diff --git a/pages/topics/10.29.03.BasicSwaggerInfo.md
b/pages/topics/10.29.03.BasicSwaggerInfo.md
index b28fb1d045..475073b744 100644
--- a/pages/topics/10.29.03.BasicSwaggerInfo.md
+++ b/pages/topics/10.29.03.BasicSwaggerInfo.md
@@ -10,31 +10,34 @@ The top part of the page shows general information about
the REST interface:

The information is pulled from the <a
href="/site/apidocs/org/apache/juneau/rest/server/Rest.html#swagger()"
target="_blank">@Rest(swagger)</a>
-annotation.
+annotation. The real `PetStoreResource` (`juneau-petstore-core`) keeps things
simple and only sets `title`/`description` via `@Rest`
+without a `swagger=` member, so the example below is a self-contained
illustrative resource — not literally the shipping
+`PetStoreResource` — showing the various ways the `@Rest(swagger)` annotation
can be populated.
-## org.apache.juneau.petstore.rest.PetStoreResource
+## Example: pulling Swagger info from an external file
```java
@Rest(
- path="/petstore",
- title="Petstore application",
+ path="/myResource",
+ title="My REST API",
...
- swagger=@Swagger("$F{PetStoreResource.json}"),
+ swagger=@Swagger("$F{MyResource.json}"),
...
)
-public class PetStoreResource extends BasicRestServlet {...}
+public class MyResource extends BasicRestServlet {...}
```
-In this particular case, the Swagger is pulled in from a localized Swagger
JSON file located in the
[org.apache.juneau.petstore.rest](/site/apidocs/org/apache/juneau/petstore/rest/package-summary.html)
package using the <a
href="/site/apidocs/org/apache/juneau/rest/server/vars/FileVar.html"
target="_blank">$F</a> variable.
+In this particular case, the Swagger is pulled in from a localized Swagger
JSON file located alongside the resource class
+using the <a
href="/site/apidocs/org/apache/juneau/rest/server/vars/FileVar.html"
target="_blank">$F</a> variable.
-## PetStoreResource.json
+## MyResource.json
```js
{
"swagger": "2.0",
"info": {
"version": "1.0.0",
- "title": "Swagger Petstore",
+ "title": "My REST API",
"termsOfService": "You are on your own.",
"contact": {
"name": "Juneau Development Team",
@@ -61,8 +64,8 @@ You could equivalently embed JSON directly into your
annotation like so:
```java
@Rest(
- path="/petstore",
- title="Petstore application",
+ path="/myResource",
+ title="My REST API",
...
swagger=@Swagger(
// Raw JSON5.
@@ -75,19 +78,19 @@ You could equivalently embed JSON directly into your
annotation like so:
),
...
)
-public class PetStoreResource extends BasicRestServlet {...}
+public class MyResource extends BasicRestServlet {...}
```
However, a more typical (and less error-prone) scenario is to define all of
your Swagger as annotations:
```java
@Rest(
- path="/petstore",
- title="Petstore application",
+ path="/myResource",
+ title="My REST API",
...
swagger=@Swagger(
version="1.0.0",
- title="Swagger Petstore",
+ title="My REST API",
termsOfService="You are on your own.",
contact=@Contact(
name="Juneau Development Team",
@@ -105,15 +108,15 @@ However, a more typical (and less error-prone) scenario
is to define all of your
),
...
)
-public class PetStoreResource extends BasicRestServlet {...}
+public class MyResource extends BasicRestServlet {...}
```
All annotations support SVL Variables, so you could for example pull localized
strings from resource bundles using <a
href="/site/apidocs/org/apache/juneau/rest/server/vars/LocalizationVar.html"
target="_blank">$L</a> variables.
```java
@Rest(
- path="/petstore",
- title="Petstore application",
+ path="/myResource",
+ title="My REST API",
messages="nls/MyMessages",
...
swagger=@Swagger(
@@ -136,18 +139,18 @@ All annotations support SVL Variables, so you could for
example pull localized s
),
...
)
-public class PetStoreResource extends BasicRestServlet {...}
+public class MyResource extends BasicRestServlet {...}
```
A third option is to define your Swagger information in your <a
href="/site/apidocs/org/apache/juneau/rest/server/Rest.html#messages()"
target="_blank">@Rest(messages)</a> resource bundle using predefined Swagger
keywords:
```ini
-PetStoreResource.version = 1.0.0
-PetStoreResource.title = Swagger Petstore
-PetStoreResource.termsOfService = You are on your own.
-PetStoreResource.contact = {name:'Juneau Development Team',
email:'[email protected]',...}
-PetStoreResource.license = {name:'Apache 2.0',...}
-PetStoreResource.externalDocs = {description:'Find out more about Juneau',...}
+MyResource.version = 1.0.0
+MyResource.title = My REST API
+MyResource.termsOfService = You are on your own.
+MyResource.contact = {name:'Juneau Development Team',
email:'[email protected]',...}
+MyResource.license = {name:'Apache 2.0',...}
+MyResource.externalDocs = {description:'Find out more about Juneau',...}
```
Information defined in multiple locations are merged into a single set of data.
diff --git a/pages/topics/10.29.04.SwaggerTags.md
b/pages/topics/10.29.04.SwaggerTags.md
index 2b3f0b95cf..b7ff232191 100644
--- a/pages/topics/10.29.04.SwaggerTags.md
+++ b/pages/topics/10.29.04.SwaggerTags.md
@@ -10,9 +10,12 @@ In the example below, the `pet` and `store` tag sections are
collapsed and the `

-Tags are also defined in the <a
href="/site/apidocs/org/apache/juneau/rest/server/Swagger.html"
target="_blank">@Swagger</a> annotation
+Tags are also defined in the <a
href="/site/apidocs/org/apache/juneau/rest/server/Swagger.html"
target="_blank">@Swagger</a> annotation.
-## PetStoreResource.json
+The real `PetStoreResource` (`juneau-petstore-core`) doesn't currently declare
Swagger tags, so the following continues the
+illustrative `MyResource` example from the previous section:
+
+## MyResource.json
```json
"tags": [
@@ -41,7 +44,7 @@ Tags are also defined in the <a
href="/site/apidocs/org/apache/juneau/rest/serve
The annotation-only approach is shown here:
-## org.apache.juneau.petstore.rest.PetStoreResource
+## MyResource
```java
swagger=@Swagger(
@@ -73,26 +76,24 @@ swagger=@Swagger(
Tags are associated with operations using the <a
href="/site/apidocs/org/apache/juneau/rest/server/OpSwagger.html#tags()"
target="_blank">@OpSwagger(tags)</a> annotation:
-## GET /user operation
+## GET /users operation
```java
@RestGet(
- path="/user",
+ path="/users",
summary="Petstore users",
swagger=@OpSwagger(
tags="user"
)
)
-public Collection getUsers() throws NotAcceptable {...}
+public Collection<User> getUsers() {...}
```
Operations can be mapped to multiple tags.
Tags are optional.
-Operations not mapped to tags are listed in the UI before tagged operations.
-
-For example, the `getTopPage()` method in `PetStoreResource` is not tagged, as
well as the `getOptions()` method
-inherited from `BaseRestServlet`, so these show up at the top of the page:
+Operations not mapped to tags are listed in the UI before tagged operations,
as well as any built-in endpoints (such as
+`OPTIONS`) inherited from `BasicRestServlet`, so these show up at the top of
the page:

diff --git a/pages/topics/10.29.05.SwaggerOperations.md
b/pages/topics/10.29.05.SwaggerOperations.md
index 877d746cca..62b1e83737 100644
--- a/pages/topics/10.29.05.SwaggerOperations.md
+++ b/pages/topics/10.29.05.SwaggerOperations.md
@@ -5,13 +5,14 @@ slug: SwaggerOperations
<a href="/site/apidocs/org/apache/juneau/rest/server/RestOp.html"
target="_blank">@RestOp</a>-annotated methods automatically get rendered as
Swagger operations.
-The following shows the annotations defined on the `GET /pet` operation:
+The following shows the annotations defined on the `GET /pets` operation. The
real `PetStoreResource` (`juneau-petstore-core`)
+doesn't currently add `@OpSwagger` tags to this method, so `tags="pet"` below
is illustrative of how you'd add them:
## PetStoreResource.getPets()
```java
@RestGet(
- path="/pet",
+ path="/pets",
summary="All pets in the store",
swagger=@OpSwagger(
tags="pet",
@@ -19,23 +20,23 @@ The following shows the annotations defined on the `GET
/pet` operation:
),
...
)
-public Collection getPets() throws NotAcceptable {
+public Collection<Pet> getPets() {
return store.getPets();
}
```
Methods marked as deprecated will show up as deprecated in the Swagger UI:
-s
-## PetStoreResource.findPetsByTag()
+
+## Deprecated operation example
```java
@RestGet(
- path="/pet/findByTags",
- summary="Finds Pets by tags",
+ path="/pets/legacySearch",
+ summary="Legacy pet search (use query parameters on GET /pets instead)",
...
)
@Deprecated
-public Collection findPetsByTags(...) {
+public Collection<Pet> legacySearch(...) {
...
}
```
diff --git a/pages/topics/10.29.06.SwaggerParameters.md
b/pages/topics/10.29.06.SwaggerParameters.md
index 8cf13cfd4e..8882d03492 100644
--- a/pages/topics/10.29.06.SwaggerParameters.md
+++ b/pages/topics/10.29.06.SwaggerParameters.md
@@ -10,7 +10,7 @@ The typical way is through annotations on parameters being
passed to your <a hre
```java
@RestGet
-public Collection getPets(
+public Collection<Pet> getPets(
@Query(
name="s",
schema=@Schema(
@@ -39,7 +39,7 @@ public Collection getPets(
)
String[] v,
...
- ) throws NotAcceptable {
+ ) {
...
}
```
@@ -51,57 +51,81 @@ public Collection getPets(
Another option is to specify your parameter information in the `parameters`
annotation as free-form JSON 5.
-In the case of the `PetStoreResource.getPets()` method, we pull this
information from a static field defined in the <a
href="/site/apidocs/org/apache/juneau/rest/server/converter/Queryable.html"
target="_blank">Queryable</a> class:
+The <a
href="/site/apidocs/org/apache/juneau/rest/server/converter/Queryable.html"
target="_blank">Queryable</a> converter class ships a
+canned `SWAGGER_PARAMS` constant with this exact information pre-built, so
resources that use `Queryable` don't have to hand-write it.
+`LogsResource` (`juneau-microservice-examples`) does exactly this:
-## PetStoreResource.getPets()
+## LogsResource.viewParsedEntries()
```java
-@RestGet(
- path="/pet",
- summary="All pets in the store",
+@RestOp(
+ method="PARSE",
+ path="/*",
+ summary="View parsed contents of file",
+ converters=Queryable.class,
swagger=@OpSwagger(
- tags="pet",
parameters={
Queryable.SWAGGER_PARAMS
}
- ),
- ...
- converters={Queryable.class}
+ )
)
-public Collection getPets() throws NotAcceptable {
- return store.getPets();
+public LogParser viewParsedEntries(...) {
+ ...
}
```
-## Queryable
+## Queryable.SWAGGER_PARAMS
```java
public class Queryable implements RestConverter {
- public static final String SWAGGER_PARAMS=""
- + "{"
- + "in:'query',"
- + "name:'s',"
- + "description:'"
- + "Search.\n"
- + "Key/value pairs representing column names and search
tokens.\n"
- + "\\'*\\' and \\'?\\' can be used as meta-characters in
string fields.\n"
- + "\\'>\\', \\'>=\\', \\'2000'}"
- + "},"
- + "{"
- + "in:'query',"
- + "name:'v',"
- + "description:'"
- + "View.\n"
- + "Column names to display."
- + "',"
- + "type:'array',"
- + "collectionFormat:'csv',"
- + "x-examples:{example:'?v=name,birthDate'}"
- + "},"
-
- ...
- ;
+ public static final String SWAGGER_PARAMS = """
+ {
+ in:'query',
+ name:'s',
+ description:'Search.
+ Key/value pairs representing column names and search tokens.
+ \'*\' and \'?\' can be used as meta-characters in string
fields.
+ \'>\', \'>=\', \'<\', and \'<=\' can be used as limits on
numeric and date fields.
+ Date fields can be matched with partial dates (e.g. \'2018\'
to match any date in the year 2018).',
+ type:'array',
+ collectionFormat:'csv',
+ examples:{example:'?s=Bill*,birthDate>2000'}
+ },{
+ in:'query',
+ name:'v',
+ description:'View.
+ Column names to display.',
+ type:'array',
+ collectionFormat:'csv',
+ examples:{example:'?v=name,birthDate'}
+ },{
+ in:'query',
+ name:'o',
+ description:'Order by.
+ Columns to sort by.
+ Column names can be suffixed with \'+\' or \'-\' to indicate
ascending or descending order.
+ The default is ascending order.',
+ type:'array',
+ collectionFormat:'csv',
+ examples:{example:'?o=name,birthDate-'}
+ },{
+ in:'query',
+ name:'p',
+ description:'Position.
+ Only return rows starting at the specified index position
(zero-indexed).
+ Default is 0',
+ type:'integer',
+ examples:{example:'?p=100'}
+ },{
+ in:'query',
+ name:'l',
+ description:'Limit.
+ Only return the specified number of rows.
+ Default is 0 (meaning return all rows).',
+ type:'integer',
+ examples:{example:'?l=100'}
+ }""";
}
```
@@ -111,19 +135,18 @@ The parameter section contains information about the
request body as well for PU
```java
@RestPost(
+ path="/pets",
summary="Add a new pet to the store",
swagger=@OpSwagger(
tags="pet"
)
)
-public Ok postPet(
+public Pet createPet(
@Content
@Schema(description="Pet object to add to the store")
- PetCreate pet
- ) throws IdConflict, NotAcceptable, UnsupportedMediaType {
-
- store.create(pet);
- return OK;
+ Pet pet
+ ) {
+ return store.createPet(pet);
}
```
diff --git a/pages/topics/10.29.07.SwaggerResponses.md
b/pages/topics/10.29.07.SwaggerResponses.md
index 265b729478..f744a6bda6 100644
--- a/pages/topics/10.29.07.SwaggerResponses.md
+++ b/pages/topics/10.29.07.SwaggerResponses.md
@@ -9,11 +9,11 @@ The `200` response is determined by the return type on the
method, in this case
```java
@RestGet(
- path="/pet",
+ path="/pets",
summary="All pets in the store",
...
)
-public Collection getPets() throws NotAcceptable {
+public Collection<Pet> getPets() {
return store.getPets();
}
```
diff --git a/pages/topics/10.31.00.HtmlDocConfigAnnotation.md
b/pages/topics/10.31.00.HtmlDocConfigAnnotation.md
index 2c361a0c90..522a02c169 100644
--- a/pages/topics/10.31.00.HtmlDocConfigAnnotation.md
+++ b/pages/topics/10.31.00.HtmlDocConfigAnnotation.md
@@ -73,7 +73,9 @@ structure:
The outline above is controlled by the <a
href="/site/apidocs/org/apache/juneau/marshall/html/HtmlDocTemplate.html"
target="_blank">HtmlDocTemplate</a>
interface which can be overridden via the <a
href="/site/apidocs/org/apache/juneau/marshall/html/HtmlDocConfig.html#template()"
target="_blank">@HtmlDocConfig(template)</a> annotation.
-The `HelloWorldResource` class was an example of the <a
href="/site/apidocs/org/apache/juneau/marshall/html/HtmlDocConfig.html"
target="_blank">@HtmlDocConfig</a> annotation in use:
+Here's a minimal, self-contained example of the <a
href="/site/apidocs/org/apache/juneau/marshall/html/HtmlDocConfig.html"
target="_blank">@HtmlDocConfig</a> annotation
+in use. (The `HelloWorldResource` class it's modeled after was part of the
now-removed `juneau-examples-rest` module; this snippet is
+illustrative and not tied to a currently-shipping class.)
```java
// Sample REST resource that prints out a simple "Hello world!" message.
@@ -82,7 +84,7 @@ The `HelloWorldResource` class was an example of the <a
href="/site/apidocs/org/
title="Hello World",
description="An example of the simplest-possible resource"
)
-@HtmlDoc(
+@HtmlDocConfig(
navlinks={
"up: request:/..",
"options: servlet:/?method=OPTIONS"
@@ -94,7 +96,6 @@ The `HelloWorldResource` class was an example of the <a
href="/site/apidocs/org/
"</div>"
}
)
-@MarshalledConfig(sortProperties="true")
public class HelloWorldResource extends BasicRestServlet {
@RestGet(path="/*", summary="Responds with \"Hello world!\"")
@@ -117,7 +118,7 @@ SVL variables can be used in any of these annotations:
"up: request:/..",
"options: servlet:/?method=OPTIONS",
// Add a nav link to view the source code for this class.
- "source:
$C{Source/gitHub}/org/apache/juneau/examples/rest/$R{servletClassSimple}.java"
+ "source:
$C{Source/gitHub}/org/apache/juneau/petstore/jetty/$R{servletClassSimple}.java"
},
aside={
// Localize our messages.
diff --git a/pages/topics/10.31.03.HtmlPredefinedWidgets.md
b/pages/topics/10.31.03.HtmlPredefinedWidgets.md
index fb68b7578f..4ad152c968 100644
--- a/pages/topics/10.31.03.HtmlPredefinedWidgets.md
+++ b/pages/topics/10.31.03.HtmlPredefinedWidgets.md
@@ -29,14 +29,14 @@ For example, to render a link that brings up a simple
dialog in a `div` tag:
```java
@Override
-public String getLabel() {
+public String getLabel(RestRequest req, RestResponse res) {
return "my-menu-item";
-};
+}
@Override
-public Div getContent() {
- return Html5Builder.div("Surprise!").style("color:red");
-};
+public Object getContent(RestRequest req, RestResponse res) {
+ return HtmlBuilder.div("Surprise!").style("color:red");
+}
```
The HTML content returned by the <a
href="/site/apidocs/org/apache/juneau/rest/server/widget/MenuItemWidget.html#getHtml(org.apache.juneau.rest.server.RestRequest,org.apache.juneau.rest.server.RestResponse)"
target="_blank">getHtml(RestRequest,RestResponse)</a> method is added where
the `$W{...}` is referenced in the page.
@@ -47,25 +47,27 @@ The HTML content returned by the <a
href="/site/apidocs/org/apache/juneau/rest/s
returns back a list of hyperlinks for rendering the contents of a page in a
variety of content types.
The variable it resolves is `$W{ContentTypeMenuItem}`.
-An example of this widget can be found in the `PetStoreResource` in the
examples that provides a drop-down menu item for
-rendering all other supported content types in plain text:
+An example of this widget can be found in `RootResources`
(`juneau-petstore-jetty`), which provides a drop-down menu item for
+rendering the current page's contents in a variety of content types:
```java
-@RestGet(path="/")
+@Rest(
+ title="Juneau Petstore (Jetty)",
+ description="Apache Juneau petstore sample application running under
Jetty/Microservice.",
+ children={...}
+)
@HtmlDocConfig(
widgets={
- ContentTypeMenuItem.class,
+ ContentTypeMenuItem.class
},
navlinks={
- "up: ...",
- "options: ...",
- "$W{QueryMenuItem}",
+ "api: servlet:/api",
+ "stats: servlet:/stats",
"$W{ContentTypeMenuItem}",
- "$W{ThemeMenuItem}",
- "source: ..."
+ "source:
$C{Source/gitHub}/org/apache/juneau/petstore/jetty/RootResources.java"
}
)
-public Collection getPets() {
+public class RootResources extends BasicRestServletGroup {...}
```
It renders the following popup-box:
@@ -80,28 +82,33 @@ The variable it resolves is `$W{QueryMenuItem}`.
This widget is designed to be used in conjunction with the <a
href="/site/apidocs/org/apache/juneau/rest/server/converter/Queryable.html"
target="_blank">Queryable</a> converter, although implementations can process
the query parameters themselves if they wish to do so by using the <a
href="/site/apidocs/org/apache/juneau/rest/server/httppart/RequestQueryParamList.html#getSearchArgs()"
target="_blank">RequestQueryParamList.getSearchArgs()</a> method to retrieve
the arguments and process [...]
-An example of this widget can be found in the `PetStoreResource` in the
examples that provides search/view/sort
-capabilities against the collection of POJOs:
+Neither of the currently-shipping petstore resources pairs this widget with
the `Queryable` converter, so the following is a
+self-contained, minimal illustrative example rather than a citation of an
existing class:
```java
-@RestGet(
- path="/",
- converters=Queryable.class
-)
-@HtmlDocConfig(
- widgets={
- QueryMenuItem.class,
- },
- navlinks={
- "up: ...",
- "options: ...",
- "$W{QueryMenuItem}",
- "$W{ContentTypeMenuItem}",
- "$W{ThemeMenuItem}",
- "source: ..."
+@Rest
+public class MyResource extends BasicRestServlet {
+
+ @RestGet(
+ path="/",
+ converters=Queryable.class
+ )
+ @HtmlDocConfig(
+ widgets={
+ QueryMenuItem.class,
+ },
+ navlinks={
+ "up: request:/..",
+ "options: ?method=OPTIONS",
+ "$W{QueryMenuItem}",
+ "$W{ContentTypeMenuItem}",
+ "$W{ThemeMenuItem}"
+ }
+ )
+ public Collection<MyBean> getBeans() {
+ ...
}
-)
-public Collection getPets() {
+}
```
It renders the following popup-box:
@@ -123,25 +130,23 @@ against `collections` of POJOs.
a list of hyperlinks for rendering the contents of a page in the various
default styles.
The variable it resolves is `$W{ThemeMenuItem}`.
-An example of this widget can be found in the `PetStoreResource` in the
examples that provides a drop-down menu item for
-rendering all other supported content types in plain text:
+Here's a minimal example that adds it to a resource's nav bar:
```java
-@RestGet(path="/")
+@Rest
@HtmlDocConfig(
widgets={
ThemeMenuItem.class,
},
navlinks={
- "up: ...",
- "options: ...",
+ "up: request:/..",
+ "options: ?method=OPTIONS",
"$W{QueryMenuItem}",
"$W{ContentTypeMenuItem}",
- "$W{ThemeMenuItem}",
- "source: ..."
+ "$W{ThemeMenuItem}"
}
)
-public Collection getPets() {
+public class MyResource extends BasicRestServlet {...}
```
## PoweredByJuneau
@@ -150,16 +155,17 @@ public Collection getPets() {
powered-by-Juneau message on a page.
The variable it resolves is `$W{PoweredByJuneau}`.
It produces a simple Apache Juneau icon floating on the right.
-Typically it's used in the footer of the page, as shown below in the
`AddressBookResource` from the examples:
+Typically it's used in the footer of the page, as shown in this minimal
example:
```java
-@Rest(path="/addressBook")
+@Rest(path="/myResource")
@HtmlDocConfig(
widgets={
PoweredByJuneau.class
},
footer="$W{PoweredByJuneau}"
)
+public class MyResource extends BasicRestServlet {...}
```
It renders the following image:
@@ -177,14 +183,14 @@ The following examples shows how tooltips can be added to
a menu item widget.
public class MyFormMenuItem extends MenuItemWidget {
@Override
- public String getLabel(RestRequest req) throws Exception {
+ public String getLabel(RestRequest req, RestResponse res) {
return "myform";
}
@Override
- public Object getContent(RestRequest req) throws Exception {
+ public Object getContent(RestRequest req, RestResponse res) {
return div(
- form().id("form").action("servlet:/form").method(POST).children(
+ form().id("form").action("servlet:/form").method("post").children(
table(
tr(
th("Field 1:"),
diff --git a/pages/topics/10.31.04.HtmlUiCustomization.md
b/pages/topics/10.31.04.HtmlUiCustomization.md
index 69c6ad04f5..214c5469a8 100644
--- a/pages/topics/10.31.04.HtmlUiCustomization.md
+++ b/pages/topics/10.31.04.HtmlUiCustomization.md
@@ -56,7 +56,8 @@ public interface BasicUniversalConfig {}
```
Notice how this is implemented using nested <a
href="/site/apidocs/org/apache/juneau/marshall/html/HtmlDocConfig.html"
target="_blank">@HtmlDocConfig</a> annotations nested within parent
configurations.
-A simpler approach is to implement your interface on your REST resource class.
+A simpler approach is to implement your interface on your REST resource class,
as shown in this illustrative example modeled
+after `RootResources` (`juneau-petstore-jetty`), a router page extending <a
href="/site/apidocs/org/apache/juneau/rest/server/servlet/BasicRestServletGroup.html"
target="_blank">BasicRestServletGroup</a>:
```java
@Rest(...)
@@ -69,7 +70,7 @@ A simpler approach is to implement your interface on your
REST resource class.
"options: ?method=OPTIONS",
"$W{ContentTypeMenuItem}",
"$W{ThemeMenuItem}",
- "source:
$C{Source/gitHub}/org/apache/juneau/examples/rest/$R{servletClassSimple}.java"
+ "source:
$C{Source/gitHub}/org/apache/juneau/petstore/jetty/$R{servletClassSimple}.java"
},
aside={
"<div class='text'>",
diff --git a/pages/topics/10.31.05.HtmlStylesheets.md
b/pages/topics/10.31.05.HtmlStylesheets.md
index 54996a62ed..e8ebe044b9 100644
--- a/pages/topics/10.31.05.HtmlStylesheets.md
+++ b/pages/topics/10.31.05.HtmlStylesheets.md
@@ -56,7 +56,9 @@ public class MyResourceBaseClass extends BasicRestServlet
{...}
You can try out different stylesheets by passing in a `stylesheet` attribute
in the request URL.
The example above show this in use.
-In case you're curious about how the menu item works, it's defined via a
widget:
+In case you're curious about how the menu item works, it's defined via a
widget. The predefined
+<a
href="/site/apidocs/org/apache/juneau/rest/server/widget/ThemeMenuItem.html"
target="_blank">ThemeMenuItem</a> widget (see
+[Predefined Widgets](/docs/topics/HtmlPredefinedWidgets)) is exactly this
style-switcher, so a resource wires it up like so:
```java
@Rest(...)
@@ -64,42 +66,40 @@ In case you're curious about how the menu item works, it's
defined via a widget:
widgets={
PoweredByApache.class,
ContentTypeMenuItem.class,
- StyleMenuItem.class
+ ThemeMenuItem.class
},
navlinks={
"options: ?method=OPTIONS",
"$W{ContentTypeMenuItem}",
- "$W{StyleMenuItem}",
- "source:
$C{Source/gitHub}/org/apache/juneau/examples/rest/$R{servletClassSimple}.java"
+ "$W{ThemeMenuItem}",
+ "source:
$C{Source/gitHub}/org/apache/juneau/petstore/jetty/$R{servletClassSimple}.java"
}
)
public class RootResources extends BasicRestServletGroup {...}
```
-The `StyleMenuItem` is a widget that extends from <a
href="/site/apidocs/org/apache/juneau/rest/server/widget/MenuItemWidget.html"
target="_blank">MenuItemWidget</a>, a specialized widget for creating pop-up
menus.
+`ThemeMenuItem` extends <a
href="/site/apidocs/org/apache/juneau/rest/server/widget/MenuItemWidget.html"
target="_blank">MenuItemWidget</a>, a specialized widget for creating pop-up
menus.
-In the case of `StyleMenuItem`, it's simply returning a list of links wrapped
in a `div` tag:
+Here's its actual implementation — simply a list of links wrapped in a `div`
tag:
```java
-import static org.apache.juneau.bean.html5.HtmlBuilder.*;
+public class ThemeMenuItem extends MenuItemWidget {
-public class StyleMenuItem extends MenuItemWidget {
+ private static final String[] BUILT_IN_STYLES = { "devops", "light",
"original", "dark" };
- private static final String[] BUILT_IN_STYLES = {"devops", "light",
"original", "dark"};
-
- @Override /* Widget */
- public String getLabel(RestRequest req) {
- return "styles";
- }
-
- @Override /* MenuItemWidget */
- public Div getContent(RestRequest req) throws Exception {
+ @Override /* Overridden from MenuItemWidget */
+ public Div getContent(RestRequest req, RestResponse res) {
Div div = div();
- for (String style : BUILT_IN_STYLES) {
- java.net.URI uri = req.getUri(true, new
AMap().append("stylesheet", "styles/"+s+".css"));
- div.children(a(uri, style), br());
+ for (var s : BUILT_IN_STYLES) {
+ java.net.URI uri = req.getUri(true,
CollectionUtils.<String,Object>map("stylesheet", "htdocs/themes/" + s +
".css"));
+ div.children(a(uri, s), br());
}
return div;
}
+
+ @Override /* Overridden from Widget */
+ public String getLabel(RestRequest req, RestResponse res) {
+ return "themes";
+ }
}
```
\ No newline at end of file
diff --git a/pages/topics/13.09.08.Request.md b/pages/topics/13.09.08.Request.md
index 05b4285cf0..3b12730820 100644
--- a/pages/topics/13.09.08.Request.md
+++ b/pages/topics/13.09.08.Request.md
@@ -38,7 +38,7 @@ public class CreatePetRequest {
@Query
public Map getQueryParams() {
- return AMap.of("debug", true);
+ return JsonMap.of("debug", true);
}
@Header("E-Tag")
diff --git a/pages/topics/13.13.02.AuthenticationForm.md
b/pages/topics/13.13.02.AuthenticationForm.md
index 88b845e9b3..08ab481e36 100644
--- a/pages/topics/13.13.02.AuthenticationForm.md
+++ b/pages/topics/13.13.02.AuthenticationForm.md
@@ -40,7 +40,7 @@ private void formBasedAuthenticate(HttpClient client) throws
IOException {
// Charset must explicitly be set to UTF-8 to handle user/pw with
non-ascii characters.
request.addHeader("Content-Type", "application/x-www-form-urlencoded;
charset=utf-8");
- List params = AList.of(
+ List params = List.of(
BasicNameValuePair.of("j_username", user),
BasicNameValuePair.of("j_password", pw)
);
diff --git a/pages/topics/13.13.03.AuthenticationOIDC.md
b/pages/topics/13.13.03.AuthenticationOIDC.md
index 0f693b1717..45b829aec1 100644
--- a/pages/topics/13.13.03.AuthenticationOIDC.md
+++ b/pages/topics/13.13.03.AuthenticationOIDC.md
@@ -105,7 +105,7 @@ private void oidcAuthenticate(HttpClient client) throws
IOException {
BasicStringHeader.of("Cookie", cookie)
};
- setDefaultHeaders(AList.of(defaultHeaders));
+ setDefaultHeaders(List.of(defaultHeaders));
} finally {
EntityUtils.consume(response.getEntity());
diff --git a/pages/topics/16.09.HealthProbes.md
b/pages/topics/16.09.HealthProbes.md
index b33557d101..b5e4eb5214 100644
--- a/pages/topics/16.09.HealthProbes.md
+++ b/pages/topics/16.09.HealthProbes.md
@@ -14,10 +14,15 @@ Starting with **9.5.0**, Juneau provides an opt-in probe
surface for Jetty micro
Probe routing now has two supported integration styles:
- **Preferred:** mix probe operations into your existing root resource with
- `@Rest(mixins=BasicHealthResource.class)`.
+ `@Rest(mixins=HealthMixin.class)`.
- **Fallback:** standalone probe servlet auto-mounted at explicit
`@Rest(paths={...})` path specs
(`/healthz`, `/readyz`, `/livez`) via `HealthProbeConfiguration`.
+> A third flavor, `HealthResource`, mounts the same three probes as a routed
child
+> (`@Rest(children=HealthResource.class)`) under a parent's `/health` subtree
— see
+> [REST Server — Standalone vs Mixin
Resources](/docs/topics/RestServerStandaloneVsMixin#health-probes-three-flavors-not-a-mixincompanion-pair)
+> for how the three flavors relate.
+
This avoids root-path collisions when your app already owns `@Rest(path="/")`.
The endpoints aggregate every `HealthIndicator` bean from the microservice
bean store and return an
@@ -56,7 +61,7 @@ import org.apache.juneau.rest.server.servlet.*;
@Rest(
path="/",
- mixins=BasicHealthResource.class
+ mixins=HealthMixin.class
)
public class RootResources extends BasicRestServlet {
@Bean(name="dbHealth")
@@ -113,7 +118,7 @@ public class App {
}
```
-`HealthProbeConfiguration` contributes a `Servlet` bean
(`BasicHealthResource`) and Jetty mounts it
+`HealthProbeConfiguration` contributes a `Servlet` bean (`HealthServlet`) and
Jetty mounts it
at the three explicit path specs declared on the resource via
`@Rest(paths={...})`.
## `HealthIndicator` SPI