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 c6f6b61560 Document @ConfigProperties feature and RestContext pilot
(TODO-311)
c6f6b61560 is described below
commit c6f6b61560d1b8ce003f461eb0cb365635b7d552
Author: James Bognar <[email protected]>
AuthorDate: Tue Jul 28 12:47:21 2026 -0400
Document @ConfigProperties feature and RestContext pilot (TODO-311)
Adds a new @ConfigProperties topic page (2.10.3) covering prefix-scoped
whole-object
config binding, relaxed key matching, nesting, precedence, and current
limitations,
registered in the sidebar next to the @Value docs. Updates the RestContext
page with a
RestContextProperties pilot section (including the empty-boolean leniency
and SVL
var-resolver widening), corrects the @Value framework-internal migration
table, and
adds 10.0.0 release notes for the feature.
Co-authored-by: Cursor <[email protected]>
---
pages/release-notes/10.0.0.md | 47 ++++++
pages/topics/02.10.02.ValueFrameworkInternal.md | 15 +-
pages/topics/02.10.03.ConfigProperties.md | 192 ++++++++++++++++++++++++
pages/topics/10.53.RestContext.md | 55 ++++++-
sidebars.ts | 5 +
5 files changed, 312 insertions(+), 2 deletions(-)
diff --git a/pages/release-notes/10.0.0.md b/pages/release-notes/10.0.0.md
index e5bff213e1..1f9bf843b1 100644
--- a/pages/release-notes/10.0.0.md
+++ b/pages/release-notes/10.0.0.md
@@ -100,6 +100,49 @@ so existing configs are unaffected:
See the new [Config Profiles & Relaxed
Binding](/docs/topics/ConfigProfilesAndRelaxedBinding) topic page for the
activation conventions, overlay/merge precedence, and the candidate-generation
rules.
+### juneau-commons / juneau-rest-server
+
+### `@ConfigProperties` — prefix-scoped whole-object config binding, with
`RestContext` as the pilot
+
+Juneau 10.0 adds a new `@ConfigProperties(prefix = "...")` annotation
(`org.apache.juneau.commons.inject`) —
+Juneau's analog of Spring Boot's `@ConfigurationProperties` — plus its
underlying, independently-callable engine,
+`ConfigPropertiesBinder`. Where [`@Value`](/docs/topics/ValueAnnotation)
resolves one configuration value onto one
+field, `@ConfigProperties` resolves an entire prefix onto every field of a
POJO in one pass:
+
+```java
+@ConfigProperties(prefix = "MyService")
+public class MyServiceProperties {
+ public String host = "localhost";
+ public int port = 8080;
+}
+```
+
+- **Relaxed key matching by default** — reuses
`RelaxedPropertySource.candidates(...)`, so `MyService.host`,
+ `MY_SERVICE_HOST`, and `my.service.host` are all equivalent.
+- **Same source-chain precedence as `@Value`** — thread-local/global test
overrides, then any caller-scoped
+ `PropertySource` beans, then the process-wide `Settings` chain (registered
sources, system properties,
+ system environment).
+- **Nested config objects** — a field whose type is itself
`@ConfigProperties`-annotated binds recursively under
+ a sub-prefix.
+- **Coexists with `@Value`/`@Inject`** on the same class — fields owned by
either are never touched by the
+ whole-object bind.
+- **Auto-registered in the `BeanStore`** — the bound instance is retrievable
via `beanStore.getBean(...)` or
+ plain `@Inject` anywhere downstream.
+- **Current limitations:** no `Optional<T>`/`Supplier<T>` field types
(raw-type conversion only); validation is a
+ no-op extension seam (`ConfigPropertiesValidator.NO_OP`) reserved for a
future release.
+
+**Pilot: `RestContextProperties`.** As proof, `RestContext`'s 15 same-prefix
`RestContext.*` env-driven-default
+`@Value` fields have been collapsed into a single public
`@ConfigProperties(prefix = "RestContext")` bean,
+`RestContextProperties`, retrievable via the new
`RestContext.getRestContextProperties()` or from the resource's
+`BeanStore`. Every existing `RestContext` getter keeps its exact signature and
`@Rest`-annotation-blending
+behavior — only the source of the underlying default moved.
`RestContext.uriAuthority`/`uriContext` (a
+null-vs-empty distinction the binder's raw-type conversion can't express in
v1) and the unrelated
+`juneau.restLogger.level` setting are unaffected and remain plain `@Value`
fields.
+
+See the new [`@ConfigProperties` Annotation
Basics](/docs/topics/ConfigProperties) topic page, and the
+[RestContext](/docs/topics/RestContext#restcontextproperties--env-driven-defaults-via-configproperties-1000)
topic
+page for the pilot.
+
### juneau-microservice-jetty
### `JettyMicroservice` zero-config facade + bundled defaults
@@ -657,6 +700,10 @@ constants (see Breaking Changes below). The
[Marshallers](/docs/topics/Marshalle
A related set of ReDoS-hardening fixes (bounded/escaped regex handling in
`HttpPartSchema`, `LogEntryFormatter`, and the request-routing
`UrlPathMatcher`) landed in the same sweep. **Migration:** none for normal
usage; an application that displayed unauthorized-request detail to end users,
or that parsed XML relying on DTD processing on the non-validating path, will
see the new generic/hardened behavior.
+- **Present-but-empty `RestContext.*` boolean settings no longer throw
(leniency improvement).** Landed alongside the new `RestContextProperties`
`@ConfigProperties` bean (see New Features above): previously, a
present-but-empty value for a boolean `RestContext.*` setting (e.g.
`RestContext.eagerInit=`) threw `BeanCreationException` at injection time,
because the old `@Value boolean` field's strict conversion had no tolerance for
an empty string. As of 10.0.0 this is resolved leniently t [...]
+
+- **SVL variables in a `RestContext.*` boolean setting now resolve through the
resource's own var resolver (capability widening).** Landed alongside the same
`RestContextProperties` change: a `$C{...}` / `$R{...}` / `$S{...}`-style
variable embedded in a boolean `RestContext.*` value (e.g.
`RestContext.virtualThreads=$C{MyConfig/virtualThreads}`) is now resolved
through the owning resource's `VarResolver` rather than `VarResolver.DEFAULT`,
so resource-scoped variables like `$C{...}` (con [...]
+
### Breaking Changes
- **`juneau-my-jetty-microservice` removed.** The template-project module has
been retired in favor of the new `JettyMicroservice` facade + bundled defaults
in `juneau-microservice-jetty`. See the New Features section above for
migration guidance.
diff --git a/pages/topics/02.10.02.ValueFrameworkInternal.md
b/pages/topics/02.10.02.ValueFrameworkInternal.md
index 766ff1e1f0..5f8965101e 100644
--- a/pages/topics/02.10.02.ValueFrameworkInternal.md
+++ b/pages/topics/02.10.02.ValueFrameworkInternal.md
@@ -23,7 +23,8 @@ the [`@Value` annotation](/docs/topics/ValueAnnotation) and
`BeanInstantiator`:
| `CallLogger.Builder` | `responseDetail` |
`${juneau.restLogger.responseDetail:STATUS_LINE}` |
| `CallLogger.Builder` | `level` | `${juneau.restLogger.level:OFF}` |
| `CallLogger.Builder` | `logger` (name) |
`${juneau.restLogger.logger:global}` |
-| `RestContext` | env-driven defaults for `debugDefault`, `debugLevel`,
`allowedHeaderParams`, `allowedMethodHeaders`, `allowedMethodParams`,
`disableContentParam`, `renderResponseStackTraces`, `problemDetails`,
`virtualThreads`, `eagerInit`, `clientVersionHeader`, `uriRelativity`,
`uriAuthority`, `uriContext`, `uriResolution` | `${RestContext.<name>:default}`
(15 sites) |
+| `RestContext` | env-driven default for the call-logger debug-level fallback,
`defaultDebugLevel` | `${juneau.restLogger.level:INFO}` |
+| `RestContext` | env-driven defaults for `uriAuthority`, `uriContext`
(`Optional<String>`-typed; null-vs-empty preserved) |
`${RestContext.uriAuthority}` / `${RestContext.uriContext}` |
| `RestOpContext` | env-driven defaults for `defaultCharset`, `maxInput` |
`${RestContext.defaultCharset:UTF-8}` / `${RestContext.maxInput:100000000}` |
| `BasicVersionResource.Builder` | `javaVersionDefault` |
`${java.version:Unknown}` |
| `Microservice.Builder` | `juneau.workingDir` | `${juneau.workingDir}` (via
`@Inject` initializer) |
@@ -37,6 +38,18 @@ Every one of these sites used to call `env(...)` or
`System.getProperty(...)` di
new flow routes through `BeanInstantiator` and inherits the standard
`Settings` lookup chain
documented in [`@Value` Annotation Basics](/docs/topics/ValueAnnotation).
+:::note 10.0.0 update — most `RestContext.*` sites moved to `@ConfigProperties`
+The 15 other `RestContext.*`-prefixed sites (`debugDefault`,
+`allowedHeaderParams`, `allowedMethodHeaders`, `allowedMethodParams`,
`disableContentParam`,
+`renderResponseStackTraces`, `problemDetails`, `virtualThreads`,
`responseTraceparent`,
+`mdcAsyncPropagation`, `eagerInit`, `lazyChildren`, `clientVersionHeader`,
`uriRelativity`,
+`uriResolution`) were collapsed in 10.0.0 into a single
`@ConfigProperties`-bound bean,
+`RestContextProperties` — see [`@ConfigProperties` Annotation
Basics](/docs/topics/ConfigProperties) and the
+[RestContext](/docs/topics/RestContext#restcontextproperties--env-driven-defaults-via-configproperties-1000)
+topic page. Only `defaultDebugLevel`, `uriAuthority`, and `uriContext` (the
table rows above) remain plain
+`@Value` fields on `RestContext`.
+:::
+
## Static-factory pattern
The five builders that did not previously flow through `BeanInstantiator` now
do, via a
diff --git a/pages/topics/02.10.03.ConfigProperties.md
b/pages/topics/02.10.03.ConfigProperties.md
new file mode 100644
index 0000000000..4cb4ee4dfd
--- /dev/null
+++ b/pages/topics/02.10.03.ConfigProperties.md
@@ -0,0 +1,192 @@
+---
+title: "@ConfigProperties Annotation Basics"
+slug: ConfigProperties
+---
+
+The <a
href="/site/apidocs/org/apache/juneau/commons/inject/ConfigProperties.html"
target="_blank">@ConfigProperties</a>
+annotation (introduced in 10.0.0, package
+[org.apache.juneau.commons.inject](/site/apidocs/org/apache/juneau/commons/inject/package-summary.html))
is a
+declarative, **prefix-scoped whole-object** config binder — Juneau's analog of
Spring Boot's
+`@ConfigurationProperties`.
+
+Where [`@Value`](/docs/topics/ValueAnnotation) resolves a single configuration
value onto a single field or
+parameter, `@ConfigProperties` resolves an entire prefix (`myapp.host`,
`myapp.port`, `myapp.timeout`, ...) onto
+the fields of one POJO in a single pass:
+
+```java
+import org.apache.juneau.commons.inject.ConfigProperties;
+
+@ConfigProperties(prefix = "MyService")
+public class MyServiceProperties {
+ public String host = "localhost";
+ public int port = 8080;
+}
+```
+
+The two annotations are complementary, not competing — a class can carry
`@Value` fields internally while also
+being the target of another class's nested `@ConfigProperties` bind (see
+[Nested config objects](#nested-config-objects) below), and
`@ConfigProperties` fields that are themselves
+annotated `@Value`/`@Inject` are left untouched by the config bind (see
+[Coexistence with `@Value` and `@Inject`](#coexistence-with-value-and-inject)).
+
+## Minimal end-to-end example
+
+Given the `MyServiceProperties` class above, materializing it through
+<a href="/site/apidocs/org/apache/juneau/commons/inject/BeanInstantiator.html"
target="_blank">BeanInstantiator</a>
+runs the bind automatically:
+
+```java
+BeanStore store = new BasicBeanStore(null);
+MyServiceProperties props = BeanInstantiator.of(MyServiceProperties.class,
store).run();
+```
+
+With `MyService.host=example.com` and `MyService.port=9090` set as system
properties (or environment variables,
+or any other registered <a
href="/site/apidocs/org/apache/juneau/commons/settings/PropertySource.html"
target="_blank">PropertySource</a>),
+`props.host` is `"example.com"` and `props.port` is `9090`. A key that isn't
present anywhere in the chain leaves
+the field's initializer value untouched — **bind-only-present** semantics, the
same "default lives in the field
+initializer" idea `@Value`'s `${key:default}` syntax expresses inline.
+
+You can also invoke the underlying binder directly, with or without the
annotation, via
+<a
href="/site/apidocs/org/apache/juneau/commons/inject/ConfigPropertiesBinder.html"
target="_blank">ConfigPropertiesBinder</a>'s
+fluent builder:
+
+```java
+MyServiceProperties props = ConfigPropertiesBinder.of(new
MyServiceProperties(), "MyService")
+ .relaxed(true) // default
+ .run();
+```
+
+## Relaxed key matching
+
+`relaxed()` defaults to `true` on the annotation (and on the binder). For each
field, the candidate key
+`prefix.fieldName` is probed in up to three spellings, via
+<a
href="/site/apidocs/org/apache/juneau/commons/settings/RelaxedPropertySource.html"
target="_blank">RelaxedPropertySource.candidates(String)</a> —
+the same relaxed-matching logic used elsewhere in `juneau-commons`:
+
+1. **Verbatim** — `MyService.host`
+2. **`SCREAMING_SNAKE_CASE`** — `MY_SERVICE_HOST` (the env-var-friendly
spelling)
+3. **`lower.dotted`** — `my.service.host`
+
+This is what lets a Kubernetes-style environment variable
(`MY_SERVICE_HOST=example.com`) satisfy a
+camelCase-prefixed key without any extra configuration. Set `relaxed = false`
on the annotation (or
+`.relaxed(false)` on the binder) to require an exact, verbatim key match only.
+
+## Source precedence
+
+Each candidate spelling is resolved through the same chain `@Value` uses —
**candidate-major**: every spelling
+is checked against the *entire* chain before the next spelling is tried, in
this order per candidate:
+
+1. A `Settings.setLocal(...)` / `Settings.setGlobal(...)` **test override**,
if one is recorded for that exact
+ candidate — always wins.
+2. Any caller-scoped <a
href="/site/apidocs/org/apache/juneau/commons/settings/PropertySource.html"
target="_blank">PropertySource</a>-typed
+ beans registered in a `BeanStore` passed via
`ConfigPropertiesBinder.of(...).beanStore(...)` (or supplied
+ automatically by the `@ConfigProperties` resolution hook — see below) —
consulted ahead of the global
+ `Settings` chain, first-match-wins among the scoped sources.
+3. The process-wide <a
href="/site/apidocs/org/apache/juneau/commons/settings/Settings.html"
target="_blank">Settings.get(name)</a>
+ chain — registered `PropertySource`s, system properties, then system
environment variables.
+
+Because precedence is candidate-major rather than source-major, a verbatim hit
in a *lower*-priority source can
+outrank a relaxed-spelling override set on a *higher*-priority source, if that
override used a different
+spelling than the one that resolved first. In practice this rarely matters —
most deployments pick one spelling
+convention per key — but it's worth knowing if a key is set two different ways
in two different places.
+
+The caller-scoped `PropertySource` layer is exactly how the `RestContext`
pilot (see
+[RestContext](/docs/topics/RestContext)) lets a resource's `@Rest(config=...)`
file participate in binding
+`RestContext.*` keys without mutating the shared `Settings.get()` singleton.
+
+## Nested config objects
+
+A field whose declared type is itself `@ConfigProperties`-annotated is bound
recursively, using
+`prefix.fieldName` as the sub-prefix — the field's own
`@ConfigProperties(prefix=...)` value is ignored for a
+nested bind (the enclosing prefix always wins):
+
+```java
+@ConfigProperties(prefix = "unused-when-nested")
+public class ServerProperties {
+ public String host = "localhost";
+ public int port = 80;
+}
+
+@ConfigProperties(prefix = "MyApp")
+public class MyAppProperties {
+ public ServerProperties server = new ServerProperties();
+}
+```
+
+`MyApp.server.host` and `MyApp.server.port` bind onto `server`'s fields. A
`null` nested field is only
+materialized (via an accessible no-arg constructor) if at least one key
resolves anywhere under its sub-prefix —
+otherwise it's left `null`, so an optional nested block doesn't force an empty
instance into existence. Circular
+`@ConfigProperties` nesting (a type that, directly or transitively, nests
itself) is detected and raises a
+`RuntimeException` rather than recursing indefinitely.
+
+This nested-field detection is inheritance-aware: a field whose *declared
type* is a subclass of an
+`@ConfigProperties`-annotated type still triggers a nested bind. This is
different from the annotation's own
+top-level trigger — see the note below.
+
+## Coexistence with `@Value` and `@Inject`
+
+`@ConfigProperties` and [`@Value`](/docs/topics/ValueAnnotation) serve
different granularities and coexist on
+the same class without conflict. A field already annotated `@Value` or
`@Inject` is **never** bound by
+`ConfigPropertiesBinder`, even when a matching `prefix.fieldName` key exists —
injection resolution owns those
+fields exclusively:
+
+```java
+@ConfigProperties(prefix = "MyService")
+public class MyServiceProperties {
+ public String host = "localhost"; // bound by
ConfigPropertiesBinder
+
+ @Value("${MyService.label:default-label}")
+ public String label; // bound by @Value, never
touched by the config bind
+}
+```
+
+When materialized through `BeanInstantiator`, the whole-object config bind
runs **after** `@Value`/`@Inject`
+field-and-method injection and **before** any `@PostConstruct` method, so a
`@PostConstruct` hook observes
+fully-bound config fields either way.
+
+## Auto-registration in the `BeanStore`
+
+When a `@ConfigProperties`-annotated class is materialized through
`BeanInstantiator`, the bound instance is
+automatically registered into the bean store as a framework default (a
non-clobbering
+`addDefaultSupplier` — lowest priority, so an explicit caller registration
still wins), under the
+**declared** annotated type. It's then retrievable anywhere downstream:
+
+```java
+MyServiceProperties props =
beanStore.getBean(MyServiceProperties.class).orElseThrow();
+```
+
+or injected directly:
+
+```java
+public class MyResource {
+ @Inject
+ MyServiceProperties props;
+}
+```
+
+**Not `@Inherited`:** the `BeanInstantiator` trigger fires only when the
*exact declared type* being
+instantiated carries `@ConfigProperties` — a subclass or interface implementor
of an annotated type does not
+itself trigger binding or auto-registration. (This is distinct from the
nested-field detection described above,
+which *is* inheritance-aware.)
+
+## Current limitations
+
+- **No `Optional<T>` / `Supplier<T>` field types.** Unlike `@Value`, type
conversion here is keyed on the
+ field's *raw* `Class`, not its full generic `Type` — generic container types
aren't supported as
+ `@ConfigProperties` field types. Use a plain field type (e.g. `String
uriAuthority` with a `null` default,
+ rather than `Optional<String>`) if you need "unset" to be distinguishable
from a real value.
+- **Validation is currently a no-op seam.** A post-bind extension point,
+ <a
href="/site/apidocs/org/apache/juneau/commons/inject/ConfigPropertiesValidator.html"
target="_blank">ConfigPropertiesValidator</a>,
+ is invoked once per bound object (innermost-nested first) — but the shipped
default,
+ `ConfigPropertiesValidator.NO_OP`, performs no validation. It exists purely
as a placement marker so a future
+ release can add JSR-303-style validation without changing the binder's
public shape.
+
+## See also
+
+- [`@Value` Annotation Basics](/docs/topics/ValueAnnotation) — the
single-value counterpart.
+- [Inject Package](/docs/topics/JuneauCommonsInject) — the broader
`org.apache.juneau.commons.inject` injection model.
+- [RestContext](/docs/topics/RestContext) — `RestContextProperties`, the
real-world `@ConfigProperties` pilot.
+- <a
href="/site/apidocs/org/apache/juneau/commons/inject/ConfigProperties.html"
target="_blank">org.apache.juneau.commons.inject.ConfigProperties</a>
+- <a
href="/site/apidocs/org/apache/juneau/commons/inject/ConfigPropertiesBinder.html"
target="_blank">org.apache.juneau.commons.inject.ConfigPropertiesBinder</a>
+- <a
href="/site/apidocs/org/apache/juneau/commons/inject/ConfigPropertiesValidator.html"
target="_blank">org.apache.juneau.commons.inject.ConfigPropertiesValidator</a>
+- <a
href="/site/apidocs/org/apache/juneau/commons/settings/RelaxedPropertySource.html"
target="_blank">org.apache.juneau.commons.settings.RelaxedPropertySource</a>
diff --git a/pages/topics/10.53.RestContext.md
b/pages/topics/10.53.RestContext.md
index d293971d19..f8bba60135 100644
--- a/pages/topics/10.53.RestContext.md
+++ b/pages/topics/10.53.RestContext.md
@@ -45,4 +45,57 @@ This is described in detail in the
[juneau-rest-server-springboot](/docs/topics/
:::
The lifecycle methods are still annotation-driven via `@RestInit`,
`@RestPreCall`, `@RestPostCall`, `@RestStartCall`, and
-`@RestDestroy`.
\ No newline at end of file
+`@RestDestroy`.
+
+## `RestContextProperties` — env-driven defaults via `@ConfigProperties`
(10.0.0)
+
+As of 10.0.0, the env-driven defaults behind most `RestContext.*` settings —
the values consulted when a
+`@Rest(...)` attribute is left unset — are resolved as a single bound object,
+<a
href="/site/apidocs/org/apache/juneau/rest/server/RestContextProperties.html"
target="_blank">RestContextProperties</a>,
+rather than as 15 separate `@Value` fields. `RestContextProperties` is declared
+`@ConfigProperties(prefix = "RestContext")` (see [`@ConfigProperties`
Annotation Basics](/docs/topics/ConfigProperties)
+for how the annotation and its underlying binder work), and it's the
framework's own pilot for that feature.
+
+Practically, this changes nothing about *how* you configure these settings — a
`RestContext.*` key is still
+resolved from the same places it always was:
+
+- A resource's
[`@Rest(config=...)`](/docs/topics/ValueAnnotation#per-resource-restconfig-integration)
file, via the
+ config's `PropertySource` registration in the resource's `BeanStore`.
+- Environment variables and system properties (relaxed key matching applies,
so `RestContext.clientVersionHeader`,
+ `REST_CONTEXT_CLIENT_VERSION_HEADER`, and
`rest.context.client.version.header`-style dotted forms are all
+ equivalent).
+- Any other registered `PropertySource`.
+
+What's new is that the bound instance itself is directly accessible — either
from the context:
+
+```java
+RestContextProperties props = ctx.getRestContextProperties();
+```
+
+or from the resource's bean store, since the bind auto-registers it (see
+[Auto-registration in the
`BeanStore`](/docs/topics/ConfigProperties#auto-registration-in-the-beanstore)):
+
+```java
+RestContextProperties props =
ctx.getBeanStore().getBean(RestContextProperties.class).orElseThrow();
+```
+
+Every existing public getter on `RestContext`
(`isRenderResponseStackTraces()`, `getClientVersionHeader()`,
+`getUriRelativity()`, etc.) keeps its exact signature and blending behavior
with `@Rest`-annotation overrides —
+they're unaffected thin wrappers; only the *source* of the default half of
that computation moved from a private
+`@Value` field to `RestContextProperties`.
+
+Two settings are intentionally **not** part of `RestContextProperties`:
`RestContext.uriAuthority` and
+`RestContext.uriContext` remain standalone
`@Value("${RestContext.uriAuthority}")` / `@Value("${RestContext.uriContext}")`
+`Optional<String>` fields directly on `RestContext`, because they carry a
null-vs-empty distinction that
+`@ConfigProperties`' current raw-type-only conversion can't express (see the
+[current limitations](/docs/topics/ConfigProperties#current-limitations) of
`@ConfigProperties`). The
+`juneau.restLogger.level` setting (a different prefix, owned by the
call-logger subsystem) is likewise unaffected.
+
+:::note Leniency improvement for present-but-empty booleans
+Under the pre-10.0.0 `@Value boolean` fields, a present-but-empty value (e.g.
`RestContext.eagerInit=`) threw
+`BeanCreationException`. As of 10.0.0, `RestContextProperties` carries every
boolean setting as a raw string and
+`RestContext` parses it leniently, so a present-but-empty value now resolves
to `false` instead of throwing —
+for all 8 boolean settings (`disableContentParam`,
`renderResponseStackTraces`, `problemDetails`,
+`virtualThreads`, `responseTraceparent`, `mdcAsyncPropagation`, `eagerInit`,
`lazyChildren`). See the
+[10.0.0 release notes](/docs/release-notes/10.0.0) for details.
+:::
\ No newline at end of file
diff --git a/sidebars.ts b/sidebars.ts
index 9ddb0db8ee..c09bf5a19a 100644
--- a/sidebars.ts
+++ b/sidebars.ts
@@ -128,6 +128,11 @@ const sidebars: SidebarsConfig = {
id:
'topics/02.10.02.ValueFrameworkInternal',
label:
'2.10.2. @Value Framework-Internal Adoption',
},
+ {
+ type:
'doc',
+ id:
'topics/02.10.03.ConfigProperties',
+ label:
'2.10.3. @ConfigProperties Annotation Basics',
+ },
],
},
{