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 bda66a6299 Fix remaining Section A docs gaps, BinaryFormat byte[]
handling, GitControl SecretStore adoption, README refresh (TODO-350/352/353/354)
bda66a6299 is described below
commit bda66a6299ecb3aa65f7bbf3c4e180d06a9a7ddd
Author: James Bognar <[email protected]>
AuthorDate: Thu Aug 13 13:52:00 2026 -0400
Fix remaining Section A docs gaps, BinaryFormat byte[] handling, GitControl
SecretStore adoption, README refresh (TODO-350/352/353/354)
TODO-350: completes Section A of the docs-gap sweep — all remaining MED and
LOW items (fabricated-API corrections, method renames, dead links,
compile-breaking snippets) across ~55 juneau-docs topic pages. Section A is now
100% triaged.
TODO-353: Bson/Cbor/MsgPack serializers now honor the configured
BinaryFormat for byte[] output, and the parser sessions decode
BinaryFormat-encoded byte[] elements instead of a lossy UTF-8 conversion (a
latent parse-side bug exposed once the write side stopped emitting native
binary). Untyped-Map.class recovery limits documented as inherent.
TODO-352: GitControl adopts the new SecretStore SPI via an opt-in
BeanStore-resolved constructor (char[] token lookup, close() zeroes the
provider); anonymous and caller-supplied constructors unchanged, no
default-behavior regression. Docs gain a SecretStore/BeanStore credential
snippet.
TODO-354: refreshes the root README — MCP section, aggregator-grouped
module inventory (incl. juneau-secret-keychain and
juneau-rest-server-datatables), 10.0.0-SNAPSHOT pins, and a 9.x->10.0 upgrade
callout. Also adds the juneau-secret-keychain docs-inventory row.
---
pages/topics/01.00.JuneauEcosystemOverview.md | 2 +-
pages/topics/01.02.WhyJuneau.md | 2 +-
pages/topics/02.03.JuneauCommonsLang.md | 47 ++++++
pages/topics/02.07.JuneauCommonsFunction.md | 16 +++
pages/topics/02.14.JuneauCommonsConcurrent.md | 31 ++++
pages/topics/03.00.JuneauMarshall.md | 8 +-
pages/topics/03.02.SerializersAndParsers.md | 20 +--
pages/topics/03.03.00.BeanContexts.md | 5 +-
pages/topics/03.03.03.BeanTypeAnnotation.md | 2 +-
pages/topics/03.03.15.ExampleAnnotation.md | 2 +-
pages/topics/03.04.HttpPartSerializersParsers.md | 2 +-
pages/topics/03.05.ContextSettings.md | 2 +-
pages/topics/03.07.ContextAnnotations.md | 8 +-
pages/topics/03.08.JsonMap.md | 2 +-
pages/topics/03.10.ComplexDataTypes.md | 6 +-
pages/topics/03.11.SupportedJdkDatatypes.md | 6 +-
pages/topics/03.13.00.Swaps.md | 2 +-
pages/topics/03.13.05.SwapAnnotation.md | 2 +-
pages/topics/03.13.06.TemplatedSwaps.md | 2 +-
.../topics/03.14.DynamicallyAppliedAnnotations.md | 2 +-
pages/topics/03.16.VirtualBeans.md | 4 +-
pages/topics/03.18.ParsingIntoGenericModels.md | 4 +-
pages/topics/03.25.06.JsonSchemaDetails.md | 2 +-
pages/topics/03.26.07.XmlNamespaces.md | 1 -
pages/topics/03.27.05.HtmlRenderAnnotation.md | 2 +-
pages/topics/03.27.08.HtmlCustomTemplates.md | 8 +-
pages/topics/06.13.SystemDefaultConfig.md | 25 ++--
pages/topics/09.05.HttpEntitiesAndResources.md | 2 +-
pages/topics/10.02.03.PathVariables.md | 2 +-
.../topics/10.03.01.InferredHttpMethodsAndPaths.md | 4 +-
pages/topics/10.03.06.Matchers.md | 2 +-
pages/topics/10.04.04.RequestBeans.md | 6 +-
pages/topics/10.06.HandlingFormPosts.md | 1 +
pages/topics/10.14.Guards.md | 6 +-
pages/topics/10.16.LocalizedMessages.md | 2 +-
pages/topics/10.18.ConfigurationFiles.md | 1 +
pages/topics/10.19.RestServerSvlVariables.md | 2 +-
pages/topics/10.31.02.HtmlWidgets.md | 2 +-
pages/topics/10.31.03.HtmlPredefinedWidgets.md | 21 ++-
pages/topics/10.31.04.HtmlUiCustomization.md | 4 +-
pages/topics/10.37.RestServerTestBeanInjection.md | 6 +-
pages/topics/10.51.SessionOptions.md | 4 +-
pages/topics/10.52.UsingWithOsgi.md | 2 +-
pages/topics/10.55.ResponseProcessors.md | 14 +-
pages/topics/10.56.RestRpc.md | 160 +++++++++++----------
pages/topics/10.60.OtherNotes.md | 4 +-
pages/topics/10.61.Log4j.md | 10 ++
pages/topics/11.04.JuneauRestServerMcp.md | 14 +-
pages/topics/13.05.ResponseHeaders.md | 2 +-
pages/topics/13.12.ExtendingRestClient.md | 4 +-
pages/topics/13.13.00.Authentication.md | 15 +-
pages/topics/13.13.02.AuthenticationForm.md | 2 +-
pages/topics/16.03.ResourceClasses.md | 4 +-
pages/topics/26.V9MigrationGuide.md | 2 +-
src/pages/about.md | 2 +
55 files changed, 329 insertions(+), 186 deletions(-)
diff --git a/pages/topics/01.00.JuneauEcosystemOverview.md
b/pages/topics/01.00.JuneauEcosystemOverview.md
index d0e4de4504..29b064c17b 100644
--- a/pages/topics/01.00.JuneauEcosystemOverview.md
+++ b/pages/topics/01.00.JuneauEcosystemOverview.md
@@ -43,7 +43,7 @@ The Juneau ecosystem consists of the following parts:
| [juneau‑commons](/docs/topics/JuneauCommons) | Common utilities and APIs
used across the Juneau ecosystem (collections, I/O, reflection, settings, SVL,
etc.) | • *None* |
| [juneau‑test](/docs/topics/JuneauTest) | Fluent-style assertions,
Bean-Centric Testing, and JUnit 5 extensions / test-time bean injection | •
JUnit 5 |
| [juneau‑config](/docs/topics/JuneauConfig) | Configuration File API | •
*None* |
-| [juneau‑marshall](/docs/topics/JuneauMarshall) | Serializers and parsers for
JSON (various flavors), XML, HTML, URL-Encoding, UON, OpenAPI, PlainText, CSV,
SOAP, and MessagePack | • *None* |
+| [juneau‑marshall](/docs/topics/JuneauMarshall) | Serializers and parsers for
JSON (various flavors), XML, SOAP, HTML, URL-Encoding, UON, OpenAPI,
MessagePack, CBOR, BSON, YAML, TOML, HOCON, HJSON, CSV, INI, Markdown, Parquet,
Protobuf, Prototext, SSE, and PlainText | • *None* |
| [juneau‑marshall‑rdf](/docs/topics/JuneauMarshallRdf) | Serializers and
parsers for RDF/XML (various flavors), N3, NTriple, and Turtle | • Apache Jena
5.x |
|
[juneau‑test‑utils](https://github.com/apache/juneau/tree/master/juneau-core/juneau-test-utils)
| Shared test infrastructure (commons-level; no juneau-marshall dependency) |
• *None* |
| **juneau-bean** | | |
diff --git a/pages/topics/01.02.WhyJuneau.md b/pages/topics/01.02.WhyJuneau.md
index 2bdab580bc..c0de2942c1 100644
--- a/pages/topics/01.02.WhyJuneau.md
+++ b/pages/topics/01.02.WhyJuneau.md
@@ -58,7 +58,7 @@ String html = Html.of(person);
// URL-Encoding
String urlEnc = UrlEncoding.of(person);
-// And 34 more
+// And dozens more (38+ formats total)
```
**With alternatives, you need different libraries and APIs for each format.**
diff --git a/pages/topics/02.03.JuneauCommonsLang.md
b/pages/topics/02.03.JuneauCommonsLang.md
index f9237ae636..c313556711 100644
--- a/pages/topics/02.03.JuneauCommonsLang.md
+++ b/pages/topics/02.03.JuneauCommonsLang.md
@@ -60,6 +60,43 @@ counter.decrement(); // 0L
long value = counter.getAndIncrement(); // Returns 0L, then sets to 1L
```
+### <java-class><a
href="/site/apidocs/org/apache/juneau/commons/lang/ByteHolder.html"
target="_blank">ByteHolder</a></java-class>
+Mutable byte with additional convenience methods.
+
+```java
+ByteHolder counter = ByteHolder.create(); // Initialized to 0
+counter.increment(); // 1
+counter.decrement(); // 0
+byte value = counter.incrementAndGet(); // Returns 1
+```
+
+### <java-class><a
href="/site/apidocs/org/apache/juneau/commons/lang/ShortHolder.html"
target="_blank">ShortHolder</a></java-class>
+Mutable short with additional convenience methods.
+
+```java
+ShortHolder counter = ShortHolder.create(); // Initialized to 0
+counter.increment(); // 1
+short value = counter.getAndIncrement(); // Returns 1, then sets to 2
+```
+
+### <java-class><a
href="/site/apidocs/org/apache/juneau/commons/lang/CharHolder.html"
target="_blank">CharHolder</a></java-class>
+Mutable character with convenience methods for incrementing/decrementing and
matching against a set of characters.
+
+```java
+CharHolder ch = CharHolder.of('A');
+ch.increment(); // 'B'
+boolean found = ch.isAny("XYZB"); // true - matches a character in the string
+```
+
+### <java-class><a
href="/site/apidocs/org/apache/juneau/commons/lang/DoubleHolder.html"
target="_blank">DoubleHolder</a></java-class> and <java-class><a
href="/site/apidocs/org/apache/juneau/commons/lang/FloatHolder.html"
target="_blank">FloatHolder</a></java-class>
+Mutable double/float with precision-based equality checks, since exact `==`
comparisons on floating-point values are unreliable.
+
+```java
+DoubleHolder pi = DoubleHolder.of(3.14159);
+boolean close = pi.is(3.14, 0.01); // true - within 0.01
+boolean anyClose = pi.isAny(0.01, 1.0, 3.15, 5.0); // true - matches 3.15
within 0.01
+```
+
### <java-class><a
href="/site/apidocs/org/apache/juneau/commons/lang/BooleanHolder.html"
target="_blank">BooleanHolder</a></java-class>
Nullable boolean with convenience methods.
@@ -100,6 +137,16 @@ if (name.isAny("John", "Jane", "Bob")) {
}
```
+### <java-class><a
href="/site/apidocs/org/apache/juneau/commons/lang/WeightedAverage.html"
target="_blank">WeightedAverage</a></java-class>
+Accumulates a running weighted average of numbers, re-weighting on each call
to `add(int, Number)`.
+
+```java
+WeightedAverage avg = new WeightedAverage();
+avg.add(2, 10.0); // weight 2, value 10.0
+avg.add(1, 40.0); // weight 1, value 40.0
+double result = avg.getValue(); // (10.0*2 + 40.0*1) / 3 = 20.0
+```
+
### <java-class><a
href="/site/apidocs/org/apache/juneau/commons/lang/StringFormat.html"
target="_blank">StringFormat</a></java-class>
Cacheable printf-style string formatter (backed by `String.format` semantics).
diff --git a/pages/topics/02.07.JuneauCommonsFunction.md
b/pages/topics/02.07.JuneauCommonsFunction.md
index 37f8b1e05e..720ac3b380 100644
--- a/pages/topics/02.07.JuneauCommonsFunction.md
+++ b/pages/topics/02.07.JuneauCommonsFunction.md
@@ -49,6 +49,22 @@ Config c = config.get(); // computed once
config.reset(); // next get() recomputes
```
+### <java-class><a
href="/site/apidocs/org/apache/juneau/commons/function/Suppliers.html"
target="_blank">Suppliers</a></java-class>
+Static factory methods for creating memoizing suppliers, without needing to
call the `NullableSupplier`/`Memoizer` constructors directly.
+
+- <c>Suppliers.memoize(Supplier)</c> — wraps a `Supplier` in a thread-safe,
non-resettable memoizing `NullableSupplier`. The underlying supplier is invoked
at most once (races are tolerated — if multiple threads call `get()` before the
first result is cached, the supplier may be invoked more than once, but every
caller ends up with the same cached value).
+- <c>Suppliers.memoizer(Supplier)</c> — wraps a `Supplier` in a resettable
`Memoizer`, equivalent to `new Memoizer<>(supplier)`.
+
+```java
+// One-shot memoization - no reset needed
+NullableSupplier<Config> config = Suppliers.memoize(() ->
loadExpensiveConfig());
+Config c = config.get(); // computed once and cached
+
+// Resettable memoization - equivalent to new Memoizer<>(supplier)
+Memoizer<Config> config2 = Suppliers.memoizer(() -> loadExpensiveConfig());
+config2.reset(); // next get() recomputes
+```
+
## Tuples
Immutable value tuples with content-based `equals()`/`hashCode()` — handy as
composite map keys.
diff --git a/pages/topics/02.14.JuneauCommonsConcurrent.md
b/pages/topics/02.14.JuneauCommonsConcurrent.md
index e64d10de74..ee909c9252 100644
--- a/pages/topics/02.14.JuneauCommonsConcurrent.md
+++ b/pages/topics/02.14.JuneauCommonsConcurrent.md
@@ -40,3 +40,34 @@ NullableReference<String> ref =
NullableReference.of("hello");
boolean present = ref.isPresent();
NullableReference<Integer> len = ref.map(String::length);
```
+
+## Replay Detection
+
+### <java-interface><a
href="/site/apidocs/org/apache/juneau/commons/concurrent/ReplayCache.html"
target="_blank">ReplayCache</a></java-interface>
+An SPI for detecting reuse ("replay") of a one-time-use identifier, such as a
nonce or a single-use token. `checkAndRecord(String, long)` atomically checks
whether an identifier has been seen before *and* records it as seen, as one
indivisible operation — of any two concurrent calls with the same identifier,
at most one returns `true` (first-seen).
+
+When the backing store can't answer (for example a remote store is
unreachable), the consumer decides how the failure is resolved by passing a
`ReplayCache.FailMode` to `checkAndRecord(String, long, ReplayCache.FailMode,
Consumer)`:
+
+- `ReplayCache.FailMode.FAIL_CLOSED` (the safe default) — treats a store
failure as a replay (reject).
+- `ReplayCache.FailMode.FAIL_OPEN` — treats a store failure as
first-seen (allow), degrading to the multi-use-tolerant behavior a consumer
would have with no `ReplayCache` wired at all.
+
+`ReplayCache.FailMode` is a nested enum declared on `ReplayCache` itself — it
is unrelated to any other `FailMode` class that may exist elsewhere in the
framework.
+
+```java
+ReplayCache cache = new InMemoryReplayCache();
+
+long expiresAtMs = System.currentTimeMillis() + 60_000L;
+boolean firstUse = cache.checkAndRecord(nonce, expiresAtMs,
ReplayCache.FailMode.FAIL_CLOSED);
+if (!firstUse) {
+ throw new SecurityException("Replayed nonce detected");
+}
+```
+
+### <java-class><a
href="/site/apidocs/org/apache/juneau/commons/concurrent/InMemoryReplayCache.html"
target="_blank">InMemoryReplayCache</a></java-class>
+The built-in, zero-config `ReplayCache` implementation: a per-process
`ConcurrentHashMap`-backed seen-identifier set, with self-eviction bounded by
each record's own `expiresAtMs`. Eviction sweeps are throttled to at most once
per `InMemoryReplayCache.DEFAULT_SWEEP_INTERVAL_MS` (1000 ms by default) to
keep `checkAndRecord()` cheap under load.
+
+Because it's per-process memory, `InMemoryReplayCache` only enforces
single-use within one JVM — two instances behind a load balancer will not see
each other's recorded identifiers. Consumers who need cross-node single-use
enforcement must supply their own `ReplayCache` backed by a store shared across
every node.
+
+```java
+InMemoryReplayCache cache = new InMemoryReplayCache();
+```
diff --git a/pages/topics/03.00.JuneauMarshall.md
b/pages/topics/03.00.JuneauMarshall.md
index 08d95066dc..f476edf3f1 100644
--- a/pages/topics/03.00.JuneauMarshall.md
+++ b/pages/topics/03.00.JuneauMarshall.md
@@ -196,9 +196,9 @@ Beans and POJO classes, methods, fields, and constructors
can also be annotated
customize how they are marshalled:
```java
-// Sort bean properties by name.
+// Disable alphabetical sorting of bean properties (bean properties are sorted
by default).
// Exclude city/state from marshalling.
-@BeanType(sort=true, excludeProperties="city,state")
+@BeanType(unsorted=true, excludeProperties="city,state")
public class Address { ... }
// Specify an implementation class for an interface.
@@ -249,7 +249,7 @@ be used to set the default value for the sort properties
setting.
Bean annotations can also be programmatically attached to POJOs using config
annotations like so:
```java
-@BeanTypeApply(onClass=Address.class, value=@BeanType(sort=true,
excludeProperties="city,state"))
+@BeanTypeApply(onClass=Address.class, value=@BeanType(unsorted=true,
excludeProperties="city,state"))
public class MyAnnotatedClass {...}
```
@@ -265,7 +265,7 @@ The Marshalling API also supports schema-based OpenAPI
serialization.
It allows HTTP parts to be marshalled to-and-from POJOs based on OpenAPI
schema definitions.
```java
-import static org.apache.juneau.httpart.HttpPartSchema.*;
+import static org.apache.juneau.marshall.httppart.HttpPartSchema.*;
// Schema - Pipe-delimited list of comma-delimited longs.
HttpPartSchema schema = tArrayPipes().items(
diff --git a/pages/topics/03.02.SerializersAndParsers.md
b/pages/topics/03.02.SerializersAndParsers.md
index c58c9de7cd..3b87ca2d1f 100644
--- a/pages/topics/03.02.SerializersAndParsers.md
+++ b/pages/topics/03.02.SerializersAndParsers.md
@@ -92,7 +92,7 @@ String json = "{name:'John Smith',age:21}";
Person person = parser.read(json, Person.class);
// Or parse it into a generic Map.
-Map map = parser.read(json, Map.class);
+Map<String,Object> map = parser.read(json, Map.class);
// Parse a JSON string.
json = "'foobar'";
@@ -105,16 +105,16 @@ Float _float = parser.read(json, Float.class);
// Parse a JSON object as a HashMap.
json = "{a:{name:'John Smith',age:21},b:{name:'Joe Smith',age:42}}";
-Map map2 = parser.read(json, HashMap.class, String.class, Person.class)
+Map<String,Person> map2 = parser.read(json, HashMap.class, String.class,
Person.class);
-// Parse a JSON object as a HashMap>.
+// Parse a JSON object as a HashMap<String,List<Person>>.
json = "{a:[{name:'John Smith',age:21},{name:'Joe Smith',age:42}]}";
-Map> map3 = parser.read(json, HashMap.class, String.class,
- LinkedList.class, Person.class)
+Map<String,List<Person>> map3 = parser.read(json, HashMap.class, String.class,
+ LinkedList.class, Person.class);
// Parse a JSON array of integers as a Collection of Integers or int[] array.
json = "[1,2,3]";
-List list = parser.read(json, LinkedList.class, Integer.class);
+List<Integer> list = parser.read(json, LinkedList.class, Integer.class);
int[] ints = parser.read(json, int[].class);
```
@@ -131,12 +131,12 @@ parser.parseIntoBean(json, person);
// Populate an existing list from a JSON array of numbers.
json = "[1,2,3]";
-List list = new LinkedList();
+List<Integer> list = new LinkedList<>();
parser.readIntoCollection(json, list, Integer.class);
// Populate an existing map from a JSON object containing beans.
json = "{a:{name:'John Smith',age:21},b:{name:'Joe Smith',age:42}}";
-Map map = new TreeMap();
+Map<String,Person> map = new TreeMap<>();
parser.readIntoMap(json, map, String.class, Person.class);
```
@@ -240,10 +240,10 @@ public class MyResource extends BasicRestServlet {
}
```
-Clients send options using the `X-Juneau-Serializer-Options` header (JSON5
format) or `juneauSerializerOptions` query parameter (UON format):
+Clients send options using the `X-Juneau-Serializer-Options` header (JSON5
format) or `juneauSerializerOptions` query parameter (UON format). The
`serializerSessionOptionsHeader(...)` and `serializerSessionOptionsQuery(...)`
convenience methods live on the classic REST client stack (`RestClient`
(classic) / `org.apache.juneau.rest.client.classic`) only — the default
next-generation `RestClient` does not have them:
```java
-// Client using Juneau REST client
+// Client using Juneau REST client (classic)
RestClient client = RestClient.create()
.rootUrl("http://localhost:8080/myresource")
.build();
diff --git a/pages/topics/03.03.00.BeanContexts.md
b/pages/topics/03.03.00.BeanContexts.md
index e0f131a0f0..4992162933 100644
--- a/pages/topics/03.03.00.BeanContexts.md
+++ b/pages/topics/03.03.00.BeanContexts.md
@@ -135,7 +135,6 @@ It also records the active object swaps and format
overrides for that type.
ClassMeta<Person> cm = MarshallingContext.DEFAULT.getClassMeta(Person.class);
cm.isBean(); // true
cm.isMap(); // false
-cm.getCategory(); // ClassMeta.Category.BEAN
```
---
@@ -181,11 +180,11 @@ public class Contact {
public String fullName;
// Read-only — serialized but ignored on parse.
- @BeanProp(ro = true)
+ @BeanProp(ro = "true")
public String getCreatedAt() { ... }
// Write-only — accepted on parse but not serialized.
- @BeanProp(wo = true)
+ @BeanProp(wo = "true")
public void setPassword(String pw) { ... }
}
```
diff --git a/pages/topics/03.03.03.BeanTypeAnnotation.md
b/pages/topics/03.03.03.BeanTypeAnnotation.md
index de6a3a12cc..6be289db33 100644
--- a/pages/topics/03.03.03.BeanTypeAnnotation.md
+++ b/pages/topics/03.03.03.BeanTypeAnnotation.md
@@ -128,7 +128,7 @@ in JSON and element names in XML.
```java
// Define a class with dashed-lowercase property names.
-@BeanType(propertyNamer=PropertyNamerDashedLC.class)
+@BeanType(propertyNamer=PropertyNamerDLC.class)
public class MyBean { ... }
```
diff --git a/pages/topics/03.03.15.ExampleAnnotation.md
b/pages/topics/03.03.15.ExampleAnnotation.md
index e22a930ab8..0ef67cfb1c 100644
--- a/pages/topics/03.03.15.ExampleAnnotation.md
+++ b/pages/topics/03.03.15.ExampleAnnotation.md
@@ -98,7 +98,7 @@ example.
## Variable Resolution
The JSON5 string forms support
-<a href="/site/apidocs/org/apache/juneau/marshall/Example.html"
target="_blank">VarResolver.DEFAULT</a> substitution, so
+<a href="/site/apidocs/org/apache/juneau/commons/svl/VarResolver.html#DEFAULT"
target="_blank">VarResolver.DEFAULT</a> substitution, so
an example value can reference configuration and other variables that are
resolved when the example is read:
```java
diff --git a/pages/topics/03.04.HttpPartSerializersParsers.md
b/pages/topics/03.04.HttpPartSerializersParsers.md
index b9ed958bc4..0e9f0d28dc 100644
--- a/pages/topics/03.04.HttpPartSerializersParsers.md
+++ b/pages/topics/03.04.HttpPartSerializersParsers.md
@@ -37,7 +37,7 @@ methods for creation of custom schemas.
The equivalent to the schema above can be structured like so:
```java
-import static org.apache.juneau.httppart.HttpPartSchema.*;
+import static org.apache.juneau.marshall.httppart.HttpPartSchema.*;
// Schema information about our part.
HttpPartSchema schema = tArrayPipes(tArrayCsv(tInt64())).build();
diff --git a/pages/topics/03.05.ContextSettings.md
b/pages/topics/03.05.ContextSettings.md
index 3426128af2..73d0e0f759 100644
--- a/pages/topics/03.05.ContextSettings.md
+++ b/pages/topics/03.05.ContextSettings.md
@@ -224,7 +224,7 @@ String html2 = HtmlSerializer.DEFAULT
|---|---|---|---|
| `byteArrayFormat` / `CsvSerializerSession.byteArrayFormat` |
`ByteArrayFormat` | `CsvSerializerSession` | Format for `byte[]` values (e.g.
`BASE64`, `HEX`, `SEMICOLON_DELIMITED`) |
| `allowNestedStructures` / `CsvSerializerSession.allowNestedStructures` |
`boolean` | `CsvSerializerSession` | Allow nested bean structures in CSV output
|
-| `nullValue` / `CsvSerializerSession.nullValue` | `String` |
`CsvSerializerSession` | String representation for `null` values (default:
empty string) |
+| `nullValue` / `CsvSerializerSession.nullValue` | `String` |
`CsvSerializerSession` | String representation for `null` values (default:
`<NULL>`) |
```java
// Use "N/A" for null values in CSV output
diff --git a/pages/topics/03.07.ContextAnnotations.md
b/pages/topics/03.07.ContextAnnotations.md
index c9e3da2d3e..0b988e1660 100644
--- a/pages/topics/03.07.ContextAnnotations.md
+++ b/pages/topics/03.07.ContextAnnotations.md
@@ -29,7 +29,7 @@ Config annotations defined on classes and methods can be
applied to serializers
<tree>
<node-0><java-class><a
href="/site/apidocs/org/apache/juneau/marshall/MarshallingContext.Builder.html"
target="_blank">MarshallingContext.Builder</a></java-class></node-0>
<node-1><java-method><a
href="/site/apidocs/org/apache/juneau/marshall/MarshallingContext.Builder.html#applyAnnotations(java.lang.Class...)"
target="_blank">applyAnnotations(Class...)</a></java-method></node-1>
-<node-1><java-method><a
href="/site/apidocs/org/apache/juneau/marshall/MarshallingContext.Builder.html#applyAnnotations(java.lang.Object...)"
target="_blank">applyAnnotations(Method...)</a></java-method></node-1>
+<node-1><java-method><a
href="/site/apidocs/org/apache/juneau/marshall/MarshallingContext.Builder.html#applyAnnotations(java.lang.Object...)"
target="_blank">applyAnnotations(Object...)</a></java-method></node-1>
</tree>
The following example shows how annotations defined on a dummy class can be
applied to a serializer:
@@ -40,7 +40,7 @@ The following example shows how annotations defined on a
dummy class can be appl
public static class DummyClass {}
WriterSerializer serializer =
JsonSerializer.create().applyAnnotations(DummyClass.class).build();
-String json = serializer.toString(addressBean);
+String json = serializer.write(addressBean);
```
Config annotations are provided for all serializers and parsers:
@@ -66,7 +66,7 @@ public class Address {...}
BeanType bt = new
BeanTypeAnnotation("Address").properties("street,city,state");
WriterSerializer serializer = JsonSerializer.create().annotations(bt).build();
-String json = serializer.toString(addressBean); // Will print street,city,state
+String json = serializer.write(addressBean); // Will print street,city,state
```
Concrete annotation implementations are provided for all annotations.
@@ -81,5 +81,5 @@ public class Address {...}
BeanType beanTypeAnnotation = new
BeanTypeAnnotation("Address").properties("street,city,state");
WriterSerializer serializer =
JsonSerializer.create().annotations(beanTypeAnnotation).build();
-String json = serializer.toString(addressBean); // Will print
street,city,state
+String json = serializer.write(addressBean); // Will print street,city,state
```
\ No newline at end of file
diff --git a/pages/topics/03.08.JsonMap.md b/pages/topics/03.08.JsonMap.md
index eb4f431019..e6c1ae8d72 100644
--- a/pages/topics/03.08.JsonMap.md
+++ b/pages/topics/03.08.JsonMap.md
@@ -84,7 +84,7 @@ JsonMap map2 = map.include("key1", "key2", "key3");
JsonMap map3 = map.exclude("key1", "key2", "key3");
// Serialize using another serializer.
-String xml = map.serializeTo(XmlSerializer.DEFAULT);
+String xml = XmlSerializer.DEFAULT.write(map);
// Nested maps.
map.inner(anotherMap);
diff --git a/pages/topics/03.10.ComplexDataTypes.md
b/pages/topics/03.10.ComplexDataTypes.md
index 5d43e20303..ef5cda33dd 100644
--- a/pages/topics/03.10.ComplexDataTypes.md
+++ b/pages/topics/03.10.ComplexDataTypes.md
@@ -8,8 +8,8 @@ The Juneau parsers have the ability to parse into complex data
types that consis
<tree>
<node-0><java-class><a
href="/site/apidocs/org/apache/juneau/marshall/parser/Parser.html"
target="_blank">Parser</a></java-class></node-0>
-<node-1><java-method><a
href="/site/apidocs/org/apache/juneau/marshall/parser/Parser.html#<init>(org.apache.juneau.marshall.parser.Parser.Builder)"
target="_blank">parse(Object,Class)</a></java-method></node-1>
-<node-1><java-method><a
href="/site/apidocs/org/apache/juneau/marshall/parser/Parser.html#<init>(org.apache.juneau.marshall.parser.Parser.Builder)"
target="_blank">parse(Object,Type,Type...)</a></java-method></node-1>
+<node-1><java-method><a
href="/site/apidocs/org/apache/juneau/marshall/parser/Parser.html#read(java.lang.Object,java.lang.Class)"
target="_blank">read(Object,Class)</a></java-method></node-1>
+<node-1><java-method><a
href="/site/apidocs/org/apache/juneau/marshall/parser/Parser.html#read(java.lang.Object,java.lang.reflect.Type,java.lang.reflect.Type...)"
target="_blank">read(Object,Type,Type...)</a></java-method></node-1>
</tree>
Arrays are simple enough and can be constructed using the first method:
@@ -19,7 +19,7 @@ String json = "[1,2,3]";
int[] array = Json.to(json, int[].class);
```
-For data types consisting of nested `Collections` and `Maps` such as
`Map<String,List<MyBean>>`, you need to use the second parse method that
+For data types consisting of nested `Collections` and `Maps` such as
`Map<String,List<MyBean>>`, you need to use the second read method that
allows you to define the parameter types of the `Collections` classes.
:::tip Example
diff --git a/pages/topics/03.11.SupportedJdkDatatypes.md
b/pages/topics/03.11.SupportedJdkDatatypes.md
index 899a209e18..da118ea4c0 100644
--- a/pages/topics/03.11.SupportedJdkDatatypes.md
+++ b/pages/topics/03.11.SupportedJdkDatatypes.md
@@ -27,7 +27,7 @@ swap-replacement dance:
```java
// First-class: per-type format knob on the builder.
-var s =
JsonSerializer.create().temporalFormat(TemporalFormat.ISO_LOCAL).build();
+var s =
JsonSerializer.create().temporalFormat(TemporalFormat.ISO_LOCAL_DATE_TIME).build();
// Versus the swap-based alternative you'd need without it.
var s = JsonSerializer.create().swaps(MyCustomInstantSwap.class).build();
@@ -102,8 +102,8 @@ contract, including how per-property `Nulls` coercion
interacts.
| `Duration` | ISO-8601 duration string (`"PT15M"`) | `durationFormat` |
| `Period` | ISO-8601 period string (`"P1Y2M"`) | `periodFormat` |
-The `temporalFormat` knob (enum) selects ISO-8601 (`DEFAULT`), local without
zone, RFC-1123, epoch millis, or
-a custom pattern. The `durationFormat` and `periodFormat` knobs select
ISO-8601 (default) or numeric milli /
+The `temporalFormat` knob (enum) selects ISO-8601 (`DEFAULT`), local without
zone, RFC-1123, or epoch millis.
+The `durationFormat` and `periodFormat` knobs select ISO-8601 (default) or
numeric milli /
day forms.
Legacy `java.util.Calendar` / `java.util.Date` are also supported via
`calendarFormat` / `dateFormat`.
diff --git a/pages/topics/03.13.00.Swaps.md b/pages/topics/03.13.00.Swaps.md
index 5475b7336e..fbfaf62521 100644
--- a/pages/topics/03.13.00.Swaps.md
+++ b/pages/topics/03.13.00.Swaps.md
@@ -91,7 +91,7 @@ json = serializer.write(bytes2d); // Produces
"['AQID','BAUG',null]"
bytes2d = parser.read(json, byte[][].class); // Reproduces
{{1,2,3},{4,5,6},null}
```
-The <a
href="/site/apidocs/org/apache/juneau/marshall/MarshallingContextable.Builder.html#swap(java.lang.Class,java.lang.Class,org.apache.juneau.utils.ThrowingFunction)"
target="_blank">MarshallingContextable.Builder.swap(Class,Class,ThrowingFunction)</a>
and <a
href="/site/apidocs/org/apache/juneau/marshall/MarshallingContextable.Builder.html#swap(java.lang.Class,java.lang.Class,org.apache.juneau.utils.ThrowingFunction,org.apache.juneau.utils.ThrowingFunction)"
target="_blank">Marshalli [...]
+The <a
href="/site/apidocs/org/apache/juneau/marshall/MarshallingContextable.Builder.html#swap(java.lang.Class,java.lang.Class,org.apache.juneau.commons.function.ThrowingFunction)"
target="_blank">MarshallingContextable.Builder.swap(Class,Class,ThrowingFunction)</a>
and <a
href="/site/apidocs/org/apache/juneau/marshall/MarshallingContextable.Builder.html#swap(java.lang.Class,java.lang.Class,org.apache.juneau.commons.function.ThrowingFunction,org.apache.juneau.commons.function.ThrowingFun
[...]
```java
// Use a function to convert beans to strings.
diff --git a/pages/topics/03.13.05.SwapAnnotation.md
b/pages/topics/03.13.05.SwapAnnotation.md
index b9ea43250d..965e24937c 100644
--- a/pages/topics/03.13.05.SwapAnnotation.md
+++ b/pages/topics/03.13.05.SwapAnnotation.md
@@ -37,7 +37,7 @@ Therefore it's possible to implement a swap that provides
fully-customized outpu
public class MyJsonSwap extends ObjectSwap {
public MediaType[] forMediaTypes() {
- return MediaType.forStrings("*/json");
+ return MediaType.forStrings("*/json");
}
public Reader swap(MarshallingSession session, MyPojo pojo) throws
Exception {
diff --git a/pages/topics/03.13.06.TemplatedSwaps.md
b/pages/topics/03.13.06.TemplatedSwaps.md
index 4925cb6436..5aa34af233 100644
--- a/pages/topics/03.13.06.TemplatedSwaps.md
+++ b/pages/topics/03.13.06.TemplatedSwaps.md
@@ -23,7 +23,7 @@ public class FreeMarkerSwap extends ObjectSwap {
public MediaType[] forMediaTypes() {
// Make sure this only applies to the HTML serializer.
- return MediaType.forStrings("*/html");
+ return MediaType.forStrings("*/html");
}
public Reader swap(MarshallingSession session, Object object, String
template) throws Exception {
diff --git a/pages/topics/03.14.DynamicallyAppliedAnnotations.md
b/pages/topics/03.14.DynamicallyAppliedAnnotations.md
index addd10f4c8..1d93299985 100644
--- a/pages/topics/03.14.DynamicallyAppliedAnnotations.md
+++ b/pages/topics/03.14.DynamicallyAppliedAnnotations.md
@@ -29,7 +29,7 @@ WriterSerializer serializer = JsonSerializer
.applyAnnotations(DummyClass.class)
.build();
-String json = serializer.toString(addressBean);
+String json = serializer.write(addressBean);
```
The advantage to this approach is it allows you to use Juneau annotations on
classes/methods/fields/constructors where
diff --git a/pages/topics/03.16.VirtualBeans.md
b/pages/topics/03.16.VirtualBeans.md
index 9ed69405ad..2cd7fea037 100644
--- a/pages/topics/03.16.VirtualBeans.md
+++ b/pages/topics/03.16.VirtualBeans.md
@@ -3,7 +3,7 @@ title: "Virtual Beans"
slug: VirtualBeans
---
-The <a
href="/site/apidocs/org/apache/juneau/marshall/MarshallingContext.Builder.html#disableInterfaceProxies()"
target="_blank">MarshallingContext.Builder.disableInterfaceProxies()</a>
setting (enabled by default) allows the Juneau parsers to parse content into
virtual beans (bean interfaces without implementation classes).
+By default, interface proxies are enabled, which allows the Juneau parsers to
parse content into virtual beans (bean interfaces without implementation
classes). Calling <a
href="/site/apidocs/org/apache/juneau/marshall/MarshallingContext.Builder.html#disableInterfaceProxies()"
target="_blank">MarshallingContext.Builder.disableInterfaceProxies()</a> turns
this behavior off.
For example, the following code creates an instance of the specified
unimplemented interface:
@@ -43,5 +43,5 @@ any other bean.
Virtual beans can also be created programmatically using the <a
href="/site/apidocs/org/apache/juneau/marshall/MarshallingContext.html"
target="_blank">MarshallingContext</a> class:
```java
-Address address =
MarshallingContext.DEFAULT.createSession().newBean(Address.class);
+Address address =
MarshallingContext.DEFAULT.createSession().build().newBean(Address.class);
```
\ No newline at end of file
diff --git a/pages/topics/03.18.ParsingIntoGenericModels.md
b/pages/topics/03.18.ParsingIntoGenericModels.md
index fbf5c8e0c8..ce66f3ef49 100644
--- a/pages/topics/03.18.ParsingIntoGenericModels.md
+++ b/pages/topics/03.18.ParsingIntoGenericModels.md
@@ -92,7 +92,7 @@ String name = map.getString("name");
int id = map.getInt("id");
// Get a value convertable from a String.
-URI uri = map.get(URI.class, "uri");
+URI uri = map.get("uri", URI.class);
Calendar birthDate = map.get("birthDate", Calendar.class);
@@ -100,7 +100,7 @@ Calendar birthDate = map.get("birthDate", Calendar.class);
JsonList addresses = map.getList("addresses");
// Get the first address and convert it to a bean.
-Address address = addresses.get(Address.class, 0);
+Address address = addresses.get(0, Address.class);
```
As a general rule, parsing into beans is often more efficient than parsing
into generic models.
diff --git a/pages/topics/03.25.06.JsonSchemaDetails.md
b/pages/topics/03.25.06.JsonSchemaDetails.md
index b5a6e81e8b..ad868c1b0a 100644
--- a/pages/topics/03.25.06.JsonSchemaDetails.md
+++ b/pages/topics/03.25.06.JsonSchemaDetails.md
@@ -18,7 +18,7 @@ import org.apache.juneau.bean.jsonschema.*;
JsonSchema schema = JsonSchemaBeanGenerator.DEFAULT.generate(Person.class);
// Equivalent convenience:
-JsonSchema schema2 = JsonSchema.of(Person.class);
+JsonSchema<?> schema2 = JsonSchema.of(Person.class);
```
## Schema Validation
diff --git a/pages/topics/03.26.07.XmlNamespaces.md
b/pages/topics/03.26.07.XmlNamespaces.md
index 7a63db699a..ff6a5f766c 100644
--- a/pages/topics/03.26.07.XmlNamespaces.md
+++ b/pages/topics/03.26.07.XmlNamespaces.md
@@ -51,7 +51,6 @@ Below shows it defined at the package level:
@XmlNs(prefix="mail", namespaceURI="http://www.apache.org/mail/")
}
)
-package org.apache.juneau.examples.addressbook;
```
## Sample Code
diff --git a/pages/topics/03.27.05.HtmlRenderAnnotation.md
b/pages/topics/03.27.05.HtmlRenderAnnotation.md
index 53859cbd84..72f11abc15 100644
--- a/pages/topics/03.27.05.HtmlRenderAnnotation.md
+++ b/pages/topics/03.27.05.HtmlRenderAnnotation.md
@@ -85,7 +85,7 @@ public class FileSpacePctRender extends HtmlRender<Float> {
```java
// Custom render for getStatus() method
-public class FileSpaceStatusRender extends HtmlRender {
+public class FileSpaceStatusRender extends HtmlRender<FileSpaceStatus> {
@Override
public String getStyle(SerializerSession session, FileSpaceStatus value) {
diff --git a/pages/topics/03.27.08.HtmlCustomTemplates.md
b/pages/topics/03.27.08.HtmlCustomTemplates.md
index f0c7775903..09ed4a10e3 100644
--- a/pages/topics/03.27.08.HtmlCustomTemplates.md
+++ b/pages/topics/03.27.08.HtmlCustomTemplates.md
@@ -10,10 +10,10 @@ Custom page templates are created by implementing the <a
href="/site/apidocs/org
<tree>
<node-0><java-class><a
href="/site/apidocs/org/apache/juneau/marshall/html/HtmlDocTemplate.html"
target="_blank">HtmlDocTemplate</a></java-class></node-0>
-<node-1><javac-method><a
href="/site/apidocs/org/apache/juneau/marshall/html/HtmlDocTemplate.html#writeTo(org.apache.juneau.marshall.html.HtmlDocSerializerSession,org.apache.juneau.marshall.html.HtmlWriter,java.lang.Object)"
target="_blank">writeTo(HtmlDocSerializerSession,HtmlWriter,Object)</a></javac-method></node-1>
+<node-1><javac-method><a
href="/site/apidocs/org/apache/juneau/marshall/html/HtmlDocTemplate.html#writeTo(org.apache.juneau.marshall.html.HtmlDocSerializerSession,org.apache.juneau.marshall.html.HtmlWriter,java.lang.Object)"
target="_blank">writeTo(HtmlDocSerializerSession,HtmlWriter<?>,Object)</a></javac-method></node-1>
</tree>
-The interface defines a single `writeTo(session, writer, pojo)` method, and
the implementation is open-ended — you can write out the page contents
any way you wish using the <a
href="/site/apidocs/org/apache/juneau/marshall/html/HtmlWriter.html"
target="_blank">HtmlWriter</a> passed to it.
+The interface defines a single `writeTo(session, writer, pojo)` method, and
the implementation is open-ended — you can write out the page contents
any way you wish using the <a
href="/site/apidocs/org/apache/juneau/marshall/html/HtmlWriter.html"
target="_blank">HtmlWriter<?></a> passed to it.
The serialized POJO is available from the session (typically written into the
body via `session.parentSerialize(writer, pojo)`).
## Implementing a template from scratch
@@ -24,7 +24,7 @@ The following template ignores the header/nav/aside/footer
settings entirely and
public class MyTemplate implements HtmlDocTemplate {
@Override
- public void writeTo(HtmlDocSerializerSession session, HtmlWriter w, Object
o) throws Exception {
+ public void writeTo(HtmlDocSerializerSession session, HtmlWriter<?> w,
Object o) throws Exception {
w.sTag("html").nl(0);
w.sTag(1, "body").nl(1);
// Serialize the POJO into the body using the parent HtmlSerializer.
@@ -65,7 +65,7 @@ The following example overrides just the footer to append a
fixed copyright noti
public class MyTemplate extends BasicHtmlDocTemplate {
@Override
- protected void footer(HtmlDocSerializerSession session, HtmlWriter w,
Object o) throws Exception {
+ protected void footer(HtmlDocSerializerSession session, HtmlWriter<?> w,
Object o) throws Exception {
// Preserve the default footer behavior...
super.footer(session, w, o);
// ...then add our own content.
diff --git a/pages/topics/06.13.SystemDefaultConfig.md
b/pages/topics/06.13.SystemDefaultConfig.md
index 34977b2ac3..a670077e3d 100644
--- a/pages/topics/06.13.SystemDefaultConfig.md
+++ b/pages/topics/06.13.SystemDefaultConfig.md
@@ -13,19 +13,18 @@ It's accessed using the following static methods:
<node-1><java-method><a
href="/site/apidocs/org/apache/juneau/config/Config.html#setSystemDefault(org.apache.juneau.config.Config)"
target="_blank">setSystemDefault(Config)</a></java-method></node-1>
</tree>
-If you do not specify a system default config, one will be automatically
searched for.
-The search is done in the following order:
-
-1. If the system property `juneau.configFile` is set, we search for this file
in first the home directory and then the classpath.
-2. In the home directory: `.cfg`
-3. Any file that end with `.cfg`. First one matched alphabetically is used.
-4. In the context classpath root package (i.e. inside the jar itself): `.cfg`
-5. `juneau.cfg`
-6. `default.cfg`
-7. `application.cfg`
-8. `app.cfg`
-9. `settings.cfg`
-10. `application.properties`
+If you do not specify a system default config, one will be automatically
searched for, using the candidate names
+returned by <a
href="/site/apidocs/org/apache/juneau/config/Config.html#getCandidateSystemDefaultConfigNames()"
target="_blank">Config.getCandidateSystemDefaultConfigNames()</a>. Each
candidate name is looked up first as a
+file in the current/working directory (the directory the JVM was launched
from), and then as a classpath
+resource; the first candidate that resolves to either is used as the system
default.
+
+The candidate names are built in the following order:
+
+1. If the system property (or environment variable) `juneau.configFile` is
set, it is the *only* candidate — no other names are considered.
+2. Otherwise:
+ 1. If the JVM was launched from a jar file (i.e. `sun.java.command` ends
in `.jar`), two jar-name-derived candidates are added first: the jar's base
file name with a `.cfg` extension (e.g. `myapp-1.0.cfg`), followed by that same
base name with any trailing `.`/`_`-delimited version suffix stripped (e.g.
`myapp.cfg`).
+ 2. Every file in the current/working directory whose name ends in `.cfg`
is added next, in whatever order the JVM's `File.listFiles()` returns them for
that directory — this is filesystem/OS-dependent and is **not**
guaranteed to be alphabetical.
+ 3. Finally, the following fixed fallback names are added, in this order:
`juneau.cfg`, `default.cfg`, `application.cfg`, `app.cfg`, `settings.cfg`,
`application.properties`.
Later in the section on REST resources, we describe how to associate
configurations with REST resources using the <a
href="/site/apidocs/org/apache/juneau/rest/server/Rest.html#config()"
target="_blank">@Rest(config)</a> annotation.
diff --git a/pages/topics/09.05.HttpEntitiesAndResources.md
b/pages/topics/09.05.HttpEntitiesAndResources.md
index 602d9ef2d2..2282dfb0d2 100644
--- a/pages/topics/09.05.HttpEntitiesAndResources.md
+++ b/pages/topics/09.05.HttpEntitiesAndResources.md
@@ -50,7 +50,7 @@ public HttpEntity echoMyEntity(HttpEntity entity) {
// REST endpoint that serves up a static file.
@RestGet(path="/resource/{fileName}")
public HttpResource getStaticFile(@Path String fileName, Locale locale) {
- getContext().getStaticFiles().resolve(fileName,
locale).orElseThrow(NotFound::new);
+ return getContext().getStaticFiles().resolve(fileName,
locale).orElseThrow(NotFound::new);
}
```
diff --git a/pages/topics/10.02.03.PathVariables.md
b/pages/topics/10.02.03.PathVariables.md
index 4a63189951..638fe1bb0b 100644
--- a/pages/topics/10.02.03.PathVariables.md
+++ b/pages/topics/10.02.03.PathVariables.md
@@ -14,7 +14,7 @@ parameters or access through the <a
href="/site/apidocs/org/apache/juneau/rest/s
public class MyResource extends BasicRestServlet {
@RestPost("/{baz}")
- public void String doX(@Path String foo, @Path int bar) {
+ public void doX(@Path String foo, @Path int bar) {
...
}
}
diff --git a/pages/topics/10.03.01.InferredHttpMethodsAndPaths.md
b/pages/topics/10.03.01.InferredHttpMethodsAndPaths.md
index e526c3c22b..83608fa58c 100644
--- a/pages/topics/10.03.01.InferredHttpMethodsAndPaths.md
+++ b/pages/topics/10.03.01.InferredHttpMethodsAndPaths.md
@@ -3,7 +3,7 @@ title: "Inferred HTTP Methods and Paths"
slug: InferredHttpMethodsAndPaths
---
-When the `name` and/or `path` values are not specified, their values are
inferred from the Java method name.
+When the `method` and/or `path` values are not specified, their values are
inferred from the Java method name.
The HTTP method can be inferred from the Java method by starting the method
name with any of the following:
@@ -58,5 +58,5 @@ public String post() {...}
:::
:::note
-If `name` and `path` are both specified, the Java method name can be anything.
+If `method` and `path` are both specified, the Java method name can be
anything.
:::
\ No newline at end of file
diff --git a/pages/topics/10.03.06.Matchers.md
b/pages/topics/10.03.06.Matchers.md
index ec1258d4b7..3446bfc547 100644
--- a/pages/topics/10.03.06.Matchers.md
+++ b/pages/topics/10.03.06.Matchers.md
@@ -3,7 +3,7 @@ title: "Matchers"
slug: Matchers
---
-<a href="/site/apidocs/org/apache/juneau/rest/server/matcher/RestMatcher.html"
target="_blank">RestMatchers</a> are used to allow multiple Java methods to
+<a href="/site/apidocs/org/apache/juneau/rest/server/matcher/RestMatcher.html"
target="_blank">RestMatcher</a> is used to allow multiple Java methods to
be tied to the same HTTP method and path but differentiated by some request
attribute such as a specific header value.
:::tip Example
diff --git a/pages/topics/10.04.04.RequestBeans.md
b/pages/topics/10.04.04.RequestBeans.md
index 3f5eec6608..b6394efe88 100644
--- a/pages/topics/10.04.04.RequestBeans.md
+++ b/pages/topics/10.04.04.RequestBeans.md
@@ -63,15 +63,15 @@ public interface MyRequest {
// Pipe-delimited list of comma-delimited lists of integers.
@Query
@Schema(
- collectionFormat="pipes"
+ collectionFormat="pipes",
items=@Items(
items=@SubItems(
- collectionFormat="csv"
+ collectionFormat="csv",
type="integer",
minimum=1,
maximum=100
),
- maximumLength=10
+ maxl=10 // Synonym for maxLength().
)
)
int[][] getPipedCdlInts();
diff --git a/pages/topics/10.06.HandlingFormPosts.md
b/pages/topics/10.06.HandlingFormPosts.md
index daa0a23ad6..5446370d74 100644
--- a/pages/topics/10.06.HandlingFormPosts.md
+++ b/pages/topics/10.06.HandlingFormPosts.md
@@ -114,6 +114,7 @@ public class TempDirResource extends DirectoryResource {
return contentType != null &&
contentType.startsWith("multipart/form-data");
}
}
+}
```
:::
diff --git a/pages/topics/10.14.Guards.md b/pages/topics/10.14.Guards.md
index fef978b709..f958863516 100644
--- a/pages/topics/10.14.Guards.md
+++ b/pages/topics/10.14.Guards.md
@@ -22,7 +22,7 @@ Guards are associated with resource classes and methods via
the following:
:::tip Example
```java
// Define a guard that only lets Billy make a request
-public BillyGuard extends RestGuard {
+public class BillyGuard extends RestGuard {
@Override /* RestGuard */
public boolean isRequestAllowed(RestRequest req) {
@@ -32,11 +32,11 @@ public BillyGuard extends RestGuard {
// Servlet with class-level guard applied
@Rest(guards=BillyGuard.class)
-public MyRestServlet extends BasicRestServlet {
+public class MyRestServlet extends BasicRestServlet {
// Delete method that only Billy is allowed to call.
@RestDelete
- public doDelete(RestRequest req, RestResponse res) throws Exception {...}
+ public void doDelete(RestRequest req, RestResponse res) throws Exception
{...}
}
```
:::
diff --git a/pages/topics/10.16.LocalizedMessages.md
b/pages/topics/10.16.LocalizedMessages.md
index 2531ca66de..9343cd2e44 100644
--- a/pages/topics/10.16.LocalizedMessages.md
+++ b/pages/topics/10.16.LocalizedMessages.md
@@ -52,7 +52,7 @@ HelloMessage = Hello {0}!
public class MyResource {
@RestGet("/hello/{you}")
- public Object helloYou(RestRequest req, Messages messages, @Path("name")
String you) {
+ public Object helloYou(RestRequest req, Messages messages, @Path("you")
String you) {
String msg;
// Get it from the RestRequest object.
diff --git a/pages/topics/10.18.ConfigurationFiles.md
b/pages/topics/10.18.ConfigurationFiles.md
index 61b93f2217..54981a533f 100644
--- a/pages/topics/10.18.ConfigurationFiles.md
+++ b/pages/topics/10.18.ConfigurationFiles.md
@@ -109,6 +109,7 @@ public class MyResource {
path = config.get("MyProperties/path").orElse("mypath");
javaHome =
config.get("MyProperties/javaHome").as(File.class).orElse(null);
}
+}
```
Another common usage is to refer to config properties through `$C` variables
in your annotations:
diff --git a/pages/topics/10.19.RestServerSvlVariables.md
b/pages/topics/10.19.RestServerSvlVariables.md
index c3c6812f31..3e7763b3d4 100644
--- a/pages/topics/10.19.RestServerSvlVariables.md
+++ b/pages/topics/10.19.RestServerSvlVariables.md
@@ -81,7 +81,7 @@ Custom variables can be defined by supplying a named
`varResolver` bean via
```java
import org.apache.juneau.commons.inject.Bean;
-// Defined a variable that simply wrapps all strings inside [] brackets.
+// Defined a variable that simply wraps all strings inside [] brackets.
// e.g. "$BRACKET{foobar}" -> "[foobar]"
public class BracketVar extends SimpleVar {
diff --git a/pages/topics/10.31.02.HtmlWidgets.md
b/pages/topics/10.31.02.HtmlWidgets.md
index 9e8c21171a..9dfcd95410 100644
--- a/pages/topics/10.31.02.HtmlWidgets.md
+++ b/pages/topics/10.31.02.HtmlWidgets.md
@@ -39,7 +39,7 @@ The <a
href="/site/apidocs/org/apache/juneau/rest/server/widget/Widget.html" tar
The HTML content returned by the <a
href="/site/apidocs/org/apache/juneau/rest/server/widget/Widget.html#getHtml(org.apache.juneau.rest.server.RestRequest,org.apache.juneau.rest.server.RestResponse)"
target="_blank">getHtml(RestRequest,RestResponse)</a> method is added wherever
the `$W{...}` variable is used.
-The CSS returned by <a
href="/site/apidocs/org/apache/juneau/rest/server/widget/Widget.html#getScript(org.apache.juneau.rest.server.RestRequest,org.apache.juneau.rest.server.RestResponse)"
target="_blank">getScript(RestRequest,RestResponse)</a> is added to the style
section in the page header.
+The CSS returned by <a
href="/site/apidocs/org/apache/juneau/rest/server/widget/Widget.html#getStyle(org.apache.juneau.rest.server.RestRequest,org.apache.juneau.rest.server.RestResponse)"
target="_blank">getStyle(RestRequest,RestResponse)</a> is added to the style
section in the page header.
The Javascript returned by <a
href="/site/apidocs/org/apache/juneau/rest/server/widget/Widget.html#getScript(org.apache.juneau.rest.server.RestRequest,org.apache.juneau.rest.server.RestResponse)"
target="_blank">getScript(RestRequest,RestResponse)</a> is added to the script
section in the page header.
diff --git a/pages/topics/10.31.03.HtmlPredefinedWidgets.md
b/pages/topics/10.31.03.HtmlPredefinedWidgets.md
index 8782409ebd..40157ee092 100644
--- a/pages/topics/10.31.03.HtmlPredefinedWidgets.md
+++ b/pages/topics/10.31.03.HtmlPredefinedWidgets.md
@@ -7,7 +7,7 @@ The <a
href="/site/apidocs/org/apache/juneau/rest/server/widget/package-summary.
<tree>
<node-0><java-package><a
href="/site/apidocs/org/apache/juneau/rest/server/widget/package-summary.html"
target="_blank">org.apache.juneau.rest.server.widget</a></java-package></node-0>
-<node-1><javac-class><a
href="/site/apidocs/org/apache/juneau/rest/server/widget/Widget.html"
target="_blank">Widget</a></javac-class> <javac-class><a
href="/site/apidocs/org/apache/juneau/rest/server/widget/MenuItemWidget.html"
target="_blank">MenuItemWidget</a></javac-class> <javac-class><a
href="/site/apidocs/org/apache/juneau/rest/server/widget/ContentTypeMenuItem.html"
target="_blank">ContentTypeMenuItem</a></javac-class> <javac-class><a
href="/site/apidocs/org/apache/juneau/rest/se [...]
+<node-1><javac-class><a
href="/site/apidocs/org/apache/juneau/rest/server/widget/Widget.html"
target="_blank">Widget</a></javac-class> <javac-class><a
href="/site/apidocs/org/apache/juneau/rest/server/widget/MenuItemWidget.html"
target="_blank">MenuItemWidget</a></javac-class> <javac-class><a
href="/site/apidocs/org/apache/juneau/rest/server/widget/ContentTypeMenuItem.html"
target="_blank">ContentTypeMenuItem</a></javac-class> <javac-class><a
href="/site/apidocs/org/apache/juneau/rest/se [...]
</tree>
## MenuItemWidget
@@ -172,6 +172,25 @@ It renders the following image:

+## PoweredByApache
+
+<a
href="/site/apidocs/org/apache/juneau/rest/server/widget/PoweredByApache.html"
target="_blank">PoweredByApache</a> is a predefined <a
href="/site/apidocs/org/apache/juneau/rest/server/widget/Widget.html"
target="_blank">Widget</a> that places a
+powered-by-Apache message on a page.
+The variable it resolves is `$W{PoweredByApache}`.
+It produces a simple Apache icon floating on the right, hyperlinked to
`http://apache.org`.
+Typically it's used in the footer of the page, as shown in this minimal
example:
+
+```java
+@Rest(path="/myResource")
+@HtmlDocConfig(
+ widgets={
+ PoweredByApache.class
+ },
+ footer="$W{PoweredByApache}"
+)
+public class MyResource extends BasicRestServlet {...}
+```
+
## Tooltip
<a href="/site/apidocs/org/apache/juneau/rest/server/widget/Tooltip.html"
target="_blank">Tooltip</a> is a predefined template for adding tooltips to
HTML5
diff --git a/pages/topics/10.31.04.HtmlUiCustomization.md
b/pages/topics/10.31.04.HtmlUiCustomization.md
index 214c5469a8..7bb37df839 100644
--- a/pages/topics/10.31.04.HtmlUiCustomization.md
+++ b/pages/topics/10.31.04.HtmlUiCustomization.md
@@ -36,10 +36,10 @@ Instead, it just uses the existing open-ended API for
defining branding via anno
"$C{REST/header}" // Extra header HTML defined in external config
file.
},
- // Default contents to add to the section of the HTML page.
+ // Default contents to add to the <head> section of the HTML page.
// Use it to add a favicon link to the page.
head={
- ""
+ "<link rel='icon' href='$U{servlet:/htdocs/mypageicon.ico}'>"
},
// Basic page navigation links.
diff --git a/pages/topics/10.37.RestServerTestBeanInjection.md
b/pages/topics/10.37.RestServerTestBeanInjection.md
index 28a6201a48..1453470bc8 100644
--- a/pages/topics/10.37.RestServerTestBeanInjection.md
+++ b/pages/topics/10.37.RestServerTestBeanInjection.md
@@ -261,8 +261,8 @@ This split is the v1 ship; revisit Mode OVERLAY for
`MockRestClient` if a concre
- [REST Server — Conditional-GET / ETag
Helpers](/docs/topics/RestServerConditionalGet)
- [REST Server — Rate-Limiting and Request-Id
Propagation](/docs/topics/RestServerRateLimitAndRequestId)
- Apache Juneau Javadoc:
- -
[`JuneauBeanStoreExtension`](/site/apidocs/org/apache/juneau/junit5/JuneauBeanStoreExtension.html)
- - [`TestBean`](/site/apidocs/org/apache/juneau/junit5/TestBean.html)
- -
[`TestBeanStore`](/site/apidocs/org/apache/juneau/junit5/TestBeanStore.html)
+ -
[`JuneauBeanStoreExtension`](/site/apidocs/org/apache/juneau/test/junit/JuneauBeanStoreExtension.html)
+ - [`TestBean`](/site/apidocs/org/apache/juneau/test/junit/TestBean.html)
+ -
[`TestBeanStore`](/site/apidocs/org/apache/juneau/test/junit/TestBeanStore.html)
-
[`BeanStoreOverridable`](/site/apidocs/org/apache/juneau/commons/inject/BeanStoreOverridable.html)
- [`Snapshot`](/site/apidocs/org/apache/juneau/commons/inject/Snapshot.html)
diff --git a/pages/topics/10.51.SessionOptions.md
b/pages/topics/10.51.SessionOptions.md
index 2702a676a5..60322180dd 100644
--- a/pages/topics/10.51.SessionOptions.md
+++ b/pages/topics/10.51.SessionOptions.md
@@ -62,9 +62,9 @@ Resources using `BasicUniversalConfig` have a comprehensive
default allowlist th
## Client Usage
-### Juneau REST Client
+### Juneau REST Client (classic)
-The `RestClient` and `RestRequest` APIs provide dedicated methods for setting
session options:
+The `RestClient` (classic) and `RestRequest` (classic) APIs provide dedicated
methods for setting session options. These convenience methods live on the
classic REST client stack (`org.apache.juneau.rest.client.classic`) only — the
default next-generation `RestClient` does not have them.
```java
RestClient client = RestClient.create()
diff --git a/pages/topics/10.52.UsingWithOsgi.md
b/pages/topics/10.52.UsingWithOsgi.md
index 94abba3551..046525c6ed 100644
--- a/pages/topics/10.52.UsingWithOsgi.md
+++ b/pages/topics/10.52.UsingWithOsgi.md
@@ -6,7 +6,7 @@ slug: UsingWithOsgi
Since REST servlets are basically just `HttpServlets`, incorporating them into
an OSGi environment is pretty
straightforward.
-The following code shows how to register your REST servlets in an OSGi
Activator:
+The following code shows how to register your REST servlets in an OSGi
Activator. (The `MyRestServlet` class it registers was part of the now-removed
`juneau-examples-rest` module; this snippet is illustrative and not tied to a
currently-shipping class — the OSGi registration pattern itself still applies
to any `HttpServlet`.)
```java
package org.apache.juneau.examples.rest;
diff --git a/pages/topics/10.55.ResponseProcessors.md
b/pages/topics/10.55.ResponseProcessors.md
index 4363564ff8..b311e14bfc 100644
--- a/pages/topics/10.55.ResponseProcessors.md
+++ b/pages/topics/10.55.ResponseProcessors.md
@@ -8,15 +8,17 @@ or set through <a
href="/site/apidocs/org/apache/juneau/rest/server/RestResponse
By default, REST resource classes are registered with the following response
processors:
<tree>
-<node-0><java-class><a
href="/site/apidocs/org/apache/juneau/rest/server/processor/HttpBodyProcessor.html"
target="_blank">HttpBodyProcessor</a></java-class></node-0>
-<node-0><java-class><a
href="/site/apidocs/org/apache/juneau/rest/server/processor/HttpResourceProcessor.html"
target="_blank">HttpResourceProcessor</a></java-class></node-0>
-<node-0><java-class><a
href="/site/apidocs/org/apache/juneau/rest/server/processor/HttpResponseProcessor.html"
target="_blank">HttpResponseProcessor</a></java-class></node-0>
-<node-0><java-class><a
href="/site/apidocs/org/apache/juneau/rest/server/processor/InputStreamProcessor.html"
target="_blank">InputStreamProcessor</a></java-class></node-0>
-<node-0><java-class><a
href="/site/apidocs/org/apache/juneau/rest/server/processor/PlainTextPojoProcessor.html"
target="_blank">PlainTextPojoProcessor</a></java-class></node-0>
+<node-0><java-class><a
href="/site/apidocs/org/apache/juneau/rest/server/processor/AsyncResponseProcessor.html"
target="_blank">AsyncResponseProcessor</a></java-class></node-0>
<node-0><java-class><a
href="/site/apidocs/org/apache/juneau/rest/server/processor/ReaderProcessor.html"
target="_blank">ReaderProcessor</a></java-class></node-0>
+<node-0><java-class><a
href="/site/apidocs/org/apache/juneau/rest/server/processor/InputStreamProcessor.html"
target="_blank">InputStreamProcessor</a></java-class></node-0>
+<node-0><java-class><a
href="/site/apidocs/org/apache/juneau/rest/server/processor/ThrowableProcessor.html"
target="_blank">ThrowableProcessor</a></java-class></node-0>
+<node-0><java-class><a
href="/site/apidocs/org/apache/juneau/rest/server/processor/ProblemDetailsProcessor.html"
target="_blank">ProblemDetailsProcessor</a></java-class></node-0>
+<node-0><java-class><a
href="/site/apidocs/org/apache/juneau/rest/server/processor/HttpResponseProcessor.html"
target="_blank">HttpResponseProcessor</a></java-class></node-0>
+<node-0><java-class><a
href="/site/apidocs/org/apache/juneau/rest/server/processor/HttpResourceProcessor.html"
target="_blank">HttpResourceProcessor</a></java-class></node-0>
+<node-0><java-class><a
href="/site/apidocs/org/apache/juneau/rest/server/processor/HttpBodyProcessor.html"
target="_blank">HttpBodyProcessor</a></java-class></node-0>
<node-0><java-class><a
href="/site/apidocs/org/apache/juneau/rest/server/processor/ResponseBeanProcessor.html"
target="_blank">ResponseBeanProcessor</a></java-class></node-0>
+<node-0><java-class><a
href="/site/apidocs/org/apache/juneau/rest/server/processor/PlainTextPojoProcessor.html"
target="_blank">PlainTextPojoProcessor</a></java-class></node-0>
<node-0><java-class><a
href="/site/apidocs/org/apache/juneau/rest/server/processor/SerializedPojoProcessor.html"
target="_blank">SerializedPojoProcessor</a></java-class></node-0>
-<node-0><java-class><a
href="/site/apidocs/org/apache/juneau/rest/server/processor/ThrowableProcessor.html"
target="_blank">ThrowableProcessor</a></java-class></node-0>
</tree>
Custom response processors can be associated with REST resources via the
following:
diff --git a/pages/topics/10.56.RestRpc.md b/pages/topics/10.56.RestRpc.md
index f770191567..980c64a284 100644
--- a/pages/topics/10.56.RestRpc.md
+++ b/pages/topics/10.56.RestRpc.md
@@ -13,27 +13,23 @@ against arbitrary backend REST interfaces.
## Remote Interfaces
-The following example shows a remote interface:
+The following example shows a remote interface built on the petstore sample's
real `Pet` bean and `PetStore` service
+(`juneau-petstore`). (The petstore samples don't currently expose a remote
interface via RRPC; this walkthrough builds
+one on top of those currently-shipping petstore types purely to illustrate the
RRPC mechanism.)
```java
@RemoteInterface // Annotation is optional
-public interface IAddressBook {
+public interface IPetStore {
- void init() throws Exception;
+ Collection<Pet> getPets();
- List getPeople();
+ Pet getPet(long id);
- List getAddresses();
+ Pet createPet(Pet pet);
- int createPerson(CreatePerson cp) throws Exception;
+ Pet updatePet(Pet pet);
- Person findPerson(int id);
-
- Address findAddress(int id);
-
- Person findPersonWithAddress(int id);
-
- Person removePerson(int id);
+ void deletePet(long id);
}
```
@@ -85,38 +81,31 @@ RestClient client = RestClient.create()
.build();
// Create a proxy interface.
-IAddressBook ab = client.getRrpcInterface(IAddressBook.class);
+IPetStore petStore = client.getRrpcInterface(IPetStore.class);
// Invoke a method on the server side and get the returned result.
-Person p = ab.createPerson(
- new Person(
- "John Smith",
- "Aug 1, 1999",
- new Address("My street", "My city", "My state", 12345, true)
- )
+Pet pet = petStore.createPet(
+ new Pet()
+ .setName("Fluffy")
+ .setSpecies(Species.CAT)
+ .setPrice(200f)
+ .setStatus(PetStatus.AVAILABLE)
);
```
Under the covers, this method call gets converted to a REST POST.
```text
-HTTP POST
http://localhost:10000/remote/org.apache.juneau.examples.addressbook.IAddressBook/createPerson(org.apache.juneau.examples.addressbook.Person)
+HTTP POST
http://localhost:10000/remote/IPetStore/createPet(org.apache.juneau.petstore.dto.Pet)
Accept: application/json
Content-Type: application/json
[
{
- "name":"John Smith",
- "birthDate":"Aug 1, 1999",
- "addresses":[
- {
- "street":"My street",
- "city":"My city",
- "state":"My state",
- "zip":12345,
- "isCurrent":true
- }
- ]
+ "name":"Fluffy",
+ "species":"CAT",
+ "price":200.0,
+ "status":"AVAILABLE"
}
]
```
@@ -141,26 +130,35 @@ browser with no coding involved.
## RrpcServlet
The <a
href="/site/apidocs/org/apache/juneau/rest/server/remote/RrpcServlet.html"
target="_blank">RrpcServlet</a> class is a simple specialized servlet
-with an abstract `getServiceMap()` method to define the server-side POJOs:
+with an abstract `getServiceMap()` method to define the server-side POJOs.
+Note that `getServiceMap()` maps each interface `Class` to a POJO *instance*
that implements it — since the petstore's real
+<a href="/site/apidocs/org/apache/juneau/petstore/service/PetStore.html"
target="_blank">PetStore</a> service doesn't itself
+implement `IPetStore`, a small anonymous adapter delegates each `IPetStore`
method to the underlying `store`:
```java
@Rest(
path="/remote"
)
-public class SampleRrpcServlet extends RrpcServlet {
+public class SamplePetStoreRrpcServlet extends RrpcServlet {
// Our server-side POJO.
- private AddressBook addressBook = new AddressBook();
+ private final transient PetStore store = new PetStore();
@Override /* RrpcServlet */
- protected Map,Object> getServiceMap() throws Exception {
- Map,Object> map = new LinkedHashMap,Object>();
-
- // In this simplified example, we expose the same POJO service under
two different interfaces.
- // One is IAddressBook which only exposes methods defined on that
interface, and
- // the other is AddressBook itself which exposes all methods defined
on the class itself (dangerous!).
- map.put(IAddressBook.class, addressBook);
- map.put(AddressBook.class, addressBook);
+ protected Map<Class<?>,Object> getServiceMap() throws Exception {
+ Map<Class<?>,Object> map = new LinkedHashMap<>();
+
+ // In this simplified example, we expose the same underlying store
under two different interfaces.
+ // One is IPetStore which only exposes methods defined on that
interface, and
+ // the other is PetStore itself which exposes all public methods
defined on the class itself (dangerous!).
+ map.put(IPetStore.class, new IPetStore() {
+ @Override public Collection<Pet> getPets() { return
store.getPets(); }
+ @Override public Pet getPet(long id) { return store.getPet(id); }
+ @Override public Pet createPet(Pet pet) { return
store.createPet(pet); }
+ @Override public Pet updatePet(Pet pet) { return
store.updatePet(pet); }
+ @Override public void deletePet(long id) { store.deletePet(id); }
+ });
+ map.put(PetStore.class, store);
return map;
}
}
@@ -173,9 +171,15 @@ You simply define a Java method whose return type is an
interface, and return th
```java
// Our exposed interface.
-<a href="/site/apidocs/org/apache/juneau/rest/server/RestOp.html"
target="_blank">@RestOp</a>(method=RRPC, path="/addressbookproxy/*")
-public IAddressBook getProxy() {
- return addressBook;
+<a href="/site/apidocs/org/apache/juneau/rest/server/RestOp.html"
target="_blank">@RestOp</a>(method=RRPC, path="/petstoreproxy/*")
+public IPetStore getProxy() {
+ return new IPetStore() {
+ @Override public Collection<Pet> getPets() { return store.getPets(); }
+ @Override public Pet getPet(long id) { return store.getPet(id); }
+ @Override public Pet createPet(Pet pet) { return store.createPet(pet);
}
+ @Override public Pet updatePet(Pet pet) { return store.updatePet(pet);
}
+ @Override public void deletePet(long id) { store.deletePet(id); }
+ };
}
```
@@ -188,27 +192,32 @@ http://localhost:10000/remote
```
Clicking the hyperlinks on each shows you the list of methods that can be
invoked on that service.
-Note that the `IAddressBook` link shows that you can only invoke methods
defined on that interface, whereas the
-`AddressBook` link shows ALL public methods defined on that class.
+Note that the `IPetStore` link shows that you can only invoke methods defined
on that interface, whereas the
+`PetStore` link shows ALL public methods defined on that class.
-## IAddressBook
+## IPetStore
-
+
```text
-http://localhost:10000/remote/org.apache.juneau.examples.addressbook.IAddressBook
+http://localhost:10000/remote/IPetStore
```
-Since `AddressBook` extends from `LinkedList`, you may notice familiar
`collections` framework methods listed.
+Only the five methods declared on the `IPetStore` interface are listed here.
-## AddressBook
+## PetStore
-
+
```text
-http://localhost:10000/remote/org.apache.juneau.examples.addressbook.AddressBook
+http://localhost:10000/remote/PetStore
```
+Since this second entry maps the concrete `PetStore` class directly, every
public method declared on `PetStore` — not
+just the five on `IPetStore` — is listed and invocable, including
`getOrders()`, `createOrder(Order)`, `getUsers()`, and
+the rest of the petstore service surface. This is why exposing a concrete
class this way is dangerous in a real
+application; prefer exposing a narrow interface like `IPetStore` instead.
+
Let's see how we can interact with this interface through nothing more than
REST calls to get a better idea on how this
works.
We'll use the same method call as in the introduction.
@@ -216,11 +225,13 @@ First, we need to create the serialized form of the
arguments:
```java
Object[] args = new Object[] {
- new CreatePerson("Test Person",
- AddressBook.toCalendar("Aug 1, 1999"),
- new CreateAddress("Test street", "Test city", "Test state", 12345,
true))
+ new Pet()
+ .setName("Fluffy")
+ .setSpecies(Species.CAT)
+ .setPrice(200f)
+ .setStatus(PetStatus.AVAILABLE)
};
-String asJson = Json5Serializer.DEFAULT_READABLE.toString(args);
+String asJson = Json5Serializer.DEFAULT_READABLE.write(args);
System.err.println(asJson);
```
@@ -229,17 +240,10 @@ That produces the following JSON output:
```js
[
{
- name: 'Test Person',
- birthDate: 'Aug 1, 1999',
- addresses: [
- {
- street: 'Test street',
- city: 'Test city',
- state: 'Test state',
- zip: 12345,
- isCurrent: true
- }
- ]
+ name: 'Fluffy',
+ species: 'CAT',
+ price: 200.0,
+ status: 'AVAILABLE'
}
]
```
@@ -252,17 +256,17 @@ Methods are invoked by POSTing the serialized object
array to the URI of the int
In this case, we want to POST our JSON to the following URL:
```text
-http://localhost:10000/remote/org.apache.juneau.examples.addressbook.IAddressBook/createPerson(org.apache.juneau.examples.addressbook.CreatePerson)
+http://localhost:10000/remote/IPetStore/createPet(org.apache.juneau.petstore.dto.Pet)
```
Make sure that we specify the `Content-Type` of the body as `text/json`.
We also want the results to be returned as JSON, so we set the `Accept` header
to `text/json` as well.
-When we execute the POST, we should see the following successful response
whose body contains the returned `Person` bean
+When we execute the POST, we should see the following successful response
whose body contains the returned `Pet` bean
serialized to JSON: From there, we could use the following code snippet to
reconstruct the response object from JSON:
```java
String response = "output from above";
-Person p = JsonParser.DEFAULT.read(response, Person.class);
+Pet pet = JsonParser.DEFAULT.read(response, Pet.class);
```
If we alter our servlet to allow overloaded GET requests, we can invoke
methods using nothing more than a browser...
@@ -274,20 +278,20 @@ If we alter our servlet to allow overloaded GET requests,
we can invoke methods
// Allow us to use method=POST from a browser.
allowedMethodParams="*"
)
-public class SampleRrpcServlet extends RrpcServlet {
+public class SamplePetStoreRrpcServlet extends RrpcServlet {
```
-For example, to invoke the `getPeople()` method on our bean:
+For example, to invoke the `getPets()` method on our service:
```text
-http://localhost:10000/remote/org.apache.juneau.examples.addressbook.IAddressBook/getPeople?method=POST
+http://localhost:10000/remote/IPetStore/getPets?method=POST
```
-Here we call the `findPerson(int)` method to retrieve a person and get the
returned POJO (in this case as HTML since
+Here we call the `getPet(long)` method to retrieve a pet and get the returned
POJO (in this case as HTML since
that's what's in the `Accept` header when calling from a browser):
```text
-http://localhost:10000/remote/org.apache.juneau.examples.addressbook.IAddressBook/findPerson(int)?method=POST&body=@(3)
+http://localhost:10000/remote/IPetStore/getPet(long)?method=POST&body=@(3)
```
When specifying the POST body as a `&body` parameter, the method arguments
should be in UON notation.
diff --git a/pages/topics/10.60.OtherNotes.md b/pages/topics/10.60.OtherNotes.md
index 603bcdc3fb..c667fce744 100644
--- a/pages/topics/10.60.OtherNotes.md
+++ b/pages/topics/10.60.OtherNotes.md
@@ -4,5 +4,5 @@ slug: OtherNotes
---
- Subclasses can use either <a
href="https://jakarta.ee/specifications/servlet/6.0/apidocs/jakarta/servlet/http/HttpServlet.html#init(ServletConfig)"
target="_blank">HttpServlet.init(ServletConfig)</a> or <a
href="https://jakarta.ee/specifications/servlet/6.0/apidocs/jakarta/servlet/http/HttpServlet.html#init()"
target="_blank">HttpServlet.init()</a> for initialization just like any other
servlet.
-- The `X-Response-Headers` header can be used to pass through header values
into the response.
- - The value should be a URL-encoded map of key-value pairs. For example,
to add a `Refresh: 1` header to the response to auto-refresh a page, the
following parameter can be specified: `/sample?X-Response-Headers=(Refresh=1)`
+- The `X-Response-Headers` request header can be used to pass through header
values into the response.
+ - The value should be a UON-encoded map of key-value pairs. For example,
to add a `Refresh: 1` header to the response to auto-refresh a page, the
following request header can be specified: `X-Response-Headers: (Refresh=1)`
diff --git a/pages/topics/10.61.Log4j.md b/pages/topics/10.61.Log4j.md
index f048b1db44..954001bfa2 100644
--- a/pages/topics/10.61.Log4j.md
+++ b/pages/topics/10.61.Log4j.md
@@ -15,9 +15,19 @@ If you wish to use LOG4J logging, you simple need to add the
following to your J
## Maven dependency
+`log4j-jul` is only the bridge that routes `java.util.logging` calls into
Log4j2 — it does not include a Log4j2 implementation. You also need
`log4j-core` (or `log4j-to-slf4j` plus an SLF4J binding) on the classpath, or
nothing will actually process the routed log records:
+
```xml
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jul</artifactId>
</dependency>
+<dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+</dependency>
```
+
+:::info See Also
+[Management Logging — Logback & Log4j2
Backends](/docs/topics/RestServerManagementLogging) covers the more thorough
`juneau-rest-server-management-logging` module, which lets the `/loggers`
runtime management endpoint drive Logback or Log4j2 directly instead of just
redirecting JUL output.
+:::
diff --git a/pages/topics/11.04.JuneauRestServerMcp.md
b/pages/topics/11.04.JuneauRestServerMcp.md
index e58c9ccc12..f27bb23f51 100644
--- a/pages/topics/11.04.JuneauRestServerMcp.md
+++ b/pages/topics/11.04.JuneauRestServerMcp.md
@@ -47,29 +47,29 @@ The implementation is stateless — every request is
dispatched against the `Mcp
### Add the dependency
-Application code normally depends on the `2025-06-18` adapter, which
transitively pulls in the core plus the `2025-06-18` wire beans:
+Application code normally depends on the `2026-07-28` adapter, which
transitively pulls in the core plus the `2026-07-28` wire beans:
```xml
<dependency>
<groupId>org.apache.juneau</groupId>
- <artifactId>juneau-rest-server-mcp-v20250618</artifactId>
+ <artifactId>juneau-rest-server-mcp-v20260728</artifactId>
<version>${juneau.version}</version>
</dependency>
```
-This module transitively pulls in `juneau-rest-server-mcp` (the core) and
`juneau-bean-mcp-v20250618`.
+This module transitively pulls in `juneau-rest-server-mcp` (the core) and
`juneau-bean-mcp-v20260728`.
### Drop-in servlet
-Subclass `org.apache.juneau.rest.server.mcp.v20250618.McpRestServlet` (not the
abstract core `AbstractMcpRestServlet` directly) and supply your config in
`createMcpConfig()`. The base class wires up `@Rest`,
`@SerializerConfig(addBeanTypes="true")`, and a `POST /` handler:
+Subclass `org.apache.juneau.rest.server.mcp.v20260728.McpRestServlet` (not the
abstract core `AbstractMcpRestServlet` directly) and supply your config in
`createMcpConfig()`. The base class wires up `@Rest`,
`@SerializerConfig(addBeanTypes="true")`, and a `POST /` handler:
```java
import org.apache.juneau.rest.server.*;
import org.apache.juneau.rest.server.mcp.*;
-import org.apache.juneau.rest.server.mcp.v20250618.*;
+import org.apache.juneau.rest.server.mcp.v20260728.*;
@Rest(path="/mcp")
-public class MyMcpServlet extends
org.apache.juneau.rest.server.mcp.v20250618.McpRestServlet {
+public class MyMcpServlet extends
org.apache.juneau.rest.server.mcp.v20260728.McpRestServlet {
@Override
protected McpServerConfig createMcpConfig() {
@@ -98,7 +98,7 @@ public class MyResource extends BasicRestServlet implements
McpEndpoint {
}
```
-The default `handleMcpRequest(...)` method on `McpEndpoint` (inherited from
the revision-neutral `McpEndpointMixin`, annotated `@RestPost("/mcp")`) takes
care of dispatch, via
`org.apache.juneau.rest.server.mcp.v20250618.McpEndpoint`'s `revision()`
override.
+The default `handleMcpRequest(...)` method on `McpEndpoint` (inherited from
the revision-neutral `McpEndpointMixin`, annotated `@RestPost("/mcp")`) takes
care of dispatch, via
`org.apache.juneau.rest.server.mcp.v20260728.McpEndpoint`'s `revision()`
override.
## Running Under Spring Boot
diff --git a/pages/topics/13.05.ResponseHeaders.md
b/pages/topics/13.05.ResponseHeaders.md
index eb3b414156..56a082b827 100644
--- a/pages/topics/13.05.ResponseHeaders.md
+++ b/pages/topics/13.05.ResponseHeaders.md
@@ -57,7 +57,7 @@ The <a
href="/site/apidocs/org/apache/juneau/rest/client/classic/ResponseHeader.
<node-1><java-method><a
href="/site/apidocs/org/apache/juneau/rest/client/classic/ResponseHeader.html#asUriHeader()"
target="_blank">asUriHeader()</a></java-method> → <a
href="/site/apidocs/org/apache/juneau/http/classic/header/BasicUriHeader.html"
target="_blank">BasicUriHeader</a></node-1>
</tree>
-The <a
href="/site/apidocs/org/apache/juneau/rest/client/classic/ResponseHeader.html#schema(org.apache.juneau.httppart.HttpPartSchema)"
target="_blank">ResponseHeader.schema(HttpPartSchema)</a> method allows you to
perform parsing of OpenAPI formats for
+The <a
href="/site/apidocs/org/apache/juneau/rest/client/classic/ResponseHeader.html#schema(org.apache.juneau.marshall.httppart.HttpPartSchema)"
target="_blank">ResponseHeader.schema(HttpPartSchema)</a> method allows you to
perform parsing of OpenAPI formats for
header parts.
:::tip Example
diff --git a/pages/topics/13.12.ExtendingRestClient.md
b/pages/topics/13.12.ExtendingRestClient.md
index 8368c1c13d..66aa9e7fb1 100644
--- a/pages/topics/13.12.ExtendingRestClient.md
+++ b/pages/topics/13.12.ExtendingRestClient.md
@@ -12,8 +12,8 @@ The following example that overrides the primary run method
shows how this can b
public class MyRestClient extends RestClient {
// Must provide this constructor!
- public MyRestClient(ContextProperties ps) {
- super(ps);
+ public MyRestClient(RestClient.Builder<?> builder) {
+ super(builder);
}
@Override
diff --git a/pages/topics/13.13.00.Authentication.md
b/pages/topics/13.13.00.Authentication.md
index 8818c03f3e..de551751d8 100644
--- a/pages/topics/13.13.00.Authentication.md
+++ b/pages/topics/13.13.00.Authentication.md
@@ -8,4 +8,17 @@ The Juneau REST client itself does not implement any support
for authentication.
Instead, it delegates it to the underlying Apache HTTP Client interface.
-The following sections show how some common authentication mechanisms can be
set up using HTTP Client APIs.
+The following sections show how some common authentication mechanisms can be
set up using HTTP Client APIs:
+
+- [BASIC Authentication](/docs/topics/AuthenticationBASIC)
+- [Form-Based Authentication](/docs/topics/AuthenticationForm)
+- [OIDC Authentication](/docs/topics/AuthenticationOIDC)
+
+:::warning Classic-client-only
+The auth-shortcut convenience methods shown on these pages (such as
<c>basicAuth(...)</c>) are builder
+methods on the classic <c>RestClient.Builder</c>
(<c>org.apache.juneau.rest.client.classic</c>), which
+wraps Apache HttpClient 4.5. The [Next-Generation REST
Client](/docs/topics/NextGenRestClient) has
+**no** equivalent auth-shortcut methods at all — it has no dependency on
Apache HttpClient, so
+authentication must instead be configured on the transport you choose (for
example, the native Apache
+HC 4.5/5, OkHttp, or JDK `HttpClient` builder) before wrapping it in an
`HttpTransport`.
+:::
diff --git a/pages/topics/13.13.02.AuthenticationForm.md
b/pages/topics/13.13.02.AuthenticationForm.md
index 08ab481e36..40f7af4b94 100644
--- a/pages/topics/13.13.02.AuthenticationForm.md
+++ b/pages/topics/13.13.02.AuthenticationForm.md
@@ -56,7 +56,7 @@ private void formBasedAuthenticate(HttpClient client) throws
IOException {
// The form auth request should always respond with a 200 ok or 302
redirect code
if (rc == SC_MOVED_TEMPORARILY) {
- if
(response.getFirstHeader("Location").getValue().isPattern("^.*/auth/authfailed.*$"))
+ if
(response.getFirstHeader("Location").getValue().matches(".*/auth/authfailed.*"))
throw new IOException("Invalid credentials.");
} else if (rc != SC_OK) {
throw new IOException("Unexpected HTTP status: " + rc);
diff --git a/pages/topics/16.03.ResourceClasses.md
b/pages/topics/16.03.ResourceClasses.md
index 9fa9327a5e..93a31b3908 100644
--- a/pages/topics/16.03.ResourceClasses.md
+++ b/pages/topics/16.03.ResourceClasses.md
@@ -139,14 +139,14 @@ servletMap =
```xml
<Configure id="ExampleServer" class="org.eclipse.jetty.server.Server">
...
- <New id="context"
class="org.eclipse.jetty.ee9.servlet.ServletContextHandler">
+ <New id="context"
class="org.eclipse.jetty.ee11.servlet.ServletContextHandler">
<Set name="contextPath">/</Set>
<Call name="addServlet">
<Arg>org.apache.juneau.petstore.jetty.RootResources</Arg>
<Arg>/*</Arg>
</Call>
<Set name="sessionHandler">
- <New class="org.eclipse.jetty.ee9.nested.SessionHandler" />
+ <New class="org.eclipse.jetty.ee11.servlet.SessionHandler" />
</Set>
</New>
...
diff --git a/pages/topics/26.V9MigrationGuide.md
b/pages/topics/26.V9MigrationGuide.md
index 71673504f7..6918f31bab 100644
--- a/pages/topics/26.V9MigrationGuide.md
+++ b/pages/topics/26.V9MigrationGuide.md
@@ -15,4 +15,4 @@ Note that you can also refer to the Release Notes for changes
as well.
| `@Body` annotation. | Has been renamed to <a
href="/site/apidocs/org/apache/juneau/http/Content.html"
target="_blank">@Content</a> (to better match HTTP naming conventions such as
Content-Type/Content-Encoding headers). |
| `@Query(_default)`, `@FormData(_default)`. | Has been renamed to <a
href="/site/apidocs/org/apache/juneau/http/Query.html#def()"
target="_blank">Query.def</a> / <a
href="/site/apidocs/org/apache/juneau/http/FormData.html#def()"
target="_blank">FormData.def</a>.<br />Note however that <a
href="/site/apidocs/org/apache/juneau/rest/server/RestOp.html"
target="_blank">@RestOp</a>-annotated parameters now also support use of
Optional parameters which simplifies the coding of default values. |
| `@Rest(reqHeaders)`. | Has been renamed to <a
href="/site/apidocs/org/apache/juneau/rest/server/Rest.html#defaultRequestHeaders()"
target="_blank">Rest.defaultRequestHeaders</a> and added <a
href="/site/apidocs/org/apache/juneau/rest/server/Rest.html#defaultResponseHeaders()"
target="_blank">Rest.defaultResponseHeaders</a>. |
-| `@Rest(staticFiles)`. | Changed from a string array to a `Class<? extends
StaticFiles>`.<br />If you're extending from <a
href="/site/apidocs/org/apache/juneau/rest/server/servlet/BasicRestServlet.html"
target="_blank">BasicRestServlet</a>/<a
href="/site/apidocs/org/apache/juneau/rest/server/servlet/BasicRestResource.html"
target="_blank">BasicRestResource</a>, the <a
href="/site/apidocs/org/apache/juneau/rest/server/servlet/BasicRestOperations.html#getHtdoc(java.lang.String,java.util.
[...]
+| `@Rest(staticFiles)`. | Changed from a string array to a `Class<? extends
StaticFiles>`.<br />If you're extending from <a
href="/site/apidocs/org/apache/juneau/rest/server/servlet/BasicRestServlet.html"
target="_blank">BasicRestServlet</a>/<a
href="/site/apidocs/org/apache/juneau/rest/server/servlet/BasicRestResource.html"
target="_blank">BasicRestResource</a>, the <a
href="/site/apidocs/org/apache/juneau/rest/server/ops/HtdocMixin.html#getHtdoc(org.apache.juneau.rest.server.RestReques
[...]
diff --git a/src/pages/about.md b/src/pages/about.md
index 3da4f80e68..c40478a0db 100644
--- a/src/pages/about.md
+++ b/src/pages/about.md
@@ -91,6 +91,8 @@ The Juneau ecosystem consists of the following parts. A few
rows are **grouped f
| [juneau-microservice-tomcat](/docs/topics/JuneauMicroserviceTomcat) |
Tomcat-embedded microservice launcher. |
| **juneau-sc** | |
| [juneau-sc-server](/docs/topics/ScServerOverview) | Centralized
configuration server exposing juneau-config files over REST. |
+| **juneau-secret-keychain** | |
+|
[juneau-secret-keychain](/docs/topics/JuneauCommonsSettings#os-keychain-backed-store)
| Opt-in module providing a macOS `security`-CLI-backed `KeychainSecretStore`
implementation of the `SecretStore` SPI. |
| **juneau-shaded** | |
| [juneau-shaded-core](/docs/topics/JuneauShadedCore) | Shaded uber-jar of the
juneau-core modules for zero-conflict dependency management. |
| [juneau-shaded-rest-client](/docs/topics/JuneauShadedRestClient) | Shaded
uber-jar of juneau-rest-client and its dependencies. |