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 527ec08ffe docs(9.5): document BeanInstantiator statics, 
CreatableBeanStore removal, WritableBeanStore narrowing, SpringBeanStore 
rename; fix BeanStore apidocs link
527ec08ffe is described below

commit 527ec08ffe7b466d86e72f438c36499e04aa2a6c
Author: James Bognar <[email protected]>
AuthorDate: Mon May 11 15:42:32 2026 -0400

    docs(9.5): document BeanInstantiator statics, CreatableBeanStore removal, 
WritableBeanStore narrowing, SpringBeanStore rename; fix BeanStore apidocs link
    
    Co-authored-by: Cursor <[email protected]>
---
 pages/release-notes/9.5.0.md                       | 124 +++++++++++++++++++++
 pages/topics/10.04.03.JavaMethodParameters.md      |   2 +-
 .../11.01.JuneauRestServerSpringbootBasics.md      |  29 +++++
 3 files changed, 154 insertions(+), 1 deletion(-)

diff --git a/pages/release-notes/9.5.0.md b/pages/release-notes/9.5.0.md
index 6bf004f8ff..a8b76af9fa 100644
--- a/pages/release-notes/9.5.0.md
+++ b/pages/release-notes/9.5.0.md
@@ -965,6 +965,91 @@ The following `asX()` methods have been removed in favor 
of their `toX()` equiva
 | `asReadableString()` *(JsonMap only)* | `toReadableJson5()` |
 | `asString(WriterSerializer)` | `toString(WriterSerializer)` |
 
