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 e0b908ced9 Secure ObjectIntrospector by default, dedupe
HtdocMixin/StaticFilesMixin, add 27 marshaller facade variants (TODO-351
Section B)
e0b908ced9 is described below
commit e0b908ced9edffab3b65fe056dc33c099ed4cfcf
Author: James Bognar <[email protected]>
AuthorDate: Thu Aug 13 08:20:48 2026 -0400
Secure ObjectIntrospector by default, dedupe HtdocMixin/StaticFilesMixin,
add 27 marshaller facade variants (TODO-351 Section B)
---
pages/release-notes/10.0.0.md | 49 ++++++++
pages/topics/01.00.JuneauEcosystemOverview.md | 2 +-
pages/topics/01.02.WhyJuneau.md | 4 +-
pages/topics/02.03.JuneauCommonsLang.md | 20 +++
pages/topics/02.15.JuneauCommonsLogging.md | 2 +-
pages/topics/03.01.Marshallers.md | 54 +++++++--
pages/topics/03.24.ObjectTools.md | 81 ++++++++++++-
pages/topics/03.43.Cbor.md | 6 +-
pages/topics/10.20.StaticFiles.md | 20 +--
pages/topics/10.21.StaticFilesMixin.md | 168 ++++++++++----------------
pages/topics/13.14.NextGenRestClient.md | 28 ++++-
pages/topics/18.01.ScServerOverview.md | 20 ++-
src/pages/about.md | 4 +-
static/ai/juneau-knowledge.jsonl | 8 +-
static/ai/manifest.json | 4 +-
15 files changed, 319 insertions(+), 151 deletions(-)
diff --git a/pages/release-notes/10.0.0.md b/pages/release-notes/10.0.0.md
index 6cc19567fd..bfda00ed30 100644
--- a/pages/release-notes/10.0.0.md
+++ b/pages/release-notes/10.0.0.md
@@ -687,6 +687,28 @@ These replace the former `Json5.DEFAULT_READABLE`,
`Ini.DEFAULT_READABLE`, and `
constants (see Breaking Changes below). The
[Marshallers](/docs/topics/Marshallers), [JSON5](/docs/topics/Json5),
[Hjson](/docs/topics/Hjson), and [Ini](/docs/topics/Ini) topic pages were
updated accordingly.
+### Additional variant marshaller classes for full format symmetry (TODO-351
B-marshall-7)
+
+Every remaining non-default `*Serializer.DEFAULT_*` / `*Parser.DEFAULT_*`
configuration across all marshaller
+formats now has its own first-class **variant facade class**, extending the
`Json5R`/`IniR`/`HjsonC` pattern
+above to full symmetry. This is a purely **additive** change — no existing
class or constant was removed or
+modified. 27 new variant classes were added:
+
+- **Readable variants:** `JsonR`, `TomlR`, `YamlR`, `PrototextR`, `UonR`,
`UrlEncodingR`, `XmlSqR`, `XmlNsSqR`, `HtmlSqR`.
+- **UON:** `UonE` (percent-encoding).
+- **URL-encoding:** `UrlEncodingPlain` (unencoded value parts),
`UrlEncodingExpanded` (repeated `key=value` for arrays/collections).
+- **HOCON:** `HoconBraces` (root `{ }` braces), `HoconC` (compact).
+- **XML:** `XmlSq` (single-quoted attrs), `XmlNs` (namespace-aware), `XmlNsSq`
(namespace + single-quoted).
+- **HTML:** `HtmlSq` (single-quoted attrs), `HtmlSimpleSq` (single-quoted +
JSON type-hint tags disabled).
+- **Binary formats (`Bson`/`Cbor`/`MsgPack`):** `*SpacedHex` and `*Base64`
(alternate `byte[]` wire representations), plus `CborNative`/`MsgPackNative`
(native-mode parsing — exposes low-level CBOR tag / MessagePack extension-type
info; pairs the plain serializer with the native-mode parser).
+
+```java
+String readable = JsonR.of(myPojo); // readable (indented) JSON
+byte[] cbor = CborSpacedHex.of(myPojo); // spaced-hex byte[] binary
format
+```
+
+See the [Marshallers](/docs/topics/Marshallers) topic page for the full
variant-class table.
+
### MCP (Model Context Protocol) support (new modules)
Juneau's first [Model Context Protocol](https://modelcontextprotocol.io/)
support lands in 10.0.0 across four new modules. (An earlier MCP write-up
appeared in the draft, unreleased `9.5.0` notes describing a single-revision
`juneau-bean-mcp` / `juneau-rest-server-mcp` pair; MCP itself had not shipped
in any released Juneau version at that point, so that content has been
withdrawn from `9.5.0` and replaced by this re-layered design, which lands for
the first time here.) The implementatio [...]
@@ -1200,6 +1222,33 @@ See
[juneau-rest-server-mcp](/docs/topics/JuneauRestServerMcp#resource-templates
- **`XmlSerializer.DEFAULT_XS_NAMESPACE` removed (TODO-238).** This unused
`protected` namespace constant (`xs` → `http://www.w3.org/2001/XMLSchema`) had
no consumers anywhere in the framework. `DEFAULT_JUNEAU_NAMESPACE` is
unaffected. **Migration:** none expected for normal usage; any external
subclass that referenced the constant should declare its own namespace via
`Namespace.of("xs", "http://www.w3.org/2001/XMLSchema")`.
- **`@ParentProperty` through collections/maps now injects the enclosing bean
(behavioral change) (TODO-291).** Previously, when a bean annotated with
`@ParentProperty` was nested inside a `List`, `Set`, array, or `Map` — rather
than being a direct bean property — the parser injected the
immediately-containing container (e.g. the `JsonList`/`JsonMap`) into the
`@ParentProperty` member. As of 10.0.0, the parser instead injects the nearest
enclosing *bean*, skipping all intermediate contai [...]
+- **`ObjectIntrospector` is now secure-by-default: reflective method dispatch
is denied unless explicitly allow-listed (behavioral change / security)
(TODO-351 B-marshall-6).**
`org.apache.juneau.marshall.objecttools.ObjectIntrospector.invokeMethod(...)`
(in all of its overloaded forms) previously invoked **any** public,
non-deprecated method resolved from a string signature (or an already-resolved
`java.lang.reflect.Method`) with no restriction — a
"reflective-invoke-over-the-wire" surf [...]
+ - **New allow-list API:** `allow(Class<?> declaringClass, String...
signatures)` allow-lists specific method signatures (as returned by
`MethodInfo#getSignature()`, e.g. `"getName"`, `"substring(int,int)"`) declared
on (or inherited by) the given class; `allow(Predicate<Method> filter)`
allow-lists any method matching an arbitrary predicate. Both can be called
multiple times — the filters are OR'ed together — and return `this` for
chaining.
+ - **Opt-in escape hatch:** `allowAll()` restores the pre-10.0 behavior of
dispatching to any public, non-deprecated method. Use only for trusted,
in-process callers — never on an introspector whose method name/arguments are
sourced from an untrusted caller.
+ - **Migration:**
+ ```java
+ // OLD (9.x) - dispatched to any public, non-deprecated method:
+ ObjectIntrospector.create(bean).invokeMethod("getName", null);
+
+ // NEW (10.0.0) - explicit allow-list (preferred):
+ ObjectIntrospector.create(bean).allow(MyBean.class,
"getName").invokeMethod("getName", null);
+
+ // NEW (10.0.0) - trusted in-process shortcut (one-line migration):
+ ObjectIntrospector.create(bean).allowAll().invokeMethod("getName", null);
+ ```
+ - **`Introspectable` REST response converter (`juneau-rest-server`) is
affected — now with real per-resource allow-list configuration.** This
converter feeds the `invokeMethod`/`invokeArgs` query parameters straight into
`ObjectIntrospector`, so as of 10.0.0 it is **deny-by-default**: with no
configuration, **every** `invokeMethod` request routed through it fails with an
HTTP 500 (`MethodNotAllowlistedException` wrapped in `InternalServerError`)
instead of dispatching. A resource opts [...]
+ ```java
+ @Rest(converters=Introspectable.class)
+ public class MyResource extends BasicRestServlet {
+ @Bean
+ public IntrospectableSettings introspectableSettings() {
+ return IntrospectableSettings.create().allow(MyBean.class,
"getName", "getAge").build();
+ }
+ }
+ ```
+ Applications that relied on `Introspectable` to invoke methods over REST
should register an `IntrospectableSettings` bean allow-listing the specific
methods they need (preferred), or `.allowAll()` on a trusted,
non-internet-facing resource only.
+ - **Unaffected:** argument parsing and return-value casting behavior are
unchanged; only the pre-dispatch allow-list check is new.
+
_Other entries TBD — to be filled in before release. See also the major
version bump note above._
### Deprecations
diff --git a/pages/topics/01.00.JuneauEcosystemOverview.md
b/pages/topics/01.00.JuneauEcosystemOverview.md
index 3be042f055..d0e4de4504 100644
--- a/pages/topics/01.00.JuneauEcosystemOverview.md
+++ b/pages/topics/01.00.JuneauEcosystemOverview.md
@@ -11,7 +11,7 @@ creating annotation-based REST end-to-end server and client
APIs.
## Key Features
-- **Universal Serialization** - Marshal POJOs to 20+ formats from a single
API: JSON (plus JSON5, JSONL, and JSON5L), XML, HTML, URL-Encoding, UON,
OpenAPI, MessagePack, CBOR, BSON, YAML, TOML, HOCON, HJSON, CSV, INI, Markdown,
Parquet, Protobuf, SSE, PlainText, and SOAP — plus RDF/XML, Turtle, N-Triple,
and N3 via juneau-marshall-rdf
+- **Universal Serialization** - Marshal POJOs to 38+ formats from a single
API: JSON (plus JSON5, JSONL, JSON5L, and JCS), XML, SOAP, HTML, URL-Encoding,
UON, OpenAPI, MessagePack, CBOR, BSON, YAML, TOML, HOCON, HJSON, CSV, INI,
Markdown, Parquet, Protobuf, Prototext, SSE, and PlainText — plus 12 RDF
variants (RDF/XML, RDF/XML-Abbrev, RDF/JSON, N-Triples, Turtle, N3, N-Quads,
TriG, TriX, JSON-LD, RDF/Thrift, and RDF/Proto) via juneau-marshall-rdf
- **End-to-End REST** - Annotation-driven REST server and client that share a
single API, with automatic Swagger/OpenAPI generation and self-documenting UIs
- **Transport-Agnostic REST Client** - Pluggable adapters for Apache
HttpClient 4.5/5.x, OkHttp, and Jetty 12, including HTTP/2 request/response
multiplexing and server push
- **DTO Beans** - Ready-made bean models for HTML5, Atom, HAL, JSON:API, JSON
Patch, JSON Schema, OpenAPI v3, Swagger v2, RFC 7807 Problem Details, and MCP
diff --git a/pages/topics/01.02.WhyJuneau.md b/pages/topics/01.02.WhyJuneau.md
index f925812b77..2bdab580bc 100644
--- a/pages/topics/01.02.WhyJuneau.md
+++ b/pages/topics/01.02.WhyJuneau.md
@@ -161,13 +161,13 @@ try (TokenReader r =
Json.DEFAULT.readTokens(inputStream)) {
| Feature | Juneau | Jackson |
|---------|--------|---------|
-| **Formats Supported** | 25+ formats in one library: JSON / JSON5 / JSONL /
JSON5L, XML, HTML, URL-Encoding, UON, OpenAPI, PlainText, CSV, SOAP,
MessagePack, CBOR, BSON, YAML, TOML, HOCON, HJSON, Parquet, SSE, Markdown, INI,
Protobuf, and RDF variants (RDF/XML, N3, NTriple, Turtle) | JSON natively; XML,
YAML, CSV, and others require separate `jackson-dataformat-*` modules |
+| **Formats Supported** | 38+ formats in one library: JSON / JSON5 / JSONL /
JSON5L / JCS, XML, SOAP, HTML, URL-Encoding, UON, OpenAPI, PlainText, CSV,
MessagePack, CBOR, BSON, YAML, TOML, HOCON, HJSON, Parquet, SSE, Markdown, INI,
Protobuf, Prototext, and 12 RDF variants (RDF/XML, RDF/XML-Abbrev, RDF/JSON,
N-Triples, Turtle, N3, N-Quads, TriG, TriX, JSON-LD, RDF/Thrift, RDF/Proto) |
JSON natively; XML, YAML, CSV, and others require separate
`jackson-dataformat-*` modules |
| **REST API Support** | Built-in with automatic Swagger | Requires additional
frameworks |
| **Configuration** | Zero configuration | Requires setup and configuration |
| **Testing Support** | Built-in MockRestClient | Requires external testing
tools |
| **Dependencies** | Self-contained | Separate module per additional format |
-**Juneau Advantage:** A single library covers 25+ formats with one consistent
API — no per-format module juggling.
+**Juneau Advantage:** A single library covers 38+ formats with one consistent
API — no per-format module juggling.
### vs. Spring Boot Web Controllers
diff --git a/pages/topics/02.03.JuneauCommonsLang.md
b/pages/topics/02.03.JuneauCommonsLang.md
index 03bfcb05f7..f9237ae636 100644
--- a/pages/topics/02.03.JuneauCommonsLang.md
+++ b/pages/topics/02.03.JuneauCommonsLang.md
@@ -128,6 +128,26 @@ literally (`{` and `'` are treated as ordinary text). This
applies consistently
[10.0.0 release notes](/docs/release-notes/10.0.0) for migration details.
:::
+#### Which String-Formatting Entry Point Should I Use?
+
+`StringFormat`, `StringUtils.format(...)`/`mformat(...)`, and
`Shorts.f()`/`mf()` all coexist deliberately —
+they're three different call-site shapes over the same two underlying grammars
(printf and MessageFormat),
+not three competing implementations. Use this table to pick the right one:
+
+| Use... | When... |
+|---|---|
+| `Shorts.f(pattern, args)` / `Shorts.mf(pattern, args)` | You want the terse,
one-off, static-import-friendly call — most call sites (logging, exception
messages, assertions). `f` = printf-style, `mf` = MessageFormat-style. |
+| `Shorts.fs(pattern, args)` / `Shorts.mfs(pattern, args)` | Same as above,
but the formatting cost should be deferred — e.g. a logging API that takes a
`Supplier<String>` and only calls it when the log level is enabled. |
+| `StringUtils.format(pattern, args)` / `mformat(pattern, args)` | You're
already in `juneau-commons` code that avoids the `Shorts` static-import
convention, or you want the fully-qualified name for clarity in a public API
signature. `Shorts.f`/`mf` are thin aliases over these two methods — behavior
is identical either way. |
+| `StringFormat.ofPrintf(pattern)` | The **same pattern is reused repeatedly**
(e.g. in a loop, or as a `static final` field) and you want to pay the
pattern-parsing cost once via the built-in cache, rather than re-parsing on
every call. Printf-style only — there is no `StringFormat` MessageFormat
counterpart. |
+
+:::note
+`StringFormat` is the odd one out shape-wise (a stateful/cacheable class, not
a static one-shot method) — reach
+for it only when reuse/caching matters. For everything else,
`Shorts.f`/`mf`/`fs`/`mfs` are the recommended
+entry point; `StringUtils.format`/`mformat` are the methods they delegate to
and remain public for callers
+that prefer explicit, non-abbreviated names.
+:::
+
### <java-class><a
href="/site/apidocs/org/apache/juneau/commons/lang/HashCode.html"
target="_blank">HashCode</a></java-class>
Utility class for generating integer hash codes.
diff --git a/pages/topics/02.15.JuneauCommonsLogging.md
b/pages/topics/02.15.JuneauCommonsLogging.md
index 224207a309..3208f2a8d7 100644
--- a/pages/topics/02.15.JuneauCommonsLogging.md
+++ b/pages/topics/02.15.JuneauCommonsLogging.md
@@ -17,7 +17,7 @@ logger.warning("Low disk space");
```
### <java-class><a
href="/site/apidocs/org/apache/juneau/commons/logging/LogRecord.html"
target="_blank">LogRecord</a></java-class>
-A `java.util.logging.LogRecord` subclass that supports lazy message formatting
— the message string is only built (via `StringUtils.mformat(String,
Object...)`, using `MessageFormat`-style `{0}` placeholders to match the
`java.util.logging` `LogRecord` contract) if the record is actually published.
+A `java.util.logging.LogRecord` subclass that supports lazy message formatting
— the message string is only built (via `StringUtils.mformat(String,
Object...)`, using `MessageFormat`-style `{0}` placeholders to match the
`java.util.logging` `LogRecord` contract) if the record is actually published.
See [Which String-Formatting Entry Point Should I
Use?](/docs/topics/JuneauCommonsLang#which-string-formatting-entry-point-should-i-use)
for how this relates to `StringFormat` and `Shorts.f`/`mf`.
## Test Support
diff --git a/pages/topics/03.01.Marshallers.md
b/pages/topics/03.01.Marshallers.md
index fbca7a7c47..2b47219a07 100644
--- a/pages/topics/03.01.Marshallers.md
+++ b/pages/topics/03.01.Marshallers.md
@@ -134,15 +134,10 @@ try (InputStream in = Files.newInputStream(path)) {
## Variant marshaller classes
-A handful of formats ship dedicated **variant** facade classes for a
commonly-used non-default configuration.
-Each variant is a subclass of its base format facade with its own `DEFAULT`
instance and the full static
-shortcut surface bound to that instance:
-
-<tree>
-<node-0><javac-class><a
href="/site/apidocs/org/apache/juneau/marshall/marshaller/Json5R.html"
target="_blank">Json5R</a></javac-class> — readable (indented) JSON5, backed by
`Json5Serializer.DEFAULT_READABLE`.</node-0>
-<node-0><javac-class><a
href="/site/apidocs/org/apache/juneau/marshall/marshaller/IniR.html"
target="_blank">IniR</a></javac-class> — readable (spaced) INI, backed by
`IniSerializer.DEFAULT_READABLE`.</node-0>
-<node-0><javac-class><a
href="/site/apidocs/org/apache/juneau/marshall/marshaller/HjsonC.html"
target="_blank">HjsonC</a></javac-class> — compact (single-line) Hjson, backed
by `HjsonSerializer.DEFAULT_COMPACT`.</node-0>
-</tree>
+Every format that has a non-default `DEFAULT_*` serializer/parser
configuration ships a corresponding
+dedicated **variant** facade class. Each variant is a subclass of its base
format facade with its own
+`DEFAULT` instance and the full static shortcut surface bound to that instance
— so it exposes the same
+`of(...)` / `to(...)` API (including the stream-based shortcuts above) as any
other marshaller:
```java
// Readable JSON5:
@@ -153,8 +148,45 @@ String compact = HjsonC.of(myPojo);
```
These replace the former `Json5.DEFAULT_READABLE`, `Ini.DEFAULT_READABLE`, and
`Hjson.DEFAULT_COMPACT`
-constants (removed in 10.0.0) — a variant class is a first-class facade, so it
exposes the same static
-`of(...)` / `to(...)` shortcut API (including the stream-based shortcuts
above) as any other marshaller.
+constants (removed in 10.0.0) and extend the same pattern to every other
format for full symmetry.
+
+| Variant class | Base | Backed by | Notes |
+|---|---|---|---|
+| [Json5R](/site/apidocs/org/apache/juneau/marshall/marshaller/Json5R.html) |
[Json5](/site/apidocs/org/apache/juneau/marshall/marshaller/Json5.html) |
`Json5Serializer.DEFAULT_READABLE` | Readable (indented) JSON5 |
+| [JsonR](/site/apidocs/org/apache/juneau/marshall/marshaller/JsonR.html) |
[Json](/site/apidocs/org/apache/juneau/marshall/marshaller/Json.html) |
`JsonSerializer.DEFAULT_READABLE` | Readable (indented) JSON |
+| [IniR](/site/apidocs/org/apache/juneau/marshall/marshaller/IniR.html) |
[Ini](/site/apidocs/org/apache/juneau/marshall/marshaller/Ini.html) |
`IniSerializer.DEFAULT_READABLE` | Readable (spaced) INI |
+| [HjsonC](/site/apidocs/org/apache/juneau/marshall/marshaller/HjsonC.html) |
[Hjson](/site/apidocs/org/apache/juneau/marshall/marshaller/Hjson.html) |
`HjsonSerializer.DEFAULT_COMPACT` | Compact (single-line) Hjson |
+| [TomlR](/site/apidocs/org/apache/juneau/marshall/marshaller/TomlR.html) |
[Toml](/site/apidocs/org/apache/juneau/marshall/marshaller/Toml.html) |
`TomlSerializer.DEFAULT_READABLE` | Readable TOML |
+| [YamlR](/site/apidocs/org/apache/juneau/marshall/marshaller/YamlR.html) |
[Yaml](/site/apidocs/org/apache/juneau/marshall/marshaller/Yaml.html) |
`YamlSerializer.DEFAULT_READABLE` | Readable YAML |
+|
[PrototextR](/site/apidocs/org/apache/juneau/marshall/marshaller/PrototextR.html)
|
[Prototext](/site/apidocs/org/apache/juneau/marshall/marshaller/Prototext.html)
| `PrototextSerializer.DEFAULT_READABLE` | Readable Protobuf Text Format |
+| [UonR](/site/apidocs/org/apache/juneau/marshall/marshaller/UonR.html) |
[Uon](/site/apidocs/org/apache/juneau/marshall/marshaller/Uon.html) |
`UonSerializer.DEFAULT_READABLE` | Readable (multi-line) UON |
+| [UonE](/site/apidocs/org/apache/juneau/marshall/marshaller/UonE.html) |
[Uon](/site/apidocs/org/apache/juneau/marshall/marshaller/Uon.html) |
`UonSerializer.DEFAULT_ENCODING` | Percent-encodes reserved/URL-unsafe
characters |
+|
[UrlEncodingR](/site/apidocs/org/apache/juneau/marshall/marshaller/UrlEncodingR.html)
|
[UrlEncoding](/site/apidocs/org/apache/juneau/marshall/marshaller/UrlEncoding.html)
| `UrlEncodingSerializer.DEFAULT_READABLE` | Readable (whitespace-separated)
URL-encoding |
+|
[UrlEncodingPlain](/site/apidocs/org/apache/juneau/marshall/marshaller/UrlEncodingPlain.html)
|
[UrlEncoding](/site/apidocs/org/apache/juneau/marshall/marshaller/UrlEncoding.html)
| `UrlEncodingSerializer.DEFAULT_PLAINTEXT` | Value parts are not
percent-encoded |
+|
[UrlEncodingExpanded](/site/apidocs/org/apache/juneau/marshall/marshaller/UrlEncodingExpanded.html)
|
[UrlEncoding](/site/apidocs/org/apache/juneau/marshall/marshaller/UrlEncoding.html)
| `UrlEncodingSerializer.DEFAULT_EXPANDED` | Arrays/collections repeat
`key=value` per element instead of comma-joining |
+|
[HoconBraces](/site/apidocs/org/apache/juneau/marshall/marshaller/HoconBraces.html)
| [Hocon](/site/apidocs/org/apache/juneau/marshall/marshaller/Hocon.html) |
`HoconSerializer.DEFAULT_BRACES` | Same as `Hocon.DEFAULT` but includes root `{
}` braces |
+| [HoconC](/site/apidocs/org/apache/juneau/marshall/marshaller/HoconC.html) |
[Hocon](/site/apidocs/org/apache/juneau/marshall/marshaller/Hocon.html) |
`HoconSerializer.DEFAULT_COMPACT` | Compact (single-line), JSON-compatible
HOCON |
+| [XmlSq](/site/apidocs/org/apache/juneau/marshall/marshaller/XmlSq.html) |
[Xml](/site/apidocs/org/apache/juneau/marshall/marshaller/Xml.html) |
`XmlSerializer.DEFAULT_SQ` | Single-quoted attributes |
+| [XmlSqR](/site/apidocs/org/apache/juneau/marshall/marshaller/XmlSqR.html) |
[Xml](/site/apidocs/org/apache/juneau/marshall/marshaller/Xml.html) |
`XmlSerializer.DEFAULT_SQ_READABLE` | Single-quoted attributes + readable |
+| [XmlNs](/site/apidocs/org/apache/juneau/marshall/marshaller/XmlNs.html) |
[Xml](/site/apidocs/org/apache/juneau/marshall/marshaller/Xml.html) |
`XmlSerializer.DEFAULT_NS` | Namespace-aware output |
+| [XmlNsSq](/site/apidocs/org/apache/juneau/marshall/marshaller/XmlNsSq.html)
| [Xml](/site/apidocs/org/apache/juneau/marshall/marshaller/Xml.html) |
`XmlSerializer.DEFAULT_NS_SQ` | Namespace-aware + single-quoted attributes |
+|
[XmlNsSqR](/site/apidocs/org/apache/juneau/marshall/marshaller/XmlNsSqR.html) |
[Xml](/site/apidocs/org/apache/juneau/marshall/marshaller/Xml.html) |
`XmlSerializer.DEFAULT_NS_SQ_READABLE` | Namespace-aware + single-quoted
attributes + readable |
+| [HtmlSq](/site/apidocs/org/apache/juneau/marshall/marshaller/HtmlSq.html) |
[Html](/site/apidocs/org/apache/juneau/marshall/marshaller/Html.html) |
`HtmlSerializer.DEFAULT_SQ` | Single-quoted attributes |
+| [HtmlSqR](/site/apidocs/org/apache/juneau/marshall/marshaller/HtmlSqR.html)
| [Html](/site/apidocs/org/apache/juneau/marshall/marshaller/Html.html) |
`HtmlSerializer.DEFAULT_SQ_READABLE` | Single-quoted attributes + readable |
+|
[HtmlSimpleSq](/site/apidocs/org/apache/juneau/marshall/marshaller/HtmlSimpleSq.html)
| [Html](/site/apidocs/org/apache/juneau/marshall/marshaller/Html.html) |
`HtmlSerializer.DEFAULT_SIMPLE_SQ` | Single-quoted attributes + JSON type-hint
tags disabled |
+|
[BsonSpacedHex](/site/apidocs/org/apache/juneau/marshall/marshaller/BsonSpacedHex.html)
| [Bson](/site/apidocs/org/apache/juneau/marshall/marshaller/Bson.html) |
`BsonSerializer.DEFAULT_SPACED_HEX` / `BsonParser.DEFAULT_SPACED_HEX` |
Spaced-hex `byte[]` binary format |
+|
[BsonBase64](/site/apidocs/org/apache/juneau/marshall/marshaller/BsonBase64.html)
| [Bson](/site/apidocs/org/apache/juneau/marshall/marshaller/Bson.html) |
`BsonSerializer.DEFAULT_BASE64` / `BsonParser.DEFAULT_BASE64` | Base64 `byte[]`
binary format |
+|
[CborSpacedHex](/site/apidocs/org/apache/juneau/marshall/marshaller/CborSpacedHex.html)
| [Cbor](/site/apidocs/org/apache/juneau/marshall/marshaller/Cbor.html) |
`CborSerializer.DEFAULT_SPACED_HEX` / `CborParser.DEFAULT_SPACED_HEX` |
Spaced-hex `byte[]` binary format |
+|
[CborBase64](/site/apidocs/org/apache/juneau/marshall/marshaller/CborBase64.html)
| [Cbor](/site/apidocs/org/apache/juneau/marshall/marshaller/Cbor.html) |
`CborSerializer.DEFAULT_BASE64` / `CborParser.DEFAULT_BASE64` | Base64 `byte[]`
binary format |
+|
[CborNative](/site/apidocs/org/apache/juneau/marshall/marshaller/CborNative.html)
| [Cbor](/site/apidocs/org/apache/juneau/marshall/marshaller/Cbor.html) |
`CborSerializer.DEFAULT` / `CborParser.DEFAULT_NATIVE` | Native-mode parsing
(exposes low-level CBOR tag/type info) |
+|
[MsgPackSpacedHex](/site/apidocs/org/apache/juneau/marshall/marshaller/MsgPackSpacedHex.html)
| [MsgPack](/site/apidocs/org/apache/juneau/marshall/marshaller/MsgPack.html)
| `MsgPackSerializer.DEFAULT_SPACED_HEX` / `MsgPackParser.DEFAULT_SPACED_HEX` |
Spaced-hex `byte[]` binary format |
+|
[MsgPackBase64](/site/apidocs/org/apache/juneau/marshall/marshaller/MsgPackBase64.html)
| [MsgPack](/site/apidocs/org/apache/juneau/marshall/marshaller/MsgPack.html)
| `MsgPackSerializer.DEFAULT_BASE64` / `MsgPackParser.DEFAULT_BASE64` | Base64
`byte[]` binary format |
+|
[MsgPackNative](/site/apidocs/org/apache/juneau/marshall/marshaller/MsgPackNative.html)
| [MsgPack](/site/apidocs/org/apache/juneau/marshall/marshaller/MsgPack.html)
| `MsgPackSerializer.DEFAULT` / `MsgPackParser.DEFAULT_NATIVE` | Native-mode
parsing (exposes low-level MessagePack extension-type info) |
+
+:::note
+`CborNative` and `MsgPackNative` pair the plain (non-variant) serializer with
a native-mode parser — only
+the low-level token-stream interpretation changes, not the serialized bytes.
+:::
## MarshallUtils
diff --git a/pages/topics/03.24.ObjectTools.md
b/pages/topics/03.24.ObjectTools.md
index f7bbf03557..5905e91cdb 100644
--- a/pages/topics/03.24.ObjectTools.md
+++ b/pages/topics/03.24.ObjectTools.md
@@ -214,22 +214,101 @@ converter.
The <a
href="/site/apidocs/org/apache/juneau/marshall/objecttools/ObjectIntrospector.html"
target="_blank">ObjectIntrospector</a> class is used to invoke
methods on `Objects` using arguments in serialized form.
+:::warning Secure by default (10.0)
+As of Juneau 10.0, `ObjectIntrospector` **denies reflective method dispatch by
default**. Before calling
+`invokeMethod(...)`, you must explicitly allow-list the method(s) that may be
invoked via `allow(Class, String...)`
+(or the `Predicate<Method>` form of `allow(...)`). Invoking a method that
isn't allow-listed throws
+<a
href="/site/apidocs/org/apache/juneau/marshall/objecttools/MethodNotAllowlistedException.html"
target="_blank">MethodNotAllowlistedException</a>.
+
+This closes off "reflective-invoke-over-the-wire" exposure — e.g. a REST
endpoint that fed an untrusted method
+name/arguments string straight into an introspector could previously be used
to invoke **any** public,
+non-deprecated method on the target object.
+
+See the [Release Notes](/docs/release-notes/10.0.0#breaking-changes) for the
full migration note.
+:::
+
:::tip Example
```java
String string1 = "foobar";
String string2 = ObjectIntrospector
.create(string1)
+ .allow(String.class, "substring(int,int)") // Explicit allow-list.
.invokeMethod(String.class, "substring(int,int)", "[3,6]"); // "bar"
```
:::
+For trusted, in-process-only use, `allowAll()` can be used instead of an
explicit allow-list to restore the
+pre-10.0 behavior of dispatching to any public, non-deprecated method:
+
+```java
+String string2 = ObjectIntrospector
+ .create(string1)
+ .allowAll() // Trusted callers only - never use with untrusted
method/argument sources.
+ .invokeMethod(String.class, "substring(int,int)", "[3,6]"); // "bar"
+```
+
The arguments passed to the identified method are POJOs serialized in JSON
format.
Arbitrarily complex arguments can be passed
in as arguments.
:::note
This class is used in the <a
href="/site/apidocs/org/apache/juneau/rest/server/converter/Introspectable.html"
target="_blank">Introspectable</a> REST
-response converter.
+response converter. `Introspectable` is **deny-by-default** as shipped — with
no configuration, every
+`invokeMethod` request fails with an HTTP 500
(`MethodNotAllowlistedException`). A resource opts specific
+methods in by registering an
+<a
href="/site/apidocs/org/apache/juneau/rest/server/converter/IntrospectableSettings.html"
target="_blank">IntrospectableSettings</a>
+bean in its bean store — see [Introspectable REST
converter](#introspectable-rest-converter) below.
+:::
+
+## Introspectable REST converter
+
+The <a
href="/site/apidocs/org/apache/juneau/rest/server/converter/Introspectable.html"
target="_blank">Introspectable</a> converter
+adapts `ObjectIntrospector` for REST — it lets a caller invoke public methods
on a `@RestOp` method's response
+object via the `invokeMethod`/`invokeArgs` query parameters.
+
+:::warning Deny-by-default (10.0)
+As shipped, `Introspectable` has **no methods allow-listed** — every
`invokeMethod` request is refused with an
+HTTP 500 (`MethodNotAllowlistedException`). A resource opts specific methods
in *explicitly* by registering an
+<a
href="/site/apidocs/org/apache/juneau/rest/server/converter/IntrospectableSettings.html"
target="_blank">IntrospectableSettings</a>
+bean in its bean store:
+:::
+
+:::tip Example — allow-listing specific methods
+```java
+@Rest(converters=Introspectable.class)
+public class MyResource extends BasicRestServlet {
+
+ @Bean
+ public IntrospectableSettings introspectableSettings() {
+ return IntrospectableSettings.create()
+ .allow(MyBean.class, "getName", "getAge")
+ .build();
+ }
+
+ @RestGet
+ public MyBean get() {
+ return new MyBean();
+ }
+}
+```
+A request to `/?invokeMethod=getName` now dispatches to `MyBean.getName()`;
any other method (e.g. `toString`)
+is still refused, since it wasn't allow-listed.
+:::
+
+For a trusted resource that needs the pre-10.0 behavior of dispatching to any
public, non-deprecated method,
+call `allowAll()` instead:
+
+```java
+@Bean
+public IntrospectableSettings introspectableSettings() {
+ return IntrospectableSettings.create().allowAll().build();
+}
+```
+
+:::warning
+Never call `allowAll()` on a resource whose response objects expose methods
you wouldn't want an arbitrary
+caller to invoke — the method name and arguments for `Introspectable` always
come from untrusted request
+query parameters. Allow-list the specific methods instead.
:::
:::warning
diff --git a/pages/topics/03.43.Cbor.md b/pages/topics/03.43.Cbor.md
index a86bd6f228..8d125be840 100644
--- a/pages/topics/03.43.Cbor.md
+++ b/pages/topics/03.43.Cbor.md
@@ -99,11 +99,7 @@ JsonMap parsed = CborParser.Base64.DEFAULT.read(b64,
JsonMap.class);
## REST Integration
```java
-// Use BasicUniversalConfig for CBOR-only REST resources
-@Rest
-public class MyResource extends RestServlet implements BasicUniversalConfig {
... }
-
-// CBOR is also included in BasicUniversalConfig
+// CBOR support is included via BasicUniversalConfig (there is no dedicated
CBOR-only config interface).
@Rest
public class MyResource extends RestServlet implements BasicUniversalConfig {
... }
```
diff --git a/pages/topics/10.20.StaticFiles.md
b/pages/topics/10.20.StaticFiles.md
index 8d945738ba..e7c0d69a48 100644
--- a/pages/topics/10.20.StaticFiles.md
+++ b/pages/topics/10.20.StaticFiles.md
@@ -8,10 +8,12 @@ The <a
href="/site/apidocs/org/apache/juneau/rest/server/servlet/BasicRestServle
```java
@RestGet(path="/htdocs/*")
public HttpResource getHtdoc(RestRequest req, @Path("/*") String path, Locale
locale) throws NotFound {
- return req.getStaticFiles().resolve(path,
locale).orElseThrow(NotFound::new);
+ return StaticFilesMixin.resolveStaticFile(req, path, locale);
}
```
+`HtdocMixin` delegates to <a
href="/site/apidocs/org/apache/juneau/rest/server/staticfile/StaticFilesMixin.html#resolveStaticFile(org.apache.juneau.rest.server.RestRequest,java.lang.String,java.util.Locale)"
target="_blank">StaticFilesMixin.resolveStaticFile(...)</a> — the same
static-file resolution chokepoint used by
[`StaticFilesMixin`](/docs/topics/StaticFilesMixin)'s own handlers — so there's
a single implementation of the lookup logic even though the two mixins expose
different mou [...]
+
The static file finder can be accessed through either of the following methods
— the
`RestRequest` shortcut is a convenience delegate for the `RestContext`
accessor:
@@ -42,15 +44,13 @@ StaticFiles
.headers(cacheControl("max-age=86400, public")); // Add cache control.
```
-:::caution Mount collision with `StaticFilesMixin`
-`BasicRestServlet`/`BasicRestResource` already bake in `HtdocMixin`, which
serves `/htdocs/*` by
-default. The separate, opt-in
[`StaticFilesMixin`](/docs/topics/StaticFilesMixin) *also*
-default-mounts `/htdocs/*` (plus `/static/*`). Because `HtdocMixin` and
`StaticFilesMixin` are
-different classes, the mixin walk's dedupe-by-class-identity rule does not
collapse them — adding
-`StaticFilesMixin` to a `BasicRestServlet` subclass registers two mixins
competing for the same
-`/htdocs/*` mount. If you need `StaticFilesMixin`'s multi-mount/OSGi-friendly
packaging on a
-`BasicRestServlet` subclass, test the combined behavior explicitly, or build
on plain `RestServlet`
-instead so only one static-file mixin is in play.
+:::note Relationship to `StaticFilesMixin`
+`HtdocMixin` and [`StaticFilesMixin`](/docs/topics/StaticFilesMixin) both
serve static content off
+the same `StaticFiles` bean, but no longer compete for the same mount by
default: `HtdocMixin`
+owns the fixed legacy `/htdocs/*` path, while `StaticFilesMixin` defaults to
`/static/*` (configurable
+via the `${juneau.staticfiles.path:static}` SVL variable — set it to `htdocs`
to reach the same URL
+`HtdocMixin` uses). Adding `StaticFilesMixin` to a `BasicRestServlet` subclass
is therefore safe out
+of the box; both mixins resolve through the shared
`StaticFilesMixin.resolveStaticFile(...)` logic.
:::
Static files can be configured programmatically through the following APIs:
diff --git a/pages/topics/10.21.StaticFilesMixin.md
b/pages/topics/10.21.StaticFilesMixin.md
index 6197ae2dd9..696a0fb005 100644
--- a/pages/topics/10.21.StaticFilesMixin.md
+++ b/pages/topics/10.21.StaticFilesMixin.md
@@ -7,8 +7,8 @@ The Juneau REST server ships with a
[`StaticFilesMixin`](/site/apidocs/org/apache/juneau/rest/server/staticfile/StaticFilesMixin.html)
mixin in the
[`org.apache.juneau.rest.server.staticfile`](/site/apidocs/org/apache/juneau/rest/server/staticfile/package-summary.html)
package that wraps the existing
[`BasicStaticFiles`](/site/apidocs/org/apache/juneau/rest/server/staticfile/BasicStaticFiles.html)
-plumbing (a `StaticFiles` implementation, not a servlet) in a servlet-level
mixin with
-multi-mount support. Any `@Rest`-annotated resource can opt into static-file
serving via
+plumbing (a `StaticFiles` implementation, not a servlet) in a servlet-level
mixin with a
+configurable mount point. Any `@Rest`-annotated resource can opt into
static-file serving via
[`@Rest(mixins=...)`](/docs/topics/RestServerComposition) without subclassing
[`BasicRestServlet`](/site/apidocs/org/apache/juneau/rest/server/servlet/BasicRestServlet.html)
just to
inherit `getHtdoc(...)`.
@@ -20,31 +20,41 @@ inherit `getHtdoc(...)`.
## What the mixin does
The mixin declares two REST operation methods bound to the same handler so a
single Java method
-serves both `GET` and `HEAD` for both default mount points:
+serves both `GET` and `HEAD` for the mixin's mount point:
```java
-@Rest(paths = {"/static/*", "/htdocs/*"})
+@Rest
public class StaticFilesMixin {
@RestGet(
- path = {"/static/*", "/htdocs/*"},
+ path = "/#{pathToken(${juneau.staticfiles.path:static})}/*",
swagger = @OpSwagger(ignore = true)
)
public HttpResource getStaticFile(RestRequest req, @Path("/*") String
path, Locale locale) {
- return req.getStaticFiles().resolve(path,
locale).orElseThrow(NotFound::new);
+ return resolveStaticFile(req, path, locale);
}
@RestOp(
method = "HEAD",
- path = {"/static/*", "/htdocs/*"},
+ path = "/#{pathToken(${juneau.staticfiles.path:static})}/*",
swagger = @OpSwagger(ignore = true)
)
public HttpResource headStaticFile(RestRequest req, @Path("/*") String
path, Locale locale) {
return getStaticFile(req, path, locale);
}
+
+ public static HttpResource resolveStaticFile(RestRequest req, String path,
Locale locale) throws NotFound {
+ return req.getStaticFiles().resolve(path,
locale).orElseThrow(NotFound::new);
+ }
}
```
+The op-level path is an SVL expression, so the mount defaults to `/static/*`
but can be
+overridden without subclassing — see [Mount path
configuration](#mount-path-configuration) below.
+The static-file resolution itself lives in the `resolveStaticFile(...)` static
helper, which is also
+what [`HtdocMixin`](/docs/topics/StaticFiles)'s legacy `/htdocs/*` handler
calls into — a single
+implementation of the lookup logic shared by both mixins.
+
The handler resolves the `StaticFiles` bean via `req.getStaticFiles()` at
request time — a
[`RestRequest`](/site/apidocs/org/apache/juneau/rest/server/RestRequest.html)
convenience shortcut for
`req.getContext().getStaticFiles()` — which delegates to
`BeanStore.getBean(StaticFiles.class)` and falls
@@ -56,19 +66,13 @@ the [problem-details
opt-in](/docs/topics/RestServerProblemDetails) is active; p
## Default mount usage
-:::caution Mount collision on `BasicRestServlet` subclasses
-`BasicRestServlet`/`BasicRestResource` already bake in
-[`HtdocMixin`](/site/apidocs/org/apache/juneau/rest/server/ops/HtdocMixin.html),
which serves
-`/htdocs/*` by default (see [Static files](/docs/topics/StaticFiles)). Adding
`StaticFilesMixin`
-to a `BasicRestServlet` subclass registers a *second*,
independently-implemented mixin that also
-default-mounts `/htdocs/*` — `HtdocMixin` and `StaticFilesMixin` are different
classes, so the
-mixin walk's dedupe-by-class-identity rule does not collapse them. This page's
examples build on
-plain `RestServlet` (no baked-in `HtdocMixin`) specifically to avoid that
overlap; if you add
-`StaticFilesMixin` to a `BasicRestServlet` subclass instead, test the combined
behavior explicitly.
-:::
-
Add the mixin to any `@Rest`-annotated resource — no subclassing of
`BasicRestServlet`
-required — and `/static/*` and `/htdocs/*` start serving classpath resources
immediately:
+required — and `/static/*` starts serving classpath resources immediately.
This is safe to add to
+a `BasicRestServlet` subclass too: `BasicRestServlet` already bakes in
+[`HtdocMixin`](/site/apidocs/org/apache/juneau/rest/server/ops/HtdocMixin.html)
for the legacy,
+fixed `/htdocs/*` mount (see [Static files](/docs/topics/StaticFiles)), and
the two mixins no
+longer compete for the same URL by default — they share the same resolution
logic but expose
+different mounts.
```java
@Rest(path = "/api", mixins = StaticFilesMixin.class)
@@ -77,14 +81,13 @@ public class ApiResource extends RestServlet {
@RestGet("/items")
public List<Item> items() { ... }
}
-// Serves /api/items, /api/static/<file>, /api/htdocs/<file>.
+// Serves /api/items and /api/static/<file>.
```
`StaticFilesMixin` is itself a fully-fledged `@Rest`-annotated resource and
can also be
subclassed and mounted as its own top-level servlet:
```java
-@Rest(paths = {"/static/*", "/htdocs/*"})
public class CdnResource extends StaticFilesMixin { }
```
@@ -92,28 +95,42 @@ Both deployment styles (mixin into an existing servlet vs.
mount as a sibling se
same way under Spring Boot and under the Jetty microservice — see
[Spring Boot vs. microservice](#spring-boot-vs-microservice) below.
-## Multi-mount semantics
+## Mount path configuration
-The mixin's `@Rest(paths = {"/static/*", "/htdocs/*"})` declares two top-level
servlet-container
-mount points at the same time. Both URLs route to the *same*
`StaticFilesMixin` instance
-and the *same* `@RestGet(path = {"/static/*","/htdocs/*"})` Java handler — the
trailing `/*`
-captures the multi-segment remainder via `@Path("/*") String path` and is
forwarded to
-`StaticFiles.resolve(...)` verbatim, so a `GET /static/css/main.css` and a
`GET /htdocs/css/main.css`
-both resolve to the same `css/main.css` file under the classpath search roots.
+The default `/static/*` mount can be overridden via the
`${juneau.staticfiles.path:static}` SVL
+variable — set via a system property (`-Djuneau.staticfiles.path=assets`), an
environment variable
+(`JUNEAU_STATICFILES_PATH=assets`), or a `Config` key
(`juneau.staticfiles.path = assets`) — to
+change the runtime mount without subclassing. The override accepts a bare
token (`assets`), a
+leading slash (`/assets`), a trailing slash (`assets/`), or a wildcard suffix
(`/assets/*`); all
+resolve to the same mount. Resolution happens once at `RestContext`
construction time.
-To add a third mount path (e.g. `/assets/*`) without touching the mixin,
subclass it:
+Setting the override to `htdocs` reaches the same URL `HtdocMixin` uses — the
classpath
+`BasicStaticFiles` search root already walks both `static/` and `htdocs/`
directories by default,
+so the same files are reachable either way:
```java
-@Rest(paths = {"/static/*", "/htdocs/*", "/assets/*"})
-public class CdnResource extends StaticFilesMixin { }
+// -Djuneau.staticfiles.path=htdocs
+@Rest(mixins = StaticFilesMixin.class)
+public class ApiResource extends RestServlet {
+ // Now serves /htdocs/<file> via StaticFilesMixin (GET + HEAD).
+}
```
-The inner `@RestGet(path = {"/static/*","/htdocs/*"})` matcher still binds to
two paths and the
-inherited `StaticFilesMixin.getStaticFile(...)` Java handler still routes
through it; a
-subclass that wants `/assets/*` to dispatch through the same handler needs to
either re-declare
-the `@RestGet` (`path = {"/static/*","/htdocs/*","/assets/*"}`) on an
overriding method or
-register two top-level servlet beans (one per mount group). See
-[Path-override constraint](#path-override-constraint) below for the full story.
+:::caution Deliberate override onto an already-occupied mount
+If you set the override to `htdocs` on a
`BasicRestServlet`/`BasicRestResource` subclass — which
+already bakes in `HtdocMixin`'s fixed `/htdocs/*` mount — `StaticFilesMixin`
now competes for that
+same URL. This is no longer the *default* behavior (the two mixins default to
different mounts),
+but it can still happen if you opt into it explicitly; test the combined
behavior, or build on
+plain `RestServlet` instead so only one static-file mixin is in play at
`/htdocs/*`.
+:::
+
+To add a completely different mount path without touching the mixin, subclass
it and override the
+op-level path via a `Config`/system-property override, or compose
`StaticFilesMixin` alongside
+another mixin/handler for the additional path — the SVL expression only
supports a single mount
+per `StaticFilesMixin` instance. Multiple independent mounts (e.g. `/static/*`
*and* `/assets/*`
+on the same host) require either two `StaticFiles`-serving beans (one
`StaticFilesMixin` instance
+per desired path, each with its own SVL override at the servlet-registration
layer) or a
+custom handler for the second path.
## HEAD support
@@ -218,82 +235,19 @@ public StaticFiles staticFiles(BeanStore bs) {
```
This is pinned by `StaticFilesMixin_SpringbootMetaInf_Test` — a file at
-`src/main/resources/META-INF/resources/spring-fixture.txt` is reachable
through both `/static/spring-fixture.txt`
-and `/htdocs/spring-fixture.txt` under the mixin's default mounts. Spring
Boot's own static-resource
-handler also continues to serve the same file at `/spring-fixture.txt` (the
root mount), so the
-two handlers coexist without shadowing each other.
-
-## Path-override constraint
-
-The mixin combines two layers of routing:
-
-1. **Container-level mount.** `@Rest(paths = {"/static/*","/htdocs/*"})`
declares which URLs the
- servlet container should dispatch to the `StaticFilesMixin` instance. This
rung
- participates in the [runtime-override paths
chain](/docs/topics/RestServerComposition#runtime-overridable-paths)
- so a subclass with `@Rest(paths = {"/assets/*"})` widens the container
mount to `/assets/*`.
-2. **Inner `@RestGet` matcher.** `@RestGet(path = {"/static/*","/htdocs/*"})`
declares which
- URL patterns route to the `getStaticFile(...)` Java handler *within* the
resource. This rung
- is *not* affected by the container-level `@Rest(paths=...)` widening —
`@RestGet(path=...)`
- is a literal compile-time list that subclasses do not implicitly
inherit-widen.
-
-The practical consequence: a naive subclass with `@Rest(paths =
{"/assets/*"})` mounts the
-servlet at `/assets/*` but the inner `@RestGet` matcher still binds to
`["/static/*", "/htdocs/*"]`,
-so `GET /assets/foo.css` reaches the resource but does not match any handler
and returns 404.
-
-Two working patterns to add a third mount path:
-
-**Subclass + override the `@RestGet` matcher.** Re-declare the handler with
the full mount
-list on the subclass:
-
-```java
-@Rest(paths = {"/static/*", "/htdocs/*", "/assets/*"})
-public class CdnResource extends StaticFilesMixin {
-
- @Override
- @RestGet(
- path = {"/static/*", "/htdocs/*", "/assets/*"},
- swagger = @OpSwagger(ignore = true)
- )
- public HttpResource getStaticFile(RestRequest req, @Path("/*") String
path, Locale locale) {
- return super.getStaticFile(req, path, locale);
- }
-}
-```
-
-**Register two beans at the servlet-registration layer.** Mount one
`StaticFilesMixin`
-instance at `/static/*, /htdocs/*` and a second at `/assets/*`:
-
-```java
-@Configuration
-public class StaticConfig {
-
- @Bean
- public ServletRegistrationBean<StaticFilesMixin> defaults() {
- return new ServletRegistrationBean<>(new StaticFilesMixin(),
"/static/*", "/htdocs/*");
- }
-
- @Bean
- public ServletRegistrationBean<StaticFilesMixin> assets() {
- return new ServletRegistrationBean<>(new StaticFilesMixin(),
"/assets/*");
- }
-}
-```
-
-The deeper refactor — decoupling inner-matcher paths from container-level
mount paths so
-runtime overrides cascade fully through both layers — was considered but
deferred. The
-constraint is intentional: keeping `@RestGet(path=...)` as a literal,
-non-inherited matcher matches every other Juneau `@RestGet`-annotated method,
and the two
-working patterns above are explicit and discoverable. If your app heavily
relies on the
-container-level mount widening cascading to inner matchers, the second pattern
(register two
-beans) is the recommended workaround.
+`src/main/resources/META-INF/resources/spring-fixture.txt` is reachable
through `/static/spring-fixture.txt`
+under the mixin's default mount (and also through `/htdocs/spring-fixture.txt`
via the always-on
+`HtdocMixin` mount when the host extends
`BasicRestServlet`/`BasicSpringRestServlet`, since both
+mixins share the same `StaticFiles` bean). Spring Boot's own static-resource
handler also continues
+to serve the same file at `/spring-fixture.txt` (the root mount), so the
handlers coexist without
+shadowing each other.
## See also
- [Static files](/docs/topics/StaticFiles) — the underlying `StaticFiles` and
`BasicStaticFiles`
reference; classpath search roots, caching, exclude patterns.
- [REST Server — Mixins and Multi-Mount
Paths](/docs/topics/RestServerComposition) —
- the `@Rest(mixins=...)` and `@Rest(paths=...)` primitives this mixin builds
on, including the
- runtime-overridable paths chain.
+ the `@Rest(mixins=...)` primitive this mixin builds on.
- [API-Docs Mixin Pack](/docs/topics/ApiDocsMixins) — the four-class api-docs
surface
that also uses the `@OpSwagger(ignore=true)` exclusion mechanism for its
`/*` handlers.
- [Response Processors](/docs/topics/ResponseProcessors) — how
`HttpResourceProcessor` handles
diff --git a/pages/topics/13.14.NextGenRestClient.md
b/pages/topics/13.14.NextGenRestClient.md
index bb41e6f925..81697f9bab 100644
--- a/pages/topics/13.14.NextGenRestClient.md
+++ b/pages/topics/13.14.NextGenRestClient.md
@@ -102,13 +102,36 @@ try (var resp = client.get("/users/{id}").pathData("id",
42).run()) {
client.close();
```
+### Zero-Config Shortcut: `create()`
+
+`RestClient.create()` is a **zero-config shortcut** — it's shorthand for
`RestClient.builder().build()`:
+an auto-discovered transport, no default serializer/parser, and no root URL.
Reach for it when you just
+want a client to issue requests against absolute URLs with no marshalling
configured up front:
+
+```java
+RestClient client = RestClient.create();
+
+try (var resp =
client.get("https://api.example.com/users/{id}").pathData("id", 42).run()) {
+ var body = resp.body().asString();
+}
+```
+
+Use `RestClient.builder()` — as shown above — whenever you need to configure a
transport, serializer/
+parser, root URL, default headers, interceptors, or any other builder option.
`create()` and `builder()`
+are the **only two idioms** for obtaining an NG `RestClient`; `create()` is
not a legacy alias for
+`builder()` (that shape belongs to the [classic
client](#key-design-differences-from-the-classic-restclient),
+which is why porting classic code replaces `RestClient.create()` with
`RestClient.builder()` — see
+[Migration Path](#migration-path) below).
+
### Auto-Discovery
If you don't pass an explicit transport, `RestClient` uses `ServiceLoader` to
pick the
-highest-priority `HttpTransportProvider` on the classpath:
+highest-priority `HttpTransportProvider` on the classpath — this applies
whether you configure the
+client via `create()` or via `builder()`. The following configures marshalling
explicitly while still
+relying on transport auto-discovery:
```java
-RestClient zeroConfig = RestClient.builder()
+RestClient client = RestClient.builder()
.serializer(Json5Serializer.DEFAULT)
.parser(Json5Parser.DEFAULT)
.rootUrl("https://api.example.com")
@@ -121,6 +144,7 @@ RestClient zeroConfig = RestClient.builder()
| Concern | Classic `RestClient` (`...client.classic`) | Canonical
`RestClient` (`...client`) |
|---|---|---|
+| Client construction | `create()` returns a `Builder` (call `.build()` to get
a client) | `create()` returns a **built, ready-to-use client** (the
zero-config shortcut); `builder()` returns a `Builder` |
| HTTP integration | Implements `org.apache.http.client.HttpClient`; bound to
Apache HC 4.5 | Composes an `HttpTransport`; transport-agnostic |
| Serialization model | Multi-language marshallers / format shortcuts
(`json()`, `xml()`, …) | **One pre-built serializer/parser pair per client**;
no multi-language mode |
| Builder surface | 40+ Apache HC passthrough methods | Small builder with
only Juneau-specific concerns |
diff --git a/pages/topics/18.01.ScServerOverview.md
b/pages/topics/18.01.ScServerOverview.md
index 1899584857..e697f7e0f8 100644
--- a/pages/topics/18.01.ScServerOverview.md
+++ b/pages/topics/18.01.ScServerOverview.md
@@ -135,9 +135,23 @@ Before exposing it outside a trusted network, consider:
- Storing Git credentials outside the config file (environment variables or a
secrets manager)
rather than hard-coding them.
-The `GitControl` class currently uses a `UsernamePasswordCredentialsProvider`
with credentials stored
-in the source. This should be externalised to environment variables or a
secrets store before production
-deployment.
+`GitControl` itself does **not** hardcode credentials — its 5-argument
constructor
+(`GitControl(localPath, remotePath, username, password, forcePush)`) takes
them as caller-supplied
+parameters, and the 2-argument constructor defaults to anonymous transport
with force-push disabled.
+**The residual risk is entirely at the call site:** anything that wires up
`GitControl` (e.g. an
+`AppConfig`/`App.java` bean method) can still reintroduce the original problem
by passing literal
+credential strings:
+
+```java
+// Unsafe — literal credentials checked into source control.
+new GitControl(pathLocal, gitRemote, "svc-account", "hardcoded-token", false);
+
+// Safe — credentials sourced from the environment (or a secrets manager) at
startup, never committed.
+new GitControl(pathLocal, gitRemote, System.getenv("GIT_USERNAME"),
System.getenv("GIT_TOKEN"), false);
+```
+
+Never hardcode the `username`/`password` arguments in application code or in
the checked-in
+`juneau-server-config.cfg`.
## See Also
diff --git a/src/pages/about.md b/src/pages/about.md
index c2021ae5b5..9b197c9753 100644
--- a/src/pages/about.md
+++ b/src/pages/about.md
@@ -32,8 +32,8 @@ The Juneau ecosystem consists of the following parts. A few
rows are **grouped f
|-----------|-------------|
| **juneau-core** | |
| [juneau-commons](/docs/topics/JuneauCommons) | Bean metadata framework, SVL
string-variable resolution, and shared utilities (I/O, reflection, HTTP,
collections) used across Juneau modules. |
-| [juneau-marshall](/docs/topics/JuneauMarshall) | POJO marshalling for 25+
wire formats — JSON/JSON5/JSONL/JCS, XML/SOAP, HTML, YAML/TOML/HOCON/HJSON/INI,
CBOR/BSON/MessagePack, Protobuf/Prototext, UON/URL-encoding, CSV, Parquet,
Markdown, SSE, OpenAPI, and PlainText — plus a token-streaming API; no external
dependencies required. |
-| [juneau-marshall-rdf](/docs/topics/JuneauMarshallRdf) | Extended marshalling
support for RDF/XML, N3, N-Triple, N-Quads, Turtle, TriG, TriX, JSON-LD,
RDF/JSON, RDF/Proto, and RDF/Thrift (requires Apache Jena). |
+| [juneau-marshall](/docs/topics/JuneauMarshall) | POJO marshalling for 26+
wire formats — JSON/JSON5/JSONL/JSON5L/JCS, XML/SOAP, HTML,
YAML/TOML/HOCON/HJSON/INI, CBOR/BSON/MessagePack, Protobuf/Prototext,
UON/URL-encoding, CSV, Parquet, Markdown, SSE, OpenAPI, and PlainText — plus a
token-streaming API; no external dependencies required. |
+| [juneau-marshall-rdf](/docs/topics/JuneauMarshallRdf) | Extended marshalling
support for 12 RDF variants — RDF/XML, RDF/XML-Abbrev, N3, N-Triple, N-Quads,
Turtle, TriG, TriX, JSON-LD, RDF/JSON, RDF/Proto, and RDF/Thrift (requires
Apache Jena). |
| [juneau-config](/docs/topics/JuneauConfig) | Multi-format (INI and YAML)
configuration file API with POJO support, variable resolution, and real-time
file watching. |
| [juneau-test](/docs/topics/JuneauTest) | Fluent assertions, Bean-Centric
Testing, and JUnit 5 extensions for readable, expressive unit tests. |
| **juneau-bean** | |
diff --git a/static/ai/juneau-knowledge.jsonl b/static/ai/juneau-knowledge.jsonl
index 99931c3860..da89a38888 100644
--- a/static/ai/juneau-knowledge.jsonl
+++ b/static/ai/juneau-knowledge.jsonl
@@ -99,7 +99,7 @@
{"description": "# Release 9.1.0\n\n**Date:** June 19, 2025\n\nJuneau 9.1.0 is
a major compatibility update focused on Jakarta EE migration and Spring Boot
modernization.\n\n## Major Changes\n\n### Jakarta EE Migration\n\n- **Complete
javax to jakarta namespace migration**: All references to `javax.*` packages
have been converted to their corresponding `jakarta.*` equivalents.\n This
includes:\n - `javax.servlet.*` \u2192 `jakarta.servlet.*`\n -
`javax.validation.*` \u2192 `jakarta.va [...]
{"description": "# Release 9.2.0\n\n**Date:** 01/05/2026\n\nJuneau 9.2.0 is a
minor release focused on enhancements and bug fixes.\n\nMajor changes
include:\n\n- **Hjson (Human JSON) Support**: New native serializer and parser
for Hjson format with quoteless strings, multiline strings, comments, and
optional commas \u2014 ideal for configuration files and hand-edited data\n-
**New Module**: Introduced `juneau-shaded` with five shaded (uber) JAR
artifacts for simplified dependency managem [...]
{"description": "# Release 9.5.0\n\n**Date:** TBD\n\nJuneau 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 \u2014
`SwaggerMixin` / `SwaggerUiMixin` / `OpenApiMixin` / `RedocMixin` \u2014 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 [...]
-{"description": "## About\n\nApache Juneau\u2122 is a single cohesive Java
ecosystem for marshalling Java objects to a wide variety of data formats and
\ncreating annotation-based REST end-to-end server and client APIs.\n\n## Key
Features\n\n- **Universal Serialization** - Marshal POJOs to 20+ formats from a
single API: JSON (plus JSON5, JSONL, and JSON5L), XML, HTML, URL-Encoding, UON,
OpenAPI, MessagePack, CBOR, BSON, YAML, TOML, HOCON, HJSON, CSV, INI, Markdown,
Parquet, Protobuf, SSE [...]
+{"description": "## About\n\nApache Juneau\u2122 is a single cohesive Java
ecosystem for marshalling Java objects to a wide variety of data formats and
\ncreating annotation-based REST end-to-end server and client APIs.\n\n## Key
Features\n\n- **Universal Serialization** - Marshal POJOs to 38+ formats from a
single API: JSON (plus JSON5, JSONL, JSON5L, and JCS), XML, SOAP, HTML,
URL-Encoding, UON, OpenAPI, MessagePack, CBOR, BSON, YAML, TOML, HOCON, HJSON,
CSV, INI, Markdown, Parquet, Pr [...]
{"description": "This page describes how Juneau's feature set lines up against
a few popular alternatives. Rather than declaring\nan overall \"winner\", each
table below simply notes whether a given capability is present, built-in, or
requires\nextra setup \u2014 the goal is to help you evaluate whether Juneau's
particular trade-offs fit your project, not to\nscore points.\n\n## Juneau vs
Jackson\n\n| Feature | Juneau | Jackson |\n|---------|--------|---------|\n|
**Multi-format support* [...]
{"description": "Apache Juneau\u2122 offers a unique combination of
simplicity, power, and zero-dependency design that makes it an excellent choice
for modern Java development. Here's why developers choose Juneau over
alternatives.\n\n## The Juneau Advantage\n\n### **Zero Dependencies, Maximum
Power**\n\nUnlike other frameworks that require multiple dependencies and
complex configurations, Juneau provides comprehensive functionality with
minimal external requirements:\n\n**Juneau:**\n``` [...]
{"description": "The juneau-commons module is the foundational layer of the
Juneau ecosystem.\nIt has no framework dependencies \u2014 just Java \u2014 and
provides the low-level utilities, collections, I/O helpers,\nreflection tools,
settings management, and dependency-injection support that all other Juneau
modules build on top of.\nBecause every other Juneau module depends on it
transitively, its classes are always on the classpath whenever you\nuse
Juneau.\n\n<DependencyInfo artifact [...]
@@ -120,7 +120,7 @@
{"description": "The
[org.apache.juneau.commons.http](/site/apidocs/org/apache/juneau/commons/http/package-summary.html)
package provides lightweight, dependency-free primitives for parsing and
modeling HTTP header values \u2014 media types, content-negotiation ranges, and
name/value parameters \u2014 as defined by RFC 2616.\n\n## Media Types and
Negotiation\n\n### <java-class><a
href=\"/site/apidocs/org/apache/juneau/commons/http/MediaType.html\"
target=\"_blank\">MediaType</a></java-cl [...]
{"description": "The
[org.apache.juneau.commons.httppart](/site/apidocs/org/apache/juneau/commons/httppart/package-summary.html)
package provides the shared enumerations and exception used to describe HTTP
\"parts\" (query parameters, path variables, headers, form data, and
request/response bodies) for OpenAPI-schema-based serialization and
parsing.\n\n## Part Enumerations\n\n### <java-enum><a
href=\"/site/apidocs/org/apache/juneau/commons/httppart/HttpPartType.html\"
target=\"_blank\">H [...]
{"description": "The
[org.apache.juneau.commons.concurrent](/site/apidocs/org/apache/juneau/commons/concurrent/package-summary.html)
package provides small concurrency helpers that make locks and atomic
references work cleanly with try-with-resources and `Optional`-style
APIs.\n\n## Auto-Closeable Locks\n\n### <java-class><a
href=\"/site/apidocs/org/apache/juneau/commons/concurrent/SimpleLock.html\"
target=\"_blank\">SimpleLock</a></java-class>\nAn `AutoCloseable` wrapper
around a `java. [...]
-{"description": "The
[org.apache.juneau.commons.logging](/site/apidocs/org/apache/juneau/commons/logging/package-summary.html)
package provides thin extensions over `java.util.logging` that add lazy
message formatting and in-memory log capture for testing.\n\n## Logger\n\n###
<java-class><a
href=\"/site/apidocs/org/apache/juneau/commons/logging/Logger.html\"
target=\"_blank\">Logger</a></java-class>\nAn extended logger that wraps an
underlying `java.util.logging.Logger` and adds convenie [...]
+{"description": "The
[org.apache.juneau.commons.logging](/site/apidocs/org/apache/juneau/commons/logging/package-summary.html)
package provides thin extensions over `java.util.logging` that add lazy
message formatting and in-memory log capture for testing.\n\n## Logger\n\n###
<java-class><a
href=\"/site/apidocs/org/apache/juneau/commons/logging/Logger.html\"
target=\"_blank\">Logger</a></java-class>\nAn extended logger that wraps an
underlying `java.util.logging.Logger` and adds convenie [...]
{"description": "The
[org.apache.juneau.commons.runtime](/site/apidocs/org/apache/juneau/commons/runtime/package-summary.html)
package provides lean accessors for two common runtime inputs: command-line
arguments and JAR manifest files.\n\n## Command-Line Arguments\n\n###
<java-class><a
href=\"/site/apidocs/org/apache/juneau/commons/runtime/Args.html\"
target=\"_blank\">Args</a></java-class>\nA lean parser for command-line
arguments passed to a `main(String[])` method. It supports positi [...]
{"description": "The
[org.apache.juneau.commons.time](/site/apidocs/org/apache/juneau/commons/time/package-summary.html)
package provides a precision-aware date/time type for granular time
operations.\n\n## Granular Date/Time\n\n### <java-class><a
href=\"/site/apidocs/org/apache/juneau/commons/time/GranularZonedDateTime.html\"
target=\"_blank\">GranularZonedDateTime</a></java-class>\nPairs a
`java.time.ZonedDateTime` with a `ChronoField` precision identifier, enabling
granular time opera [...]
{"description": "<DependencyInfo artifact=\"juneau-marshall\"
bundle=\"org.apache.juneau.marshall\" />\n\n## Contents/Features\n\n-
Foundation for all serializers and parsers.\n- Implementations for all
serializers and parsers except RDF languages.\n- Various reusable utilities
used throughout the framework.\n\n## Overview\n\nThe **juneau-marshall**
library includes easy-to-use and highly customizable serializers and parsers
based around a common\nAPI.\nIt allows you to marshall Java POJ [...]
@@ -359,8 +359,8 @@
{"description": "The <a
href=\"/site/apidocs/org/apache/juneau/rest/server/Rest.html#encoders()\"
target=\"_blank\">@Rest(encoders)</a> annotation can be used to\nassociate
character encoders with a servlet class.\nEncoders can be used to enable
various kinds of compression (e.g. `gzip`) on requests and responses based on
the request\n`Accept-Encoding` and `Content-Encoding` headers.\n\n:::tip
Example\n```java\n// Servlet with automated support for GZIP
compression\n@Rest(encoders={GzipE [...]
{"description": ":::warning Outdated examples (9.5)\nExamples on this page
using `RestContext.Builder` is pre-9.5 and kept only for historical
context.\nUse `Config` parameter injection in `@RestOp` methods, `@Bean` beans,
or `RestContext.getConfig()`\nfrom a supported `@RestInit` parameter. See the
[v9.5 Migration Guide](/docs/release-notes/9.5.0).\n:::\n\nThe Server API
provides methods for associating configuration files with REST servlets so that
configuration properties\ncan be defi [...]
{"description": ":::warning Outdated examples (9.5)\nExamples on this page
using `RestContext.Builder` / `builder.vars(...)` is pre-9.5 and kept only\nfor
historical context. Register custom vars through `@Bean(name=\"varResolver\")`
with a\n`VarResolver` (or `VarResolver.Builder`) supplier. See the\n[v9.5
Migration Guide](/docs/release-notes/9.5.0).\n:::\n\nIn the previous examples,
there were several cases where embedded variables were contained within
annotation values:\n\n```java\n@R [...]
-{"description": "The <a
href=\"/site/apidocs/org/apache/juneau/rest/server/servlet/BasicRestServlet.html\"
target=\"_blank\">BasicRestServlet</a> and <a
href=\"/site/apidocs/org/apache/juneau/rest/server/servlet/BasicRestResource.html\"
target=\"_blank\">BasicRestResource</a> classes come with built-in support for
serving up static files through the <a
href=\"/site/apidocs/org/apache/juneau/rest/server/ops/HtdocMixin.html\"
target=\"_blank\">HtdocMixin</a> op-mixin, which provides the fo [...]
-{"description": "The Juneau REST server ships with
a\n[`StaticFilesMixin`](/site/apidocs/org/apache/juneau/rest/server/staticfile/StaticFilesMixin.html)\nmixin
in the
[`org.apache.juneau.rest.server.staticfile`](/site/apidocs/org/apache/juneau/rest/server/staticfile/package-summary.html)\npackage
that wraps the existing
[`BasicStaticFiles`](/site/apidocs/org/apache/juneau/rest/server/staticfile/BasicStaticFiles.html)\nplumbing
(a `StaticFiles` implementation, not a servlet) in a servlet- [...]
+{"description": "The <a
href=\"/site/apidocs/org/apache/juneau/rest/server/servlet/BasicRestServlet.html\"
target=\"_blank\">BasicRestServlet</a> and <a
href=\"/site/apidocs/org/apache/juneau/rest/server/servlet/BasicRestResource.html\"
target=\"_blank\">BasicRestResource</a> classes come with built-in support for
serving up static files through the <a
href=\"/site/apidocs/org/apache/juneau/rest/server/ops/HtdocMixin.html\"
target=\"_blank\">HtdocMixin</a> op-mixin, which provides the fo [...]
+{"description": "The Juneau REST server ships with
a\n[`StaticFilesMixin`](/site/apidocs/org/apache/juneau/rest/server/staticfile/StaticFilesMixin.html)\nmixin
in the
[`org.apache.juneau.rest.server.staticfile`](/site/apidocs/org/apache/juneau/rest/server/staticfile/package-summary.html)\npackage
that wraps the existing
[`BasicStaticFiles`](/site/apidocs/org/apache/juneau/rest/server/staticfile/BasicStaticFiles.html)\nplumbing
(a `StaticFiles` implementation, not a servlet) in a servlet- [...]
{"description": "The Juneau REST server ships with a four-class
**convention-endpoints mixin pack**
in\n[`org.apache.juneau.rest.server.convention`](/site/apidocs/org/apache/juneau/rest/server/convention/package-summary.html)\ncovering
the small set of de-facto-standard URLs that every public-facing service
eventually has\nto wire up by hand: the browser favicon, the SEO contracts
(`robots.txt`, `sitemap.xml`), a\nJSON deployment-introspection endpoint, and
the RFC 8615 `/.well-known/*` [...]
{"description": "The Juneau REST server ships with a three-class **ops /
introspection mixin pack**
in\n[`org.apache.juneau.rest.server.ops`](/site/apidocs/org/apache/juneau/rest/server/ops/package-summary.html)\ncovering
the operational surface every long-running service eventually grows: a
request-echo\nendpoint for round-trip debugging, a JVM admin surface for thread
/ heap / cache /\nrate-limit visibility, and a route-index endpoint for
navigation. Each mixin is a single-purpose\n`@R [...]
{"description": "The `juneau-rest-server-view-jsp` module adds JSP (JavaServer
Pages) view-rendering to\n`juneau-rest-server` without bleeding the JSP-engine
dependency (Apache Jasper) into the core.\n\n> This page covers the
JSP-specific bridge. For the engine-agnostic\n>
[`View`](/site/apidocs/org/apache/juneau/rest/server/view/View.html) interface
itself, see the\n> [9.5.0 release notes](/docs/release-notes/9.5.0) under the
`juneau-rest-server` section.\n> Sibling view modules [Thymel [...]
diff --git a/static/ai/manifest.json b/static/ai/manifest.json
index 3c9b7c6d9f..280e3452a8 100644
--- a/static/ai/manifest.json
+++ b/static/ai/manifest.json
@@ -3,8 +3,8 @@
"record_count": 507,
"schema_version": "1.0.0",
"source_commit": {
- "juneau": "a8ee40428f42e51de1d62cabe01b9d77261c2cc0",
- "juneau_docs": "e7b3d653d49551c2c15e8630ad402b10ea00ab90"
+ "juneau": "014158eb25e8f44b49fd7c62a946007a268550c3",
+ "juneau_docs": "a639636f18e9f136076f6aa7219b006d89f2fca3"
},
"version": "10.0.0"
}