+#### `BasicBeanStore` precedence-aware affordances
+
+`BasicBeanStore` (in `org.apache.juneau.cp`) gained two new affordances that 
power the 9.5 `RestContext` precedence flip (see *juneau-rest-server* below). 
Both are opt-in; existing call sites that use only `parent(...)` and local 
`addBean(...)` calls keep their current behavior.
+
+- **`Builder.overridingParent(BasicBeanStore)`** — Registers a parent bean 
store that is consulted *before* local entries during `getBean(...)` / 
`getBeanSupplier(...)`. The classic `parent(...)` slot keeps its post-entry 
fallback role. Useful for bridging an outer scope (Spring `ApplicationContext`, 
parent-resource bootstrap, test harness) on top of a child bean store and 
having the outer scope win without mutating local entries.
+- **`addDefaultSupplier(Class, Supplier)`** (and a named variant) — Registers 
a fallback supplier that fires only after local entries and the regular parent 
chain have all returned empty. Stored in a separate map from regular entries, 
so resolution order is unambiguous and `addBean(...)` calls can override the 
default at any time without removing the fallback.
+
+Final resolve order on `BasicBeanStore` is:
+
+```text
+overridingParent.getBeanSupplier(type, name)        // outer scope (e.g. 
Spring)
+  -> entries[type][name]                            // addBean(...) / 
@RestInject
+  -> parent.getBeanSupplier(type, name)             // regular fallback
+  -> defaults[type][name]                           // addDefaultSupplier(...)
+```
+
+`hasBean(...)` follows the same precedence; a new `hasDefaultSupplier(...)` 
accessor lets callers ask "is there a registered default for this type?" 
without forcing the supplier to fire.
+
+#### Removal of Legacy `cp` Injection Classes
+
+The following classes in `org.apache.juneau.cp` have been removed as part of 
the migration to the `org.apache.juneau.commons.inject` package:
+
+- **`BasicBeanStore`** (was `org.apache.juneau.cp.BasicBeanStore`) — replaced 
by `org.apache.juneau.commons.inject.BasicBeanStore` (renamed from 
`BasicBeanStore2`).
+- **`BeanCreator`** — replaced by 
`org.apache.juneau.commons.inject.BeanInstantiator`.
+- **`BeanBuilder`** — replaced by 
`org.apache.juneau.commons.inject.BeanInstantiator` (was the base class for 
domain fluent builders; replaced with native builder fields and 
`BeanInstantiator`).
+- **`BeanCreateMethodFinder`** — replaced by 
`BeanStore.createBeanFromMethod(...)`.
+- **`ContextBeanCreator`** is **not** removed — it solves a different problem 
(persistent `Context.Builder` holder for repeated annotation application) and 
is retained as a first-class API.
+
+**Migration guide:**
+
+| Legacy (`org.apache.juneau.cp`) | Replacement 
(`org.apache.juneau.commons.inject`) |
+|---|---|
+| `BasicBeanStore.create().build()` | `new BasicBeanStore()` |
+| `BasicBeanStore.INSTANCE` | `BasicBeanStore.INSTANCE` |
+| `BasicBeanStore.of(parent)` | `new BasicBeanStore(parent)` |
+| `BeanCreator.of(MyBean.class, store)` | `BeanInstantiator.of(MyBean.class, 
store)` |
+| `creator.arg(Type.class, value)` | `instantiator.addBean(Type.class, value)` 
|
+| `creator.type(Impl.class)` | `instantiator.type(Impl.class)` |
+| `creator.impl(instance)` | `instantiator.impl(instance)` |
+| `creator.run()` | `instantiator.run()` |
+| `creator.orElse(default)` | `instantiator.asOptional().orElse(default)` |
+| `new BeanCreateMethodFinder(type, obj, bs)` | `bs.createBeanFromMethod(type, 
obj, predicate)` |
+
+#### `BeanInstantiator` Static Convenience Methods
+
+Three static factory helpers have been added to `BeanInstantiator` to 
eliminate verbose ternary patterns at common call sites:
+
+| Method | Equivalent |
+|---|---|
+| `BeanInstantiator.createOrNull(Class<T>)` | `beanType == null ? null : 
BeanInstantiator.of(beanType).fallback(() -> null).run()` |
+| `BeanInstantiator.optionalOf(Class<T>)` | `beanType == null ? 
Optional.empty() : BeanInstantiator.of(beanType).asOptional()` |
+| `BeanInstantiator.createOrDefault(Class<T>, T)` | `beanType == null ? 
defaultValue : BeanInstantiator.of(beanType).run()` |
+
+All three return `null` / `Optional.empty()` / the default when the class 
argument is `null`, avoiding null-checks at every call site. Typical usage:
+
+```java
+// Before:
+var listenerCls = ctx.getListener();
+listener = listenerCls == null ? null : 
BeanInstantiator.of(listenerCls).fallback(() -> null).run();
+
+// After:
+listener = BeanInstantiator.createOrNull(ctx.getListener());
+```
+
+#### `CreatableBeanStore` Removed
+
+`CreatableBeanStore` (in `org.apache.juneau.commons.inject`) has been removed. 
It was an unused internal interface with no production callers. 
`WritableBeanStore` serves as the write-capable interface for the inject 
package.
+
+#### `WritableBeanStore` → `BeanStore` in Builder Classes
+
+The following builder-class constructors and fields have been narrowed from 
`WritableBeanStore` to `BeanStore` because they only perform read operations 
(bean lookup) on the store; they do not add beans:
+
+- `EncoderSet.Builder`
+- `SerializerSet.Builder`
+- `ParserSet.Builder`
+- `ResponseProcessorList.Builder`
+- `RestOpArgList.Builder`
+- `RestMatcherList.Builder`
+- `RestGuardList.Builder`
+- `RestConverterList.Builder`
+- `RestOperations.Builder`
+- `RestChildren.Builder`
+
+Callers that previously passed a `WritableBeanStore` still compile without 
changes, since `WritableBeanStore` extends `BeanStore`.
+
 ### juneau-marshall-rdf
 
 #### Upgraded Apache Jena to 5.6.0
@@ -1076,6 +1161,10 @@ String name
 
 ### juneau-rest-server
 
+#### `SpringBeanStore2` Renamed to `SpringBeanStore`
+
+`SpringBeanStore2` has been renamed to `SpringBeanStore` for consistency with 
the `BasicBeanStore2` → `BasicBeanStore` rename completed in this release. The 
old name `SpringBeanStore2` is removed; update any import or type reference to 
`org.apache.juneau.rest.springboot.SpringBeanStore`.
+
 #### `RestServerConstants`
 
 - **`RestServerConstants`** — Central place for **juneau-rest-server** static 
literals, starting with `Settings` keys. Serializer/parser session-option 
settings (`juneau.rest.sessionOptions.*`) use fields such as 
**`SETTING_sessionOptions_rejectWhenAllowlistEmpty`** and 
**`SETTING_sessionOptions_failOnInvalidAllowlistEntry`**. HTTP wire names for 
those options are fields on **`RestSharedConstants`** in 
**juneau-rest-common**. This supersedes the **`RestSessionOptionsSettings`** 
type.
@@ -1195,6 +1284,41 @@ Key changes:
 
 See the [V9.5 Migration Guide](/docs/topics/V9.5-migration-guide) for a 
per-setting replacement table.
 
+#### Bean precedence: Spring > `@RestInject` > default (breaking)
+
+The precedence order used by `RestContext` to resolve framework-managed beans 
(`CallLogger`, `EncoderSet`, `SerializerSet`, `ParserSet`, `ThrownStore`, 
`Config`, `VarResolver`, `HttpPartSerializer`, `HttpPartParser`, `Messages`, 
`MethodExecStore`, `JsonSchemaGenerator`, `StaticFiles`, `DebugEnablement`, 
`SwaggerProvider`, `RestOperations`, `RestChildren`, named `HeaderList` / 
`NamedAttributeMap` slots, etc.) has been flipped:
+
+| Tier | 9.4 and earlier | 9.5+ |
+| ---- | --------------- | ---- |
+| 1 (highest) | `@RestInject` method on the resource | **Spring `@Bean`** (or 
any bean reachable through the bootstrap / overriding-parent bean store) |
+| 2 | Spring `@Bean` (via `SpringBeanStore`) | **`@RestInject` method on the 
resource** |
+| 3 (lowest) | Memoizer-backed framework default | **Memoizer-backed framework 
default** |
+
+`@RestInject` is now documented as a *programmable default*, analogous to 
Spring's `@ConditionalOnMissingBean`: if a Spring bean of the same type (and 
name, where named) is available, it wins; otherwise the `@RestInject` method 
runs and its result is cached. Resolution short-circuits on the first hit, so 
non-Spring deployments collapse to the familiar `@RestInject > default` chain.
+
+Mechanically, the change is implemented through three new affordances on 
`BasicBeanStore`:
+
+- An **overriding parent** bean store (constructor / 
`Builder.overridingParent(...)`) that is consulted *before* local entries 
during `getBean(...)` / `getBeanSupplier(...)`. The Spring boot integration 
installs the application context bridge here.
+- **`addDefaultSupplier(Class, Supplier)`** (and a named variant) that 
registers a fallback supplier consulted *after* local entries and the regular 
parent. `RestContext` registers every memoizer-backed framework bean as a 
default supplier, so they only fire when nothing higher up in the chain has 
bound the type.
+- `RestContext.getBootstrapBeanStore()` continues to return a 
`BasicBeanStore`, but the resolution order on that store now reflects the new 
precedence model.
+
+Side effects of the new model:
+
+- The legacy `DELAYED_INJECTION` / `DELAYED_INJECTION_NAMES` skip lists in 
`RestContext` are gone. The `@RestInject` method walk now runs for every type 
with no hand-maintained filter; default-supplier presence is what auto-derives 
"skip this for now" behavior.
+- Inside each framework-bean memoizer body, redundant 
`bs.getBean(X).ifPresent(impl::override)` lookups have been removed. The bean 
store is the precedence engine — defaults no longer probe the store on the way 
out.
+- All `RestContext.getX()` accessor methods (`getCallLogger()`, `getConfig()`, 
`getVarResolver()`, etc.) now route through `beanStore.getBean(X)`, so internal 
callers see Spring overrides without needing to hit the bean store directly.
+
+##### Migration
+
+If you previously relied on `@RestInject` overriding a Spring `@Bean`, you 
have a few options in 9.5+:
+
+- **Preferred — let Spring win.** Remove the `@RestInject` method and lean on 
the Spring bean. The `@RestInject` was effectively a "default", which Spring 
already provides via `@ConditionalOnMissingBean` semantics on the bean factory.
+- **Skip the Spring `@Bean`.** Don't declare the type as a Spring `@Bean` and 
the `@RestInject` method will continue to win over the framework default.
+- **Use Spring-native overrides.** Mark the relevant Spring bean with 
`@Primary`, `@MockBean`, or `@ConditionalOnProperty` so Spring itself picks the 
right candidate. The bean store will then surface that candidate to 
`RestContext`.
+- **Programmatic registrations** that flow through 
`args.beanStoreConfigurer()` (the `Consumer<BasicBeanStore>` hook on 
`RestContextInit`) land as *regular* entries — the same tier as `@RestInject`. 
They no longer beat Spring; if you need that, register the bean as a Spring 
`@Bean` (or contribute it through the overriding-parent layer in a custom 
`BasicBeanStore` subclass).
+
+`SpringBeanStore` keeps backward-compatible behavior at the API level: as a 
`BasicBeanStore` subclass it picks up the new precedence model automatically 
when used through `RestContext`. Custom `BasicBeanStore` subclasses that want 
Spring-equivalent precedence can wire themselves in via 
`Builder.overridingParent(...)`; the existing `parent(...)` slot continues to 
behave as a regular fallback (consulted after local entries).
+
 #### `RestResponse.setSerializer(Serializer)`
 
 - **`RestResponse.setSerializer(Serializer)`** — Forces the serializer used 
for the response body (via `setContent(Object)` or equivalent), bypassing 
`Accept` header negotiation. Pass `null` to clear the override. `Content-Type` 
is still set by the response processor from the serializer when appropriate; 
you can call `setContentType(String)` first if needed.
diff --git a/pages/topics/10.04.03.JavaMethodParameters.md 
b/pages/topics/10.04.03.JavaMethodParameters.md
index 5f23278d3d..da9bf1e4c0 100644
--- a/pages/topics/10.04.03.JavaMethodParameters.md
+++ b/pages/topics/10.04.03.JavaMethodParameters.md
@@ -12,7 +12,7 @@ Java methods can contain any of the following parameters in 
any order:
 <node-1>**Response objects:**</node-1>
 <node-2><javac-class>`HttpServletResponse`</javac-class> <javac-class><a 
href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/OutputStream.html";
 target="_blank">OutputStream</a></javac-class> <javac-class><a 
href="/site/apidocs/org/apache/juneau/rest/RestResponse.html" 
target="_blank">RestResponse</a></javac-class> 
<javac-class>`ServletOutputStream`</javac-class> <javac-class><a 
href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/Writer.html";
  [...]
 <node-1>**Session objects:**</node-1>
-<node-2><javac-class>`HttpSession`</javac-class> <javac-class><a 
href="/site/apidocs/org/apache/juneau/rest/RestSession.html" 
target="_blank">RestSession</a></javac-class> <javac-class><a 
href="/site/apidocs/org/apache/juneau/rest/util/UrlPath.html" 
target="_blank">UrlPath</a></javac-class> <javac-class><a 
href="/site/apidocs/org/apache/juneau/rest/util/UrlPathMatch.html" 
target="_blank">UrlPathMatch</a></javac-class> <javac-class><a 
href="/site/apidocs/org/apache/juneau/cp/BeanStore.htm [...]
+<node-2><javac-class>`HttpSession`</javac-class> <javac-class><a 
href="/site/apidocs/org/apache/juneau/rest/RestSession.html" 
target="_blank">RestSession</a></javac-class> <javac-class><a 
href="/site/apidocs/org/apache/juneau/rest/util/UrlPath.html" 
target="_blank">UrlPath</a></javac-class> <javac-class><a 
href="/site/apidocs/org/apache/juneau/rest/util/UrlPathMatch.html" 
target="_blank">UrlPathMatch</a></javac-class> <javac-class><a 
href="/site/apidocs/org/apache/juneau/commons/inject/B [...]
 <node-1>**Parsed request header values:**</node-1>
 <node-2><javac-class><a 
href="/site/apidocs/org/apache/juneau/http/header/Accept.html" 
target="_blank">Accept</a></javac-class> <javac-class><a 
href="/site/apidocs/org/apache/juneau/http/header/AcceptCharset.html" 
target="_blank">AcceptCharset</a></javac-class> <javac-class><a 
href="/site/apidocs/org/apache/juneau/http/header/AcceptEncoding.html" 
target="_blank">AcceptEncoding</a></javac-class> <javac-class><a 
href="/site/apidocs/org/apache/juneau/http/header/AcceptLanguage.html" target= 
[...]
 <node-1>**Context values:**</node-1>
diff --git a/pages/topics/11.01.JuneauRestServerSpringbootBasics.md 
b/pages/topics/11.01.JuneauRestServerSpringbootBasics.md
index fc3f0d8404..6f45086694 100644
--- a/pages/topics/11.01.JuneauRestServerSpringbootBasics.md
+++ b/pages/topics/11.01.JuneauRestServerSpringbootBasics.md
@@ -29,3 +29,32 @@ org.apache.juneau.rest.server.springboot_0.0.0.jar
 
 The `juneau-rest-server-springboot` library provides classes to make it easy 
to integrate Juneau REST resources with
 Spring and Spring Boot.
+
+#### Bean Precedence (since 9.5.0)
+
+When a Juneau REST resource runs inside a Spring Boot application, 
framework-managed beans on `RestContext`
+(`CallLogger`, `EncoderSet`, `SerializerSet`, `ParserSet`, `ThrownStore`, 
`Config`, `VarResolver`,
+`HttpPartSerializer`, `HttpPartParser`, etc.) are resolved in the following 
order — the first match wins:
+
+1. **Spring `@Bean`** — any bean of the matching type (and name, where 
applicable) reachable through the
+   Spring `ApplicationContext` via `SpringBeanStore`.
+2. **`@RestInject` method/field on the resource class** — treated as a 
*programmable default*, analogous to
+   Spring's `@ConditionalOnMissingBean`.
+3. **Memoizer-backed framework default** — Juneau's built-in implementation 
(`BasicCallLogger`,
+   `BasicEncoderSet`, etc.).
+
+This is a behavior change from 9.4 and earlier, where `@RestInject` won over 
Spring. Migration tips:
+
+- **Preferred — let Spring win.** Remove the `@RestInject` method and lean on 
the Spring bean. The
+  `@RestInject` was effectively a "default", which Spring already provides 
through the bean factory.
+- **Skip the Spring `@Bean`.** Don't expose the type as a Spring `@Bean` and 
the `@RestInject` method on
+  the resource will continue to win over the framework default.
+- **Use Spring-native overrides.** Mark the relevant Spring bean with 
`@Primary`, `@MockBean`, or a
+  `@ConditionalOn...` predicate so Spring itself picks the right candidate; 
that candidate then becomes the
+  one Juneau sees through `SpringBeanStore`.
+
+Internally, this is implemented by installing `SpringBeanStore` as the 
**overriding parent** of the
+`RestContext`'s bean store (via 
`BasicBeanStore.Builder.overridingParent(...)`), and by registering every
+framework default as a `addDefaultSupplier(...)` entry on the same store — so 
Spring beans are consulted
+before any local registration, and built-in defaults fire only when nothing 
higher up has bound the type.
+See the 9.5.0 release notes for the full per-tier breakdown.

Reply via email to