This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new d303a7f57c refactor: align bean-store precedence and make RestContext 
eager init optional
d303a7f57c is described below

commit d303a7f57c4648b1a8784150ad2a86240474fad3
Author: James Bognar <[email protected]>
AuthorDate: Thu May 7 13:40:02 2026 -0400

    refactor: align bean-store precedence and make RestContext eager init 
optional
---
 .../juneau/commons/inject/BasicBeanStore2.java     | 137 ++++++++-
 .../juneau/commons/inject/WritableBeanStore.java   |  31 ++
 .../java/org/apache/juneau/cp/BasicBeanStore.java  | 159 +++++++++-
 .../java/org/apache/juneau/rest/RestContext.java   | 328 ++++++++++++---------
 .../apache/juneau/rest/RestServerConstants.java    |   3 +
 .../org/apache/juneau/rest/annotation/Rest.java    |  27 +-
 .../juneau/rest/annotation/RestAnnotation.java     |  19 ++
 .../apache/juneau/rest/annotation/RestInject.java  |  27 ++
 .../juneau/commons/inject/BasicBeanStore_Test.java | 191 ++++++++++++
 .../java/org/apache/juneau/cp/BeanStore_Test.java  |  89 ++++++
 .../juneau/rest/RestContext_Precedence_Test.java   | 128 ++++++++
 11 files changed, 976 insertions(+), 163 deletions(-)

diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BasicBeanStore2.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BasicBeanStore2.java
index f365319be4..1c5fed3531 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BasicBeanStore2.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BasicBeanStore2.java
@@ -40,6 +40,16 @@ import org.apache.juneau.commons.collections.*;
  * <p>
  * This implementation is thread-safe and supports parent bean stores for 
hierarchical bean resolution.
  *
+ * <h5 class='section'>Resolution order:</h5>
+ * <p>
+ * Bean lookups consult the following sources in this order, returning the 
first match:
+ * <ol>
+ *     <li>{@linkplain #BasicBeanStore2(BeanStore,BeanStore) Overriding 
parent} (e.g. a Spring application context bridge), if non-{@code null}.
+ *     <li>Local entries added via {@link #addBean(Class,Object) addBean} / 
{@link #addSupplier(Class,Supplier) addSupplier}.
+ *     <li>Regular {@linkplain #BasicBeanStore2(BeanStore) parent}, if 
non-{@code null}.
+ *     <li>Local default suppliers added via {@link 
#addDefaultSupplier(Class,Supplier) addDefaultSupplier} (memoizer-backed 
framework defaults).
+ * </ol>
+ *
  * <h5 class='section'>See Also:</h5><ul>
  *     <li class='jc'>{@link BeanStore} - Read-only bean lookup interface
  *     <li class='jc'>{@link WritableBeanStore} - Writable bean store interface
@@ -52,23 +62,54 @@ public class BasicBeanStore2 implements WritableBeanStore {
 
        // Property name constants
        private static final String PROP_bean = "bean";
+       private static final String PROP_defaults = "defaults";
        private static final String PROP_entries = "entries";
        private static final String PROP_identity = "identity";
        private static final String PROP_name = "name";
+       private static final String PROP_overridingParent = "overridingParent";
        private static final String PROP_parent = "parent";
        private static final String PROP_type = "type";
 
        private final ConcurrentHashMap<Class<?>, ConcurrentHashMap<String, 
Supplier<?>>> entries;
+       private final ConcurrentHashMap<Class<?>, ConcurrentHashMap<String, 
Supplier<?>>> defaults;
        private final BeanStore parent;
+       private final BeanStore overridingParent;
 
        /**
         * Constructor.
         *
-        * @param parent The parent bean store.  Can be <jk>null</jk>.  Bean 
searches are performed recursively up this parent chain.
+        * @param parent The parent bean store.  Can be <jk>null</jk>.  Bean 
searches are performed recursively up this parent chain
+        *      <i>after</i> local entries are checked.
         */
        public BasicBeanStore2(BeanStore parent) {
+               this(parent, null);
+       }
+
+       /**
+        * Constructor that accepts an overriding parent bean store.
+        *
+        * <p>
+        * The {@code overridingParent} is consulted <i>before</i> any local 
entries during bean lookup, allowing an outer
+        * scope (typically a Spring {@code ApplicationContext} bridge) to take 
precedence over local registrations.  The
+        * regular {@code parent} continues to be consulted as a fallback after 
local entries.
+        *
+        * <p>
+        * Final resolution order:
+        * <ol>
+        *      <li>{@code overridingParent} (if non-{@code null})
+        *      <li>local entries (added via {@link #addBean(Class,Object) 
addBean} / {@link #addSupplier(Class,Supplier) addSupplier})
+        *      <li>regular {@code parent} (if non-{@code null})
+        *      <li>local default suppliers (added via {@link 
#addDefaultSupplier(Class,Supplier) addDefaultSupplier})
+        * </ol>
+        *
+        * @param parent The parent bean store, used as a fallback after local 
entries.  Can be <jk>null</jk>.
+        * @param overridingParent The overriding parent bean store, consulted 
before local entries.  Can be <jk>null</jk>.
+        */
+       public BasicBeanStore2(BeanStore parent, BeanStore overridingParent) {
                this.parent = parent;
+               this.overridingParent = overridingParent;
                entries = new ConcurrentHashMap<>();
+               defaults = new ConcurrentHashMap<>();
                addSupplier(BasicBeanStore2.class, ()->this, null);
        }
 
@@ -162,6 +203,45 @@ public class BasicBeanStore2 implements WritableBeanStore {
                return this;
        }
 
+       /**
+        * Adds a fallback supplier for an unnamed bean of the specified type 
to this store.
+        *
+        * <p>
+        * Default suppliers are consulted only after local {@linkplain 
#addBean(Class,Object) entries} and the regular
+        * {@linkplain #BasicBeanStore2(BeanStore) parent} have been searched.  
They are intended for memoizer-backed
+        * framework defaults that should not shadow explicit user 
registrations or beans inherited from an
+        * {@linkplain #BasicBeanStore2(BeanStore,BeanStore) overriding parent} 
(e.g. Spring).
+        *
+        * @param <T> The bean type.
+        * @param beanType The bean type.
+        * @param supplier The bean supplier.
+        * @return This object.
+        */
+       @Override
+       public <T> BasicBeanStore2 addDefaultSupplier(Class<T> beanType, 
Supplier<T> supplier) {
+               return addDefaultSupplier(beanType, supplier, null);
+       }
+
+       /**
+        * Adds a fallback supplier for a named bean of the specified type to 
this store.
+        *
+        * <p>
+        * See {@link #addDefaultSupplier(Class,Supplier)} for ordering 
semantics.
+        *
+        * @param <T> The bean type.
+        * @param beanType The bean type.
+        * @param supplier The bean supplier.
+        * @param name The bean name.  Can be <jk>null</jk>.
+        * @return This object.
+        */
+       @Override
+       public <T> BasicBeanStore2 addDefaultSupplier(Class<T> beanType, 
Supplier<T> supplier, String name) {
+               var typeMap = defaults.computeIfAbsent(beanType, k -> new 
ConcurrentHashMap<>());
+               var key = emptyIfNull(name);
+               typeMap.put(key, supplier);
+               return this;
+       }
+
        /**
         * Removes all beans from this store.
         *
@@ -173,6 +253,7 @@ public class BasicBeanStore2 implements WritableBeanStore {
        @Override
        public BasicBeanStore2 clear() {
                entries.clear();
+               defaults.clear();
                return this;
        }
 
@@ -224,15 +305,20 @@ public class BasicBeanStore2 implements WritableBeanStore 
{
                "unchecked" // Type erasure requires cast to Map<String,T>
        })
        public <T> Map<String,T> getBeansOfType(Class<T> beanType) {
+               // Build the result respecting the priority order used by 
getBean / resolve:
+               //   defaults (lowest) < parent < entries (local) < 
overridingParent (highest)
+               // Higher-priority maps overwrite lower-priority ones with the 
same name.
                Map<String,T> result = map();
-               if (nn(parent)) {
-                       var parentBeans = parent.getBeansOfType(beanType);
-                       parentBeans.forEach(result::put);
-               }
+               var defaultMap = defaults.get(beanType);
+               if (nn(defaultMap))
+                       defaultMap.forEach((name, supplier) -> result.put(name, 
(T)supplier.get()));
+               if (nn(parent))
+                       parent.getBeansOfType(beanType).forEach(result::put);
                var typeMap = entries.get(beanType);
-               if (nn(typeMap)) {
+               if (nn(typeMap))
                        typeMap.forEach((name, supplier) -> result.put(name, 
(T)supplier.get()));
-               }
+               if (nn(overridingParent))
+                       
overridingParent.getBeansOfType(beanType).forEach(result::put);
                return result;
        }
 
@@ -295,6 +381,13 @@ public class BasicBeanStore2 implements WritableBeanStore {
                "unchecked" // Type erasure requires cast for supplier 
resolution
        })
        protected <T> Optional<Supplier<T>> resolve(Class<T> beanType, String 
name) {
+               // (1) Overriding parent (e.g. Spring) — wins over local 
entries.
+               if (nn(overridingParent)) {
+                       var fromOverriding = 
overridingParent.getBeanSupplier(beanType, name);
+                       if (fromOverriding.isPresent())
+                               return fromOverriding;
+               }
+               // (2) Local regular entries.
                var typeMap = entries.get(beanType);
                if (nn(typeMap)) {
                        var key = emptyIfNull(name);
@@ -302,8 +395,20 @@ public class BasicBeanStore2 implements WritableBeanStore {
                        if (nn(supplier))
                                return opt((Supplier<T>)supplier);
                }
-               if (nn(parent))
-                       return parent.getBeanSupplier(beanType, name);
+               // (3) Regular parent fallback.
+               if (nn(parent)) {
+                       var fromParent = parent.getBeanSupplier(beanType, name);
+                       if (fromParent.isPresent())
+                               return fromParent;
+               }
+               // (4) Local default suppliers (memoizer-backed framework 
defaults).
+               var defaultMap = defaults.get(beanType);
+               if (nn(defaultMap)) {
+                       var key = emptyIfNull(name);
+                       var supplier = defaultMap.get(key);
+                       if (nn(supplier))
+                               return opt((Supplier<T>)supplier);
+               }
                return opte();
        }
 
@@ -335,8 +440,22 @@ public class BasicBeanStore2 implements WritableBeanStore {
                        .a(PROP_type, cns(type))
                        .a(PROP_bean, id(supplier.get()))
                        .a(PROP_name, name))));
+               var defaultList = list();
+               defaults.forEach((type, typeMap) -> typeMap.forEach((name, 
supplier) -> defaultList.add(filteredBeanPropertyMap()
+                       .a(PROP_type, cns(type))
+                       .a(PROP_bean, id(supplier.get()))
+                       .a(PROP_name, name))));
+               Object overridingParentValue = null;
+               if (nn(overridingParent)) {
+                       if (overridingParent instanceof BasicBeanStore2 op2)
+                               overridingParentValue = op2.properties();
+                       else
+                               overridingParentValue = s(overridingParent);
+               }
                return filteredBeanPropertyMap()
                        .a(PROP_entries, entryList)
+                       .a(PROP_defaults, defaultList.isEmpty() ? null : 
defaultList)
+                       .a(PROP_overridingParent, overridingParentValue)
                        .a(PROP_identity, id(this))
                        .a(PROP_parent, parent instanceof BasicBeanStore2 
parent2 ? parent2.properties() : s(parent));
                // @formatter:on
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/WritableBeanStore.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/WritableBeanStore.java
index a548948330..b85ecea82e 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/WritableBeanStore.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/WritableBeanStore.java
@@ -99,6 +99,37 @@ public interface WritableBeanStore extends BeanStore {
         */
        <T> WritableBeanStore addSupplier(Class<T> beanType, Supplier<T> 
supplier, String name);
 
+       /**
+        * Adds a fallback supplier for an unnamed bean of the specified type 
to this store.
+        *
+        * <p>
+        * Default suppliers are consulted only after regular {@linkplain 
#addBean(Class,Object) entries} and the regular {@linkplain 
BasicBeanStore2#BasicBeanStore2(BeanStore) parent}
+        * chain have been searched.  They serve as a "use this if nothing else 
has provided one" hook,
+        * useful for memoizer-backed framework defaults that should not shadow 
explicit user
+        * registrations or beans inherited from an overriding parent (e.g. a 
Spring application context).
+        *
+        * @param <T> The bean type.
+        * @param beanType The bean type.
+        * @param supplier The bean supplier.  Must not be <jk>null</jk>.
+        * @return This object for method chaining.
+        */
+       <T> WritableBeanStore addDefaultSupplier(Class<T> beanType, Supplier<T> 
supplier);
+
+       /**
+        * Adds a fallback supplier for a named bean of the specified type to 
this store.
+        *
+        * <p>
+        * Default suppliers are consulted only after regular {@linkplain 
#addBean(Class,Object,String) entries} and the regular
+        * parent chain have been searched.  See {@link 
#addDefaultSupplier(Class,Supplier)}.
+        *
+        * @param <T> The bean type.
+        * @param beanType The bean type.
+        * @param supplier The bean supplier.  Must not be <jk>null</jk>.
+        * @param name The bean name.  Can be <jk>null</jk> for unnamed beans.
+        * @return This object for method chaining.
+        */
+       <T> WritableBeanStore addDefaultSupplier(Class<T> beanType, Supplier<T> 
supplier, String name);
+
        /**
         * Removes all beans from this store.
         *
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BasicBeanStore.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BasicBeanStore.java
index 01b3c58d39..7d0829921d 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BasicBeanStore.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BasicBeanStore.java
@@ -53,8 +53,20 @@ import org.apache.juneau.commons.reflect.*;
  *     <li class='jm'>{@link #addBean(Class,Object,String) 
addBean(Class,Object,String)}
  *     <li class='jm'>{@link #addSupplier(Class,Supplier) 
addSupplier(Class,Supplier)}
  *     <li class='jm'>{@link #addSupplier(Class,Supplier,String) 
addSupplier(Class,Supplier,String)}
+ *     <li class='jm'>{@link #addDefaultSupplier(Class,Supplier) 
addDefaultSupplier(Class,Supplier)} (last-resort fallback)
+ *     <li class='jm'>{@link #addDefaultSupplier(Class,Supplier,String) 
addDefaultSupplier(Class,Supplier,String)}
  * </ul>
  *
+ * <h5 class='section'>Resolution order:</h5>
+ * <p>
+ * Bean lookups consult the following sources in this order, returning the 
first match:
+ * <ol>
+ *     <li>{@linkplain Builder#overridingParent(BasicBeanStore) Overriding 
parent} (e.g. a Spring application context bridge), if non-{@code null}.
+ *     <li>Local entries added via {@link #addBean(Class,Object) addBean} / 
{@link #addSupplier(Class,Supplier) addSupplier}.
+ *     <li>Regular {@linkplain Builder#parent(BasicBeanStore) parent}, if 
non-{@code null}.
+ *     <li>Local default suppliers added via {@link 
#addDefaultSupplier(Class,Supplier) addDefaultSupplier} (memoizer-backed 
framework defaults).
+ * </ol>
+ *
  * <p>
  * Beans are retrieved through the following methods:
  * <ul class='javatreec'>
@@ -106,6 +118,7 @@ public class BasicBeanStore {
        public static class Builder {
 
                BasicBeanStore parent;
+               BasicBeanStore overridingParent;
                boolean readOnly;
                boolean threadSafe;
                Class<? extends BasicBeanStore> type;
@@ -177,6 +190,22 @@ public class BasicBeanStore {
                        return this;
                }
 
+               /**
+                * Specifies an overriding-parent bean store.
+                *
+                * <p>
+                * The overriding parent is consulted <i>before</i> any local 
entries during bean lookup, allowing an outer
+                * scope (typically a Spring {@code ApplicationContext} bridge) 
to take precedence over local registrations.
+                * The regular {@link #parent(BasicBeanStore)} continues to be 
consulted as a fallback after local entries.
+                *
+                * @param value The overriding-parent bean store.  Can be 
<jk>null</jk>.
+                * @return This object.
+                */
+               public Builder overridingParent(BasicBeanStore value) {
+                       overridingParent = value;
+                       return this;
+               }
+
                /**
                 * Specifies that the bean store is read-only.
                 *
@@ -251,9 +280,12 @@ public class BasicBeanStore {
 
        private final Deque<Entry<?>> entries;
        private final Map<Class<?>,Entry<?>> unnamedEntries;
+       private final Deque<Entry<?>> defaults;
+       private final Map<Class<?>,Entry<?>> unnamedDefaults;
        private final Map<Class<?>,Class<?>> beanTypes;
 
        final Optional<BasicBeanStore> parent;
+       final Optional<BasicBeanStore> overridingParent;
        final boolean readOnly;
        final boolean threadSafe;
        final SimpleReadWriteLock lock;
@@ -265,11 +297,14 @@ public class BasicBeanStore {
         */
        protected BasicBeanStore(Builder builder) {
                parent = opt(builder.parent);
+               overridingParent = opt(builder.overridingParent);
                readOnly = builder.readOnly;
                threadSafe = builder.threadSafe;
                lock = threadSafe ? new SimpleReadWriteLock() : 
SimpleReadWriteLock.NO_OP;
                entries = threadSafe ? new ConcurrentLinkedDeque<>() : new 
LinkedList<>();
                unnamedEntries = threadSafe ? new ConcurrentHashMap<>() : map();
+               defaults = threadSafe ? new ConcurrentLinkedDeque<>() : new 
LinkedList<>();
+               unnamedDefaults = threadSafe ? new ConcurrentHashMap<>() : 
map();
                beanTypes = threadSafe ? new ConcurrentHashMap<>() : map();
                var e = createEntry(BasicBeanStore.class, ()->this, null);
                entries.addFirst(e);
@@ -364,6 +399,47 @@ public class BasicBeanStore {
                return this;
        }
 
+       /**
+        * Adds a fallback supplier for an unnamed bean of the specified type 
to this factory.
+        *
+        * <p>
+        * Default suppliers are consulted only after local {@linkplain 
#addBean(Class,Object) entries} and the regular
+        * {@linkplain Builder#parent(BasicBeanStore) parent} have been 
searched.  They are intended for memoizer-backed
+        * framework defaults that should not shadow explicit user 
registrations or beans inherited from an
+        * {@linkplain Builder#overridingParent(BasicBeanStore) overriding 
parent} (e.g. Spring).
+        *
+        * @param <T> The class to associate this bean with.
+        * @param beanType The class to associate this bean with.
+        * @param bean The bean supplier.
+        * @return This object.
+        */
+       public <T> BasicBeanStore addDefaultSupplier(Class<T> beanType, 
Supplier<T> bean) {
+               return addDefaultSupplier(beanType, bean, null);
+       }
+
+       /**
+        * Adds a fallback supplier for a named bean of the specified type to 
this factory.
+        *
+        * <p>
+        * See {@link #addDefaultSupplier(Class,Supplier)} for ordering 
semantics.
+        *
+        * @param <T> The class to associate this bean with.
+        * @param beanType The class to associate this bean with.
+        * @param bean The bean supplier.
+        * @param name The bean name if this is a named bean.  Can be 
<jk>null</jk>.
+        * @return This object.
+        */
+       public <T> BasicBeanStore addDefaultSupplier(Class<T> beanType, 
Supplier<T> bean, String name) {
+               assertCanWrite();
+               var e = createEntry(beanType, bean, name);
+               try (var x = lock.write()) {
+                       defaults.addFirst(e);
+                       if (e(name))
+                               unnamedDefaults.put(beanType, e);
+               }
+               return this;
+       }
+
        /**
         * Clears out all bean in this bean store.
         *
@@ -377,6 +453,8 @@ public class BasicBeanStore {
                try (var x = lock.write()) {
                        unnamedEntries.clear();
                        entries.clear();
+                       unnamedDefaults.clear();
+                       defaults.clear();
                        beanTypes.clear();
                }
                return this;
@@ -451,11 +529,26 @@ public class BasicBeanStore {
        })
        public <T> Optional<T> getBean(Class<T> beanType) {
                try (var x = lock.read()) {
+                       // (1) Overriding parent (e.g. Spring) — wins over 
local entries.
+                       if (overridingParent.isPresent()) {
+                               var fromOverriding = 
overridingParent.get().getBean(beanType);
+                               if (fromOverriding.isPresent())
+                                       return fromOverriding;
+                       }
+                       // (2) Local entries.
                        var e = (Entry<T>)unnamedEntries.get(beanType);
                        if (nn(e))
                                return opt(e.get());
-                       if (parent.isPresent())
-                               return parent.get().getBean(beanType);
+                       // (3) Regular parent fallback.
+                       if (parent.isPresent()) {
+                               var fromParent = parent.get().getBean(beanType);
+                               if (fromParent.isPresent())
+                                       return fromParent;
+                       }
+                       // (4) Local default suppliers.
+                       var d = (Entry<T>)unnamedDefaults.get(beanType);
+                       if (nn(d))
+                               return opt(d.get());
                        return opte();
                }
        }
@@ -473,11 +566,26 @@ public class BasicBeanStore {
        })
        public <T> Optional<T> getBean(Class<T> beanType, String name) {
                try (var x = lock.read()) {
+                       // (1) Overriding parent.
+                       if (overridingParent.isPresent()) {
+                               var fromOverriding = 
overridingParent.get().getBean(beanType, name);
+                               if (fromOverriding.isPresent())
+                                       return fromOverriding;
+                       }
+                       // (2) Local entries.
                        var e = (Entry<T>)entries.stream().filter(x2 -> 
x2.matches(beanType, name)).findFirst().orElse(null);
                        if (nn(e))
                                return opt(e.get());
-                       if (parent.isPresent())
-                               return parent.get().getBean(beanType, name);
+                       // (3) Regular parent fallback.
+                       if (parent.isPresent()) {
+                               var fromParent = parent.get().getBean(beanType, 
name);
+                               if (fromParent.isPresent())
+                                       return fromParent;
+                       }
+                       // (4) Local default suppliers.
+                       var d = (Entry<T>)defaults.stream().filter(x2 -> 
x2.matches(beanType, name)).findFirst().orElse(null);
+                       if (nn(d))
+                               return opt(d.get());
                        return opte();
                }
        }
@@ -561,7 +669,10 @@ public class BasicBeanStore {
         * @return <jk>true</jk> if this store contains the specified unnamed 
bean type.
         */
        public boolean hasBean(Class<?> beanType) {
-               return unnamedEntries.containsKey(beanType) || parent.map(x -> 
x.hasBean(beanType)).orElse(false);
+               return overridingParent.map(x -> 
x.hasBean(beanType)).orElse(false)
+                       || unnamedEntries.containsKey(beanType)
+                       || parent.map(x -> x.hasBean(beanType)).orElse(false)
+                       || unnamedDefaults.containsKey(beanType);
        }
 
        /**
@@ -572,7 +683,43 @@ public class BasicBeanStore {
         * @return <jk>true</jk> if this store contains the specified named 
bean type.
         */
        public boolean hasBean(Class<?> beanType, String name) {
-               return entries.stream().anyMatch(x -> x.matches(beanType, 
name)) || parent.map(x -> x.hasBean(beanType, name)).orElse(false);
+               return overridingParent.map(x -> x.hasBean(beanType, 
name)).orElse(false)
+                       || entries.stream().anyMatch(x -> x.matches(beanType, 
name))
+                       || parent.map(x -> x.hasBean(beanType, 
name)).orElse(false)
+                       || defaults.stream().anyMatch(x -> x.matches(beanType, 
name));
+       }
+
+       /**
+        * Returns <jk>true</jk> if this store has a {@linkplain 
#addDefaultSupplier(Class,Supplier) default supplier}
+        * registered locally for the specified unnamed bean type.
+        *
+        * <p>
+        * This is intended for callers that need to distinguish "framework 
default present" from "any binding
+        * exists" — for example, the {@code RestContext} {@code @RestInject} 
eager walk uses this signal to
+        * skip types that are managed by an internal memoizer (replacing the 
legacy {@code DELAYED_INJECTION}
+        * skip-list).  Parent and overriding-parent stores are <i>not</i> 
consulted.
+        *
+        * @param beanType The bean type to check.
+        * @return <jk>true</jk> if a default supplier for the unnamed bean 
type is registered on this store.
+        */
+       public boolean hasDefaultSupplier(Class<?> beanType) {
+               return unnamedDefaults.containsKey(beanType);
+       }
+
+       /**
+        * Returns <jk>true</jk> if this store has a {@linkplain 
#addDefaultSupplier(Class,Supplier,String) default supplier}
+        * registered locally for the specified bean type and name.
+        *
+        * <p>
+        * See {@link #hasDefaultSupplier(Class)} for the rationale.  Parent 
and overriding-parent stores are
+        * <i>not</i> consulted.
+        *
+        * @param beanType The bean type to check.
+        * @param name The bean name.  Can be <jk>null</jk> for unnamed beans.
+        * @return <jk>true</jk> if a default supplier for the bean type and 
name is registered on this store.
+        */
+       public boolean hasDefaultSupplier(Class<?> beanType, String name) {
+               return defaults.stream().anyMatch(x -> x.matches(beanType, 
name));
        }
 
        protected FluentMap<String,Object> properties() {
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index 400599d0a0..b542c44c4b 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -221,61 +221,6 @@ public class RestContext extends Context {
         */
        static class Builder extends Context.Builder implements ServletConfig {
 
-               // @formatter:off
-               private static final Set<Class<?>> DELAYED_INJECTION = set(
-                       BasicBeanStore.Builder.class,
-                       BasicBeanStore.class,
-                       CallLogger.class,
-                       Config.class,
-                       DebugEnablement.class,
-                       EncoderSet.Builder.class,
-                       EncoderSet.class,
-                       FileFinder.Builder.class,
-                       FileFinder.class,
-                       HttpPartParser.class,
-                       HttpPartSerializer.class,
-                       JsonSchemaGenerator.class,
-                       Logger.class,
-                       Messages.class,
-                       MethodExecStore.class,
-                       ParserSet.Builder.class,
-                       ParserSet.class,
-                       ResponseProcessorList.Builder.class,
-                       ResponseProcessorList.class,
-                       RestChildren.Builder.class,
-                       RestChildren.class,
-                       RestOpArgList.Builder.class,
-                       RestOpArgList.class,
-                       RestOperations.Builder.class,
-                       RestOperations.class,
-                       SerializerSet.Builder.class,
-                       SerializerSet.class,
-                       StaticFiles.class,
-                       SwaggerProvider.class,
-                       ThrownStore.class,
-                       VarList.class,
-                       VarResolver.class
-               );
-
-               private static final Set<String> DELAYED_INJECTION_NAMES = set(
-                       PROP_bootstrapVarResolver,
-                       "destroyMethods",
-                       "endCallMethods",
-                       "postCallMethods",
-                       "postInitChildFirstMethods",
-                       "postInitMethods",
-                       "preCallMethods",
-                       "startCallMethods"
-               );
-               // @formatter:on
-
-               
//-----------------------------------------------------------------------------------------------------------------
-               // The following fields are meant to be modifiable.
-               // They should not be declared final.
-               // Read-only snapshots of these will be made in 
RestServletContext.
-               
//-----------------------------------------------------------------------------------------------------------------
-
-
                private final Class<?> resourceClass;
                private final RestContext parentContext;
                private final ServletConfig inner;
@@ -393,7 +338,11 @@ public class RestContext extends Context {
         * @return A new bean store builder.
         */
        private BasicBeanStore.Builder createBeanStore(BasicBeanStore parentBs, 
Supplier<?> resource) {
-               var v = Value.of(BasicBeanStore.create().parent(parentBs));
+               // The 9.5 precedence model places the parent (Spring or 
parent-resource bootstrap) as the
+               // overriding parent so it wins over local entries.  
Memoizer-backed framework defaults are
+               // registered later in the constructor via addDefaultSupplier, 
putting them at the bottom of
+               // the resolution order.
+               var v = 
Value.of(BasicBeanStore.create().overridingParent(parentBs));
 
                // Apply @Rest(beanStore).
                rstream(AnnotationProvider.INSTANCE.find(Rest.class, 
info(resourceClass))).map(x -> 
x.inner().beanStore()).filter(ClassUtils::isNotVoid).forEach(x -> 
v.get().type(x));
@@ -407,6 +356,59 @@ public class RestContext extends Context {
        private RestContext parentContext() { return parentContext; }
        private RestOperations restOperations() { return restOperations.get(); }
 
+       /**
+        * Registers memoizer-backed default suppliers for every 
framework-managed bean type on the supplied
+        * bean store.
+        *
+        * <p>
+        * Default suppliers sit at the bottom of the bean-store resolution 
order: they fire only when no
+        * {@link RestInject} method, no programmatic {@code addBean(...)} 
call, and no Spring/overriding-parent
+        * binding has been registered for the type.  This is the mechanism 
that replaces the old
+        * {@code DELAYED_INJECTION} list — by registering the framework's own 
factories as defaults
+        * <i>before</i> the {@link RestInject} method walk runs, any {@link 
RestInject} method whose parameters
+        * include framework types can now resolve those parameters lazily 
through the bean store without
+        * requiring a hand-maintained skip list.
+        */
+       private void registerFrameworkDefaults(BasicBeanStore bs) {
+               // @formatter:off
+               // Unnamed framework types backed by per-resource memoizers.
+               bs.addDefaultSupplier(BeanContext.class, beanContext::get);
+               bs.addDefaultSupplier(EncoderSet.class, encoders::get);
+               bs.addDefaultSupplier(SerializerSet.class, serializers::get);
+               bs.addDefaultSupplier(ParserSet.class, parsers::get);
+               bs.addDefaultSupplier(Logger.class, logger::get);
+               bs.addDefaultSupplier(java.util.logging.Logger.class, 
logger::get);
+               bs.addDefaultSupplier(ThrownStore.class, thrownStore::get);
+               bs.addDefaultSupplier(MethodExecStore.class, 
methodExecStore::get);
+               bs.addDefaultSupplier(Messages.class, messages::get);
+               bs.addDefaultSupplier(VarResolver.class, varResolver::get);
+               bs.addDefaultSupplier(Config.class, config::get);
+               bs.addDefaultSupplier(ResponseProcessor[].class, 
responseProcessors::get);
+               bs.addDefaultSupplier(CallLogger.class, callLogger::get);
+               bs.addDefaultSupplier(HttpPartSerializer.class, 
partSerializer::get);
+               bs.addDefaultSupplier(HttpPartParser.class, partParser::get);
+               bs.addDefaultSupplier(JsonSchemaGenerator.class, 
jsonSchemaGenerator::get);
+               bs.addDefaultSupplier(StaticFiles.class, staticFiles::get);
+               bs.addDefaultSupplier(FileFinder.class, staticFiles::get);
+               bs.addDefaultSupplier(DebugEnablement.class, 
debugEnablement::get);
+               bs.addDefaultSupplier(SwaggerProvider.class, 
swaggerProvider::get);
+               bs.addDefaultSupplier(RestOperations.class, 
restOperations::get);
+               bs.addDefaultSupplier(RestChildren.class, restChildren::get);
+               // Named framework beans (replaces DELAYED_INJECTION_NAMES).
+               bs.addDefaultSupplier(VarResolver.class, 
this::getBootstrapVarResolver, PROP_bootstrapVarResolver);
+               bs.addDefaultSupplier(HeaderList.class, 
defaultRequestHeaders::get, PROP_defaultRequestHeaders);
+               bs.addDefaultSupplier(HeaderList.class, 
defaultResponseHeaders::get, PROP_defaultResponseHeaders);
+               bs.addDefaultSupplier(NamedAttributeMap.class, 
defaultRequestAttributes::get, PROP_defaultRequestAttributes);
+               bs.addDefaultSupplier(MethodList.class, () -> 
destroyInvokerPair.get().methods, "destroyMethods");
+               bs.addDefaultSupplier(MethodList.class, () -> 
endCallInvokerPair.get().methods, "endCallMethods");
+               bs.addDefaultSupplier(MethodList.class, postCallMethods::get, 
"postCallMethods");
+               bs.addDefaultSupplier(MethodList.class, () -> 
postInitChildFirstInvokerPair.get().methods, "postInitChildFirstMethods");
+               bs.addDefaultSupplier(MethodList.class, () -> 
postInitInvokerPair.get().methods, "postInitMethods");
+               bs.addDefaultSupplier(MethodList.class, preCallMethods::get, 
"preCallMethods");
+               bs.addDefaultSupplier(MethodList.class, () -> 
startCallInvokerPair.get().methods, "startCallMethods");
+               // @formatter:on
+       }
+
        private static final class LifecycleInvokerPair {
                final MethodList methods;
                final MethodInvoker[] invokers;
@@ -426,7 +428,6 @@ public class RestContext extends Context {
         */
        private final Memoizer<BeanContext.Builder> beanContextBuilder = 
memoizer(() -> {
                var v = Value.of(BeanContext.create());
-               beanStore().getBean(BeanContext.class).ifPresent(x -> 
v.get().impl(x));
                v.get().apply(annotationWork);
                return v.get();
        });
@@ -447,7 +448,9 @@ public class RestContext extends Context {
        private final Memoizer<Config> rawConfig = memoizer(() -> {
                var bs = beanStore();
                var v = Value.<Config>empty();
-               var vr = bs.getBean(VarResolver.class).orElseThrow(() -> new 
IllegalArgumentException("VarResolver not found."));
+               // Bootstrap VarResolver is registered under 
PROP_bootstrapVarResolver during construction; the
+               // unnamed VarResolver slot is reserved for the full runtime 
resolver default supplier.
+               var vr = bs.getBean(VarResolver.class, 
PROP_bootstrapVarResolver).orElseGet(this::getBootstrapVarResolver);
                var cfv = Value.<String>empty();
                rstream(AnnotationProvider.INSTANCE.find(Rest.class, 
info(resourceClass()))).map(x -> 
x.inner().config()).filter(Utils::ne).forEach(x -> cfv.set(vr.resolve(x)));
                var cf = cfv.orElse("");
@@ -459,7 +462,6 @@ public class RestContext extends Context {
                                cb.name(cf);
                        v.set(cb.build());
                }
-               bs.getBean(Config.class).ifPresent(v::set);
                new BeanCreateMethodFinder<>(Config.class, resource().get(), 
bs).addBean(Config.class, 
v.get()).find(RestContext::isRestInjectMethod).run(v::set);
                return v.get();
        });
@@ -489,7 +491,6 @@ public class RestContext extends Context {
                                .bean(FileFinder.class, 
FileFinder.create(bs).cp(resourceClass(), null, true).build())
                                .build()
                );
-               bs.getBean(VarResolver.class, 
PROP_bootstrapVarResolver).ifPresent(v::set);
                new BeanCreateMethodFinder<>(VarResolver.class, 
resource().get(), bs).find(x -> isRestInjectMethod(x, 
PROP_bootstrapVarResolver)).run(v::set);
                return v.get();
        });
@@ -515,7 +516,6 @@ public class RestContext extends Context {
                        .filter(c -> c != CallLogger.Void.class)
                        .reduce((first, second) -> second)
                        .ifPresent(creator::type);
-               bs.getBean(CallLogger.class).ifPresent(creator::impl);
                new BeanCreateMethodFinder<>(CallLogger.class, 
resource().get(), bs).find(RestContext::isRestInjectMethod).run(creator::impl);
                return creator.orElse(null);
        });
@@ -584,7 +584,6 @@ public class RestContext extends Context {
                        .filter(c -> c != DebugEnablement.Void.class)
                        .reduce((first, second) -> second)
                        .ifPresent(creator::type);
-               bs.getBean(DebugEnablement.class).ifPresent(creator::impl);
                new BeanCreateMethodFinder<>(DebugEnablement.class, 
resource().get(), bs).find(RestContext::isRestInjectMethod).run(creator::impl);
                return creator.orElse(null);
        });
@@ -605,7 +604,6 @@ public class RestContext extends Context {
                        .filter(StringUtils::isNotBlank)
                        .map(BasicNamedAttribute::ofPair)
                        .forEach(v.get()::add));
-               beanStore().getBean(NamedAttributeMap.class, 
PROP_defaultRequestAttributes).ifPresent(v::set);
                new BeanCreateMethodFinder<>(NamedAttributeMap.class, 
resource().get(), beanStore()).addBean(NamedAttributeMap.class, v.get()).find(x 
-> isRestInjectMethod(x, PROP_defaultRequestAttributes)).run(v::set);
                return v.get();
        });
@@ -630,7 +628,6 @@ public class RestContext extends Context {
                        if (isNotBlank(defaultContentType))
                                
v.get().setDefault(contentType(defaultContentType));
                });
-               beanStore().getBean(HeaderList.class, 
PROP_defaultRequestHeaders).ifPresent(v::set);
                new BeanCreateMethodFinder<>(HeaderList.class, 
resource().get(), beanStore()).addBean(HeaderList.class, v.get()).find(x -> 
isRestInjectMethod(x, PROP_defaultRequestHeaders)).run(v::set);
                return v.get();
        });
@@ -645,7 +642,6 @@ public class RestContext extends Context {
        private final Memoizer<HeaderList> defaultResponseHeaders = memoizer(() 
-> {
                var v = Value.of(HeaderList.create());
                getRestAnnotationsTopDown().forEach(ai -> 
Arrays.stream(ai.inner().defaultResponseHeaders()).filter(StringUtils::isNotBlank).map(this::resolve).filter(StringUtils::isNotBlank).map(s
 -> stringHeader(s)).forEach(v.get()::setDefault));
-               beanStore().getBean(HeaderList.class, 
PROP_defaultResponseHeaders).ifPresent(v::set);
                new BeanCreateMethodFinder<>(HeaderList.class, 
resource().get(), beanStore()).addBean(HeaderList.class, v.get()).find(x -> 
isRestInjectMethod(x, PROP_defaultResponseHeaders)).run(v::set);
                return v.get();
        });
@@ -674,7 +670,6 @@ public class RestContext extends Context {
                var bs = beanStore();
                var v = Value.of(EncoderSet.create(bs));
                bs.getBeanType(EncoderSet.class).ifPresent(x -> 
v.get().type(x));
-               bs.getBean(EncoderSet.class).ifPresent(x -> v.get().impl(x));
                getRestAnnotationsForProperty(PROPERTY_encoders).forEach(ai -> 
v.get().add(ai.inner().encoders()));
                new BeanCreateMethodFinder<>(EncoderSet.class, 
resource().get(), bs).addBean(EncoderSet.Builder.class, 
v.get()).find(RestContext::isRestInjectMethod).run(x -> v.get().impl(x));
                return v.get();
@@ -701,7 +696,6 @@ public class RestContext extends Context {
        private final Memoizer<JsonSchemaGenerator.Builder> 
jsonSchemaGeneratorBuilder = memoizer(() -> {
                var bs = beanStore();
                var v = Value.of(JsonSchemaGenerator.create());
-               bs.getBean(JsonSchemaGenerator.class).ifPresent(x -> 
v.get().impl(x));
                new BeanCreateMethodFinder<>(JsonSchemaGenerator.class, 
resource().get(), bs).find(RestContext::isRestInjectMethod).run(x -> 
v.get().impl(x));
                v.get().apply(annotationWork);
                return v.get();
@@ -721,7 +715,6 @@ public class RestContext extends Context {
         */
        private final Memoizer<Logger> logger = memoizer(() -> {
                var v = Value.of(Logger.getLogger(cn(resourceClass())));
-               beanStore().getBean(Logger.class).ifPresent(v::set);
                new BeanCreateMethodFinder<>(Logger.class, resource().get(), 
beanStore()).addBean(Logger.class, 
v.get()).find(RestContext::isRestInjectMethod).run(v::set);
                return v.get();
        });
@@ -741,7 +734,6 @@ public class RestContext extends Context {
                // (it depends on getMessages()).
                var vrs = getBootstrapVarResolver().createSession();
                getRestAnnotationsTopDown().forEach(ai -> 
ai.getString(PROPERTY_messages).filter(StringUtils::isNotBlank).ifPresent(s -> 
b.location(vrs.resolve(s))));
-               beanStore().getBean(Messages.class).ifPresent(b::impl);
                new BeanCreateMethodFinder<>(Messages.class, resource().get(), 
beanStore()).addBean(Messages.Builder.class, 
b).find(RestContext::isRestInjectMethod).run(b::impl);
                return b.build();
        });
@@ -756,7 +748,6 @@ public class RestContext extends Context {
                var bs = beanStore();
                var b = 
MethodExecStore.create(bs).thrownStoreOnce(getThrownStore());
                bs.getBeanType(MethodExecStore.class).ifPresent(b::type);
-               bs.getBean(MethodExecStore.class).ifPresent(b::impl);
                new BeanCreateMethodFinder<>(MethodExecStore.class, 
resource().get(), bs).addBean(MethodExecStore.Builder.class, 
b).find(RestContext::isRestInjectMethod).run(b::impl);
                return b.build();
        });
@@ -773,7 +764,6 @@ public class RestContext extends Context {
                var bs = beanStore();
                var v = Value.of(ParserSet.create(bs));
                bs.getBeanType(ParserSet.class).ifPresent(x -> v.get().type(x));
-               bs.getBean(ParserSet.class).ifPresent(x -> v.get().impl(x));
                getRestAnnotationsForProperty(PROPERTY_parsers).forEach(ai -> 
v.get().add(ai.inner().parsers()));
                new BeanCreateMethodFinder<>(ParserSet.class, resource().get(), 
bs).addBean(ParserSet.Builder.class, 
v.get()).find(RestContext::isRestInjectMethod).run(x -> v.get().impl(x));
                return v.get();
@@ -790,7 +780,6 @@ public class RestContext extends Context {
        private final Memoizer<HttpPartParser.Creator> partParserCreator = 
memoizer(() -> {
                var bs = beanStore();
                Value<HttpPartParser.Creator> v = 
Value.of(HttpPartParser.creator().type(OpenApiParser.class));
-               bs.getBean(HttpPartParser.class).ifPresent(x -> 
v.get().impl(x));
                opt(resource().get() instanceof HttpPartParser x ? x : 
null).ifPresent(x -> v.get().impl(x));
                bs.getBeanType(HttpPartParser.class).ifPresent(x -> 
v.get().type(x));
                new BeanCreateMethodFinder<>(HttpPartParser.class, 
resource().get(), bs).find(RestContext::isRestInjectMethod).run(x -> 
v.get().impl(x));
@@ -821,7 +810,6 @@ public class RestContext extends Context {
        private final Memoizer<HttpPartSerializer.Creator> 
partSerializerCreator = memoizer(() -> {
                var bs = beanStore();
                Value<HttpPartSerializer.Creator> v = 
Value.of(HttpPartSerializer.creator().type(OpenApiSerializer.class));
-               bs.getBean(HttpPartSerializer.class).ifPresent(x -> 
v.get().impl(x));
                opt(resource().get() instanceof HttpPartSerializer x ? x : 
null).ifPresent(x -> v.get().impl(x));
                bs.getBeanType(HttpPartSerializer.class).ifPresent(x -> 
v.get().type(x));
                new BeanCreateMethodFinder<>(HttpPartSerializer.class, 
resource().get(), bs).find(RestContext::isRestInjectMethod).run(x -> 
v.get().impl(x));
@@ -927,7 +915,6 @@ public class RestContext extends Context {
                getRestAnnotationsForProperty(PROPERTY_responseProcessors)
                        .forEach(ai -> 
v.get().add(ai.inner().responseProcessors()));
                // Bean-store override REPLACES the entire annotation-derived 
list.
-               bs.getBean(ResponseProcessorList.class).ifPresent(x -> 
v.get().impl(x));
                // @RestInject method override REPLACES the entire 
annotation-derived list.
                new BeanCreateMethodFinder<>(ResponseProcessorList.class, 
resource().get(), bs)
                        .addBean(ResponseProcessorList.Builder.class, v.get())
@@ -953,7 +940,6 @@ public class RestContext extends Context {
                getRestAnnotationsForProperty(PROPERTY_restOpArgs)
                        .forEach(ai -> v.get().add(ai.inner().restOpArgs()));
                // Bean-store override REPLACES the entire annotation-derived 
list.
-               bs.getBean(RestOpArgList.class).ifPresent(x -> v.get().impl(x));
                // @RestInject method override REPLACES the entire 
annotation-derived list.
                new BeanCreateMethodFinder<>(RestOpArgList.class, 
resource().get(), bs)
                        .addBean(RestOpArgList.Builder.class, v.get())
@@ -974,7 +960,6 @@ public class RestContext extends Context {
                var bs = beanStore();
                var v = Value.of(SerializerSet.create(bs));
                bs.getBeanType(SerializerSet.class).ifPresent(x -> 
v.get().type(x));
-               bs.getBean(SerializerSet.class).ifPresent(x -> v.get().impl(x));
                getRestAnnotationsForProperty(PROPERTY_serializers).forEach(ai 
-> v.get().add(ai.inner().serializers()));
                new BeanCreateMethodFinder<>(SerializerSet.class, 
resource().get(), bs).addBean(SerializerSet.Builder.class, 
v.get()).find(RestContext::isRestInjectMethod).run(x -> v.get().impl(x));
                return v.get();
@@ -1013,7 +998,6 @@ public class RestContext extends Context {
                        .filter(c -> c != StaticFiles.Void.class)
                        .reduce((first, second) -> second)
                        .ifPresent(creator::type);
-               bs.getBean(StaticFiles.class).ifPresent(creator::impl);
                new BeanCreateMethodFinder<>(StaticFiles.class, 
resource().get(), bs).find(RestContext::isRestInjectMethod).run(creator::impl);
                return creator.orElse(null);
        });
@@ -1036,7 +1020,6 @@ public class RestContext extends Context {
                        .filter(c -> c != SwaggerProvider.Void.class)
                        .reduce((first, second) -> second)
                        .ifPresent(creator::type);
-               bs.getBean(SwaggerProvider.class).ifPresent(creator::impl);
                new BeanCreateMethodFinder<>(SwaggerProvider.class, 
resource().get(), bs).find(RestContext::isRestInjectMethod).run(creator::impl);
                return creator.orElse(null);
        });
@@ -1052,7 +1035,6 @@ public class RestContext extends Context {
                var bs = beanStore();
                var b = ThrownStore.create(bs).impl(parentContext() == null ? 
null : parentContext().getThrownStore());
                bs.getBeanType(ThrownStore.class).ifPresent(b::type);
-               bs.getBean(ThrownStore.class).ifPresent(b::impl);
                new BeanCreateMethodFinder<>(ThrownStore.class, 
resource().get(), bs).addBean(ThrownStore.Builder.class, 
b).find(RestContext::isRestInjectMethod).run(b::impl);
                return b.build();
        });
@@ -1070,7 +1052,6 @@ public class RestContext extends Context {
                var b = getBootstrapVarResolver().copy()
                        .bean(Messages.class, getMessages())
                        .bean(Config.class, rawConfig.get());
-               bs.getBean(VarResolver.class).ifPresent(b::impl);
                new BeanCreateMethodFinder<>(VarResolver.class, 
resource().get(), bs).addBean(VarResolver.Builder.class, 
b).find(RestContext::isRestInjectMethod).run(b::impl);
                return b.build();
        });
@@ -1086,6 +1067,7 @@ public class RestContext extends Context {
         */
        @SuppressWarnings({"java:S3776", "java:S1141"})
        private final Memoizer<RestOperations> restOperations = memoizer(() -> 
safe(() -> {
+               initializeFrameworkBeansForRestOps();
                var bs = beanStore();
                var v = Value.of(RestOperations.create(bs));
                var ap = getBeanContext().getAnnotationProvider();
@@ -1206,12 +1188,14 @@ public class RestContext extends Context {
                        var rs = new ResourceSupplier(resourceClass, 
assertArgNotNull("resource", builder.args.resource()));
                        resource = rs;
 
-                       // --- beanStore setup (moved from Builder constructor, 
May 2026 refactor) ---
+                       // --- beanStore setup (May 2026 refactor; 
precedence-flipped 9.5) ---
 
                        // Determine the parent (bootstrap) store: inherited 
from parent resource if present.
                        BasicBeanStore parentBs = parentContext != null ? 
parentContext.bootstrapBeanStore : null;
 
                        // Build the initial beanStore; apply @Rest(beanStore) 
+ optional @RestInject override.
+                       // In the new 9.5 precedence model, the parent (Spring 
or parent-resource bootstrap) is
+                       // installed as the overriding parent so it wins over 
local entries.
                        // @formatter:off
                        BasicBeanStore bs = createBeanStore(parentBs, rs)
                                .build()
@@ -1220,18 +1204,34 @@ public class RestContext extends Context {
                                .addBean(ServletContext.class, 
(nn(builder.inner) ? builder.inner : builder).getServletContext());
                        // @formatter:on
 
-                       // If no parent store, promote bs to bootstrap and 
layer a fresh child store on top.
+                       // If no parent store, promote bs to bootstrap and 
layer a fresh per-resource store on top.
                        if (parentBs == null) {
                                bootstrapBeanStore = bs;
-                               bs = BasicBeanStore.of(bootstrapBeanStore);
+                               bs = 
BasicBeanStore.create().overridingParent(bootstrapBeanStore).build();
                        } else {
                                bootstrapBeanStore = parentBs;
                        }
                        beanStore = bs;
 
                        beanStore.add(BasicBeanStore.class, beanStore);
-                       beanStore.add(VarResolver.class, 
getBootstrapVarResolver());
-                       beanStore.add(Config.class, rawConfig.get());
+                       // Register the bootstrap VarResolver as a NAMED entry 
only.  The unnamed VarResolver
+                       // slot is intentionally left to the 
registerFrameworkDefaults() default supplier (which
+                       // resolves to the full runtime VarResolver) so that 
internal accessors such as
+                       // getVarResolver() return the right thing when routed 
through beanStore.getBean(...).
+                       beanStore.add(VarResolver.class, 
getBootstrapVarResolver(), PROP_bootstrapVarResolver);
+                       // Force-build raw Config now (fail fast if 
@Rest(config) is misconfigured).  The unnamed
+                       // Config slot in the bean store is intentionally left 
to the default supplier (the full
+                       // runtime Config) — @RestInit hooks that take Config 
as a parameter will see the fully
+                       // resolved instance instead of the raw bootstrap 
Config (9.5 behavior change).
+                       rawConfig.get();
+
+                       // Register memoizer-backed defaults for every 
framework-managed type.  These sit at the
+                       // bottom of the precedence order and only fire when no 
@RestInject method, no programmatic
+                       // add, and no Spring/overriding-parent bean has been 
registered for the type.  This is
+                       // what removes the need for the old DELAYED_INJECTION 
gate-keeping list — the @RestInject
+                       // walk below can now invoke any framework type's 
factory and still resolve framework
+                       // dependencies through the bean store.
+                       registerFrameworkDefaults(beanStore);
 
                        var rci2 = ClassInfo.of(resourceClass);
 
@@ -1248,17 +1248,22 @@ public class RestContext extends Context {
                                ));
                        // @formatter:on
 
-                       // Run non-delayed @RestInject methods.
+                       // Run @RestInject methods for non-framework types.  
Framework types (those with a default
+                       // supplier registered above) handle their @RestInject 
scan inside the corresponding memoizer
+                       // body so that user methods can declare the 
framework's Builder type as a parameter; running
+                       // them again here would either re-invoke side effects 
or skip them entirely (for Pattern-2
+                       // methods whose Builder parameter isn't injected 
here).  This auto-derives the legacy
+                       // DELAYED_INJECTION list from the default-supplier 
registrations.
                        rci2.getAllMethods().stream().filter(x -> 
x.hasAnnotation(RestInject.class)).forEach(x -> {
                                var rt = x.getReturnType().<Object>inner();
                                var name = 
RestInjectAnnotation.name(x.getAnnotations(RestInject.class).findFirst().map(AnnotationInfo::inner).orElse(null));
-                               if (! (Builder.DELAYED_INJECTION.contains(rt) 
|| Builder.DELAYED_INJECTION_NAMES.contains(name))) {
-                                       // @formatter:off
-                                       new BeanCreateMethodFinder<>(rt, 
resource.get(), beanStore)
-                                               
.find(RestContext::isRestInjectMethod)
-                                               .run(y -> beanStore.add(rt, y, 
name));
-                                       // @formatter:on
-                               }
+                               if (beanStore.hasDefaultSupplier(rt, name))
+                                       return;
+                               // @formatter:off
+                               new BeanCreateMethodFinder<>(rt, 
resource.get(), beanStore)
+                                       .find(RestContext::isRestInjectMethod)
+                                       .run(y -> beanStore.add(rt, y, name));
+                               // @formatter:on
                        });
 
                        // Run @RestInit-annotated methods on the resource 
object (deduplicated by signature, top-down order).
@@ -1328,37 +1333,20 @@ public class RestContext extends Context {
                                .addBean(AnnotationWorkList.class, 
annotationWork);
                        // @formatter:on
 
-                       bs.addBean(BeanContext.class, getBeanContext());
-                       bs.add(EncoderSet.class, getEncoders());
-                       bs.add(SerializerSet.class, getSerializers());
-                       bs.add(ParserSet.class, getParsers());
-                       var lg = getLogger();
-                       bs.addBean(Logger.class, lg);
-                       bs.addBean(java.util.logging.Logger.class, lg); // Also 
register under java.util.logging.Logger for CallLogger compatibility
-                       bs.addBean(ThrownStore.class, getThrownStore());
-                       bs.addBean(MethodExecStore.class, getMethodExecStore());
-                       var msgs = getMessages();
-                       bs.addBean(Messages.class, msgs);
-                       bs.add(VarResolver.class, getVarResolver());
-                       bs.add(Config.class, getConfig());
-                       bs.add(ResponseProcessor[].class, 
getResponseProcessors());
-                       bs.addBean(CallLogger.class, getCallLogger());
-                       bs.add(HttpPartSerializer.class, getPartSerializer());
-                       bs.add(HttpPartParser.class, getPartParser());
-                       bs.add(JsonSchemaGenerator.class, 
getJsonSchemaGenerator());
-                       var sf = getStaticFiles();
-                       bs.addBean(StaticFiles.class, sf);
-                       bs.addBean(FileFinder.class, sf);
-                       bs.add(HeaderList.class, getDefaultRequestHeaders(), 
PROP_defaultRequestHeaders);
-                       bs.add(HeaderList.class, getDefaultResponseHeaders(), 
PROP_defaultResponseHeaders);
-                       bs.add(NamedAttributeMap.class, 
getDefaultRequestAttributes(), PROP_defaultRequestAttributes);
-                       bs.addBean(DebugEnablement.class, getDebugEnablement());
-                       // Force-initialize restOperations and restChildren now 
so that any construction failures
-                       // (e.g. bad @RestOp method or invalid child class) 
surface here inside the try-catch and
-                       // propagate as a proper init exception rather than 
lazily on first use.
-                       getRestOperations();
-                       getRestChildren();
-                       bs.addBean(SwaggerProvider.class, getSwaggerProvider());
+                       if (isEagerInit()) {
+                               // Force-fire the framework-bean memoizers in 
dependency-friendly order so their @Rest()
+                               // annotation walks (e.g. 
`@Rest(partParser=…)`, `@Rest(partSerializer=…)`, `@Rest(encoders=…)`,
+                               // etc.) execute eagerly inside the try-catch.  
These walks MUTATE the cached creators that
+                               // downstream RestOpContext memoizers later 
copy from, so they must run before
+                               // getRestOperations() builds the per-op 
contexts.  We do NOT re-add results to the bean
+                               // store — the default suppliers registered 
earlier already cover lookups.
+                               initializeFrameworkBeansForRestOps();
+
+                               // Force-initialize restOperations and 
restChildren now so that any construction failures
+                               // (e.g. bad @RestOp method or invalid child 
class) surface here inside the try-catch.
+                               getRestOperations();
+                               getRestChildren();
+                       }
 
                        // produces/consumes are resolved lazily via the 
produces/consumes memoizers below
                        // (April 2026 refactor, 2026-04-19) — they walk the 
@Rest(produces=...) / @Rest(consumes=...)
@@ -1552,6 +1540,13 @@ public class RestContext extends Context {
        private final Memoizer<Boolean> renderResponseStackTraces = memoizer(() 
->
                
mergeReplacedBooleanAttribute(PROPERTY_renderResponseStackTraces, 
env("RestContext.renderResponseStackTraces", false)));
 
+       /**
+        * Whether framework memoizers and operation/child contexts should be 
force-initialized during constructor execution;
+        * resolved from {@code @Rest(eagerInit)}.
+        */
+       private final Memoizer<Boolean> eagerInit = memoizer(() ->
+               mergeReplacedBooleanAttribute(PROPERTY_eagerInit, 
env("RestContext.eagerInit", false)));
+
        /**
         * The request header used for client-version matching; resolved from 
{@code @Rest(clientVersionHeader)},
         * default {@code "Client-Version"}.
@@ -1919,7 +1914,7 @@ public class RestContext extends Context {
         *
         * @return The bean store associated with this context.
         */
-       public BeanContext getBeanContext() { return beanContext.get(); }
+       public BeanContext getBeanContext() { return 
beanStore.getBean(BeanContext.class).orElse(null); }
 
        BeanContext.Builder         getBeanContextBuilder()          { return 
beanContextBuilder.get(); }
        EncoderSet.Builder          getEncodersBuilder()             { return 
encodersBuilder.get(); }
@@ -1966,7 +1961,7 @@ public class RestContext extends Context {
         *      The call logger to use for this resource.
         *      <br>Never <jk>null</jk>.
         */
-       public CallLogger getCallLogger() { return callLogger.get(); }
+       public CallLogger getCallLogger() { return 
beanStore.getBean(CallLogger.class).orElse(null); }
 
        /**
         * Returns the name of the client version header name used by this 
resource.
@@ -1991,7 +1986,7 @@ public class RestContext extends Context {
         *      The resolving config file associated with this servlet.
         *      <br>Never <jk>null</jk>.
         */
-       public Config getConfig() { return config.get(); }
+       public Config getConfig() { return 
beanStore.getBean(Config.class).orElse(null); }
 
        /**
         * Returns the explicit list of supported content types for this 
resource.
@@ -2013,7 +2008,7 @@ public class RestContext extends Context {
         *
         * @return The debug enablement bean for this context.
         */
-       public DebugEnablement getDebugEnablement() { return 
debugEnablement.get(); }
+       public DebugEnablement getDebugEnablement() { return 
beanStore.getBean(DebugEnablement.class).orElse(null); }
 
        /**
         * Returns the default request attributes for this resource.
@@ -2026,7 +2021,7 @@ public class RestContext extends Context {
         *      The default request headers for this resource in an 
unmodifiable list.
         *      <br>Never <jk>null</jk>.
         */
-       public NamedAttributeMap getDefaultRequestAttributes() { return 
defaultRequestAttributes.get(); }
+       public NamedAttributeMap getDefaultRequestAttributes() { return 
beanStore.getBean(NamedAttributeMap.class, 
PROP_defaultRequestAttributes).orElse(null); }
 
        /**
         * Returns the default request headers for this resource.
@@ -2039,7 +2034,7 @@ public class RestContext extends Context {
         *      The default request headers for this resource in an 
unmodifiable list.
         *      <br>Never <jk>null</jk>.
         */
-       public HeaderList getDefaultRequestHeaders() { return 
defaultRequestHeaders.get(); }
+       public HeaderList getDefaultRequestHeaders() { return 
beanStore.getBean(HeaderList.class, PROP_defaultRequestHeaders).orElse(null); }
 
        /**
         * Returns the default response headers for this resource.
@@ -2052,14 +2047,14 @@ public class RestContext extends Context {
         *      The default response headers for this resource in an 
unmodifiable list.
         *      <br>Never <jk>null</jk>.
         */
-       public HeaderList getDefaultResponseHeaders() { return 
defaultResponseHeaders.get(); }
+       public HeaderList getDefaultResponseHeaders() { return 
beanStore.getBean(HeaderList.class, PROP_defaultResponseHeaders).orElse(null); }
 
        /**
         * Returns the encoders associated with this context.
         *
         * @return The encoders associated with this context.
         */
-       public EncoderSet getEncoders() { return encoders.get(); }
+       public EncoderSet getEncoders() { return 
beanStore.getBean(EncoderSet.class).orElse(null); }
 
        /**
         * Returns the path for this resource as defined by the {@link 
Rest#path() @Rest(path)} annotation or
@@ -2083,7 +2078,7 @@ public class RestContext extends Context {
         *      The HTTP-part serializer associated with this resource.
         *      <br>Never <jk>null</jk>.
         */
-       public JsonSchemaGenerator getJsonSchemaGenerator() { return 
jsonSchemaGenerator.get(); }
+       public JsonSchemaGenerator getJsonSchemaGenerator() { return 
beanStore.getBean(JsonSchemaGenerator.class).orElse(null); }
 
        /**
         * Returns the HTTP call for the current request.
@@ -2105,7 +2100,7 @@ public class RestContext extends Context {
         *      The logger for this resource.
         *      <br>Never <jk>null</jk>.
         */
-       public Logger getLogger() { return logger.get(); }
+       public Logger getLogger() { return 
beanStore.getBean(Logger.class).orElse(null); }
 
        /**
         * Returns the resource bundle used by this resource.
@@ -2114,21 +2109,21 @@ public class RestContext extends Context {
         *      The resource bundle for this resource.
         *      <br>Never <jk>null</jk>.
         */
-       public Messages getMessages() { return messages.get(); }
+       public Messages getMessages() { return 
beanStore.getBean(Messages.class).orElse(null); }
 
        /**
         * Returns the timing statistics on all method executions on this class.
         *
         * @return The timing statistics on all method executions on this class.
         */
-       public MethodExecStore getMethodExecStore() { return 
methodExecStore.get(); }
+       public MethodExecStore getMethodExecStore() { return 
beanStore.getBean(MethodExecStore.class).orElse(null); }
 
        /**
         * Returns the parsers associated with this context.
         *
         * @return The parsers associated with this context.
         */
-       public ParserSet getParsers() { return parsers.get(); }
+       public ParserSet getParsers() { return 
beanStore.getBean(ParserSet.class).orElse(null); }
 
        /**
         * Returns the HTTP-part parser associated with this resource.
@@ -2137,7 +2132,7 @@ public class RestContext extends Context {
         *      The HTTP-part parser associated with this resource.
         *      <br>Never <jk>null</jk>.
         */
-       public HttpPartParser getPartParser() { return partParser.get(); }
+       public HttpPartParser getPartParser() { return 
beanStore.getBean(HttpPartParser.class).orElse(null); }
 
        /**
         * Returns the HTTP-part serializer associated with this resource.
@@ -2146,7 +2141,7 @@ public class RestContext extends Context {
         *      The HTTP-part serializer associated with this resource.
         *      <br>Never <jk>null</jk>.
         */
-       public HttpPartSerializer getPartSerializer() { return 
partSerializer.get(); }
+       public HttpPartSerializer getPartSerializer() { return 
beanStore.getBean(HttpPartSerializer.class).orElse(null); }
 
        /**
         * Returns the path for this resource as defined by the {@link 
Rest#path() @Rest(path)} annotation or
@@ -2221,7 +2216,7 @@ public class RestContext extends Context {
         *      The response processors for this resource.
         *      <br>Never <jk>null</jk>.
         */
-       public ResponseProcessor[] getResponseProcessors() { return 
responseProcessors.get(); }
+       public ResponseProcessor[] getResponseProcessors() { return 
beanStore.getBean(ResponseProcessor[].class).orElse(null); }
 
        /**
         * Returns the {@link RestOpArg} classes registered on this resource.
@@ -2248,7 +2243,7 @@ public class RestContext extends Context {
         *      An unmodifiable map of child resources.
         *      Keys are the {@link Rest#path() @Rest(path)} annotation defined 
on the child resource.
         */
-       public RestChildren getRestChildren() { return restChildren.get(); }
+       public RestChildren getRestChildren() { return 
beanStore.getBean(RestChildren.class).orElse(null); }
 
        /**
         * Returns the REST Java methods defined in this resource.
@@ -2259,7 +2254,7 @@ public class RestContext extends Context {
         * @return
         *      An unmodifiable map of Java method names to call method objects.
         */
-       public RestOperations getRestOperations() { return 
restOperations.get(); }
+       public RestOperations getRestOperations() { return 
beanStore.getBean(RestOperations.class).orElse(null); }
 
        /**
         * Returns the bootstrap bean store for this context.
@@ -2277,7 +2272,7 @@ public class RestContext extends Context {
         *
         * @return The serializers associated with this context.
         */
-       public SerializerSet getSerializers() { return serializers.get(); }
+       public SerializerSet getSerializers() { return 
beanStore.getBean(SerializerSet.class).orElse(null); }
 
        /**
         * Returns the servlet init parameter returned by {@link 
ServletConfig#getInitParameter(String)}.
@@ -2296,7 +2291,7 @@ public class RestContext extends Context {
         *      The static files for this resource.
         *      <br>Never <jk>null</jk>.
         */
-       public StaticFiles getStaticFiles() { return staticFiles.get(); }
+       public StaticFiles getStaticFiles() { return 
beanStore.getBean(StaticFiles.class).orElse(null); }
 
        /**
         * Gives access to the internal statistics on this context.
@@ -2336,7 +2331,7 @@ public class RestContext extends Context {
         *      The information provider for this resource.
         *      <br>Never <jk>null</jk>.
         */
-       public SwaggerProvider getSwaggerProvider() { return 
swaggerProvider.get(); }
+       public SwaggerProvider getSwaggerProvider() { return 
beanStore.getBean(SwaggerProvider.class).orElse(null); }
 
        /**
         * Returns the stack trace database associated with this context.
@@ -2345,7 +2340,7 @@ public class RestContext extends Context {
         *      The stack trace database for this resource.
         *      <br>Never <jk>null</jk>.
         */
-       public ThrownStore getThrownStore() { return thrownStore.get(); }
+       public ThrownStore getThrownStore() { return 
beanStore.getBean(ThrownStore.class).orElse(null); }
 
        /**
         * Returns the authority path of the resource.
@@ -2454,7 +2449,7 @@ public class RestContext extends Context {
         *
         * @return The var resolver in use by this resource.
         */
-       public VarResolver getVarResolver() { return varResolver.get(); }
+       public VarResolver getVarResolver() { return 
beanStore.getBean(VarResolver.class).orElse(null); }
 
        /**
         * Returns the bootstrap (pre-runtime) variable resolver used during 
context construction.
@@ -2487,6 +2482,17 @@ public class RestContext extends Context {
         */
        public boolean isRenderResponseStackTraces() { return 
renderResponseStackTraces.get(); }
 
+       /**
+        * Returns whether framework beans and operation/child contexts are 
eagerly initialized at construction time.
+        *
+        * <h5 class='section'>See Also:</h5><ul>
+        *      <li class='ja'>{@link Rest#eagerInit()}
+        * </ul>
+        *
+        * @return <jk>true</jk> if eager initialization is enabled.
+        */
+       public boolean isEagerInit() { return eagerInit.get(); }
+
        /**
         * Called during servlet initialization to invoke all {@link 
RestPostInit} child-last methods.
         *
@@ -2541,6 +2547,34 @@ public class RestContext extends Context {
                return getDebugEnablement().isDebug(this, call.getRequest());
        }
 
+       /**
+        * Ensures framework bean memoizers that can mutate creator state from 
{@code @Rest(...)} annotation walks
+        * have run before {@link RestOpContext} instances are built.
+        */
+       private void initializeFrameworkBeansForRestOps() {
+               getBeanContext();
+               getEncoders();
+               getSerializers();
+               getParsers();
+               getLogger();
+               getThrownStore();
+               getMethodExecStore();
+               getMessages();
+               getVarResolver();
+               getConfig();
+               getResponseProcessors();
+               getCallLogger();
+               getPartSerializer();
+               getPartParser();
+               getJsonSchemaGenerator();
+               getStaticFiles();
+               getDefaultRequestHeaders();
+               getDefaultResponseHeaders();
+               getDefaultRequestAttributes();
+               getDebugEnablement();
+               getSwaggerProvider();
+       }
+
        private static Set<String> newCaseInsensitiveSet(String value) {
                var s = new TreeSet<>(String.CASE_INSENSITIVE_ORDER) {
                        private static final long serialVersionUID = 1L;
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServerConstants.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServerConstants.java
index 7d82be18c4..adb7fa4875 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServerConstants.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServerConstants.java
@@ -63,6 +63,9 @@ public final class RestServerConstants {
        /** The {@code "renderResponseStackTraces"} annotation attribute name — 
used in {@code noInherit} matching. */
        public static final String PROPERTY_renderResponseStackTraces = 
"renderResponseStackTraces";
 
+       /** The {@code "eagerInit"} annotation attribute name — used in {@code 
noInherit} matching. */
+       public static final String PROPERTY_eagerInit = "eagerInit";
+
        /** The {@code "clientVersionHeader"} annotation attribute name — used 
in {@code noInherit} matching. */
        public static final String PROPERTY_clientVersionHeader = 
"clientVersionHeader";
 
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java
index 51ecdbfe5d..000482d33a 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java
@@ -242,6 +242,31 @@ public @interface Rest {
         */
        String config() default "";
 
+       /**
+        * Eagerly initializes framework-managed memoizers during {@link 
RestContext} construction.
+        *
+        * <p>
+        * When enabled, framework bean memoizers and operation/child-context 
memoizers are force-fired inside the
+        * constructor try/catch so startup-time configuration errors fail fast.
+        *
+        * <p>
+        * This setting is disabled by default.
+        *
+        * <ul class='values'>
+        *      <li><js>"true"</js> - Force eager initialization during context 
construction.
+        *      <li><js>"false"</js> - Keep initialization lazy until first use 
(default).
+        * </ul>
+        *
+        * <h5 class='section'>Notes:</h5><ul>
+        *      <li class='note'>
+        *              Supports <a class="doclink" 
href="https://juneau.apache.org/docs/topics/RestServerSvlVariables";>SVL 
Variables</a>
+        *              (e.g. <js>"$L{my.localized.variable}"</js>).
+        * </ul>
+        *
+        * @return The annotation value.
+        */
+       String eagerInit() default "";
+
        /**
         * Supported content media types.
         *
@@ -304,7 +329,7 @@ public @interface Rest {
         * <p>
         * Accepted values include {@code "allowedParserOptions"}, {@code 
"allowedSerializerOptions"},
         * {@code "allowedHeaderParams"}, {@code "allowedMethodHeaders"}, 
{@code "allowedMethodParams"},
-        * {@code "disableContentParam"}, {@code "renderResponseStackTraces"}, 
{@code "clientVersionHeader"},
+        * {@code "disableContentParam"}, {@code "renderResponseStackTraces"}, 
{@code "eagerInit"}, {@code "clientVersionHeader"},
         * {@code "uriAuthority"}, {@code "uriContext"}, {@code 
"uriRelativity"}, and {@code "uriResolution"}.
         * Each entry is SVL-resolved then comma-split. Prevents the named 
property from inheriting values from
         * parent {@code @Rest} annotations (router hierarchy). The {@code 
noInherit} attribute itself is never inherited.
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestAnnotation.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestAnnotation.java
index bc91305b03..a9f287fec3 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestAnnotation.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestAnnotation.java
@@ -83,6 +83,7 @@ public class RestAnnotation {
                private String allowedMethodParams = "";
                private String clientVersionHeader = "";
                private String config = "";
+               private String eagerInit = "";
                private String debug = "";
                private String debugDefault = "";
                private String debugOn = "";
@@ -229,6 +230,17 @@ public class RestAnnotation {
                        return this;
                }
 
+               /**
+                * Sets the {@link Rest#eagerInit()} property on this 
annotation.
+                *
+                * @param value The new value for this property.
+                * @return This object.
+                */
+               public Builder eagerInit(String value) {
+                       eagerInit = value;
+                       return this;
+               }
+
                /**
                 * Sets the {@link Rest#consumes()} property on this annotation.
                 *
@@ -705,6 +717,7 @@ public class RestAnnotation {
                private final String allowedMethodParams;
                private final String clientVersionHeader;
                private final String config;
+               private final String eagerInit;
                private final String debug;
                private final String debugDefault;
                private final String debugOn;
@@ -748,6 +761,7 @@ public class RestAnnotation {
                        children = copyOf(b.children);
                        clientVersionHeader = b.clientVersionHeader;
                        config = b.config;
+                       eagerInit = b.eagerInit;
                        allowedParserOptions = copyOf(b.allowedParserOptions);
                        allowedSerializerOptions = 
copyOf(b.allowedSerializerOptions);
                        noInherit = copyOf(b.noInherit);
@@ -833,6 +847,11 @@ public class RestAnnotation {
                        return config;
                }
 
+               @Override /* Overridden from Rest */
+               public String eagerInit() {
+                       return eagerInit;
+               }
+
                @Override /* Overridden from Rest */
                public String[] allowedParserOptions() {
                        return allowedParserOptions;
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestInject.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestInject.java
index a7fa2b4127..485ef91f1c 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestInject.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestInject.java
@@ -137,6 +137,33 @@ import org.apache.juneau.svl.*;
  *             {@link RestInject#methodScope()} annotation can be used to 
apply to method-level only (when applicable).
  * </ul>
  *
+ * <h5 class='section'>Precedence (since 9.5.0):</h5>
+ * <p>
+ *     {@code @RestInject} acts as a <i>programmable default</i>, analogous to 
Spring's
+ *     <c>&#64;ConditionalOnMissingBean</c>.  When a {@link RestContext} 
resolves a framework-managed bean
+ *     (<c>CallLogger</c>, <c>EncoderSet</c>, <c>SerializerSet</c>, 
<c>ParserSet</c>, <c>ThrownStore</c>,
+ *     <c>Config</c>, <c>VarResolver</c>, <c>HttpPartSerializer</c>, 
<c>HttpPartParser</c>, etc.), the lookup
+ *     walks the following tiers in order, returning the first hit:
+ * </p>
+ * <ol>
+ *     <li><b>Overriding-parent bean store</b> — Spring beans (in 
<c>juneau-rest-server-springboot</c> deployments,
+ *             via <c>SpringBeanStore</c>), or any bean reachable through 
{@link 
org.apache.juneau.cp.BasicBeanStore.Builder#overridingParent(org.apache.juneau.cp.BasicBeanStore)
 overridingParent(...)}.</li>
+ *     <li><b>{@code @RestInject} method/field on the resource class</b> — 
registered as a regular bean-store
+ *             entry, beating the framework default.</li>
+ *     <li><b>Memoizer-backed framework default</b> — built into {@link 
RestContext} as a default supplier.</li>
+ * </ol>
+ * <p>
+ *     In other words: a Spring <c>&#64;Bean</c> of type <c>CallLogger</c> 
wins over a {@code @RestInject CallLogger}
+ *     method on the same servlet, which in turn wins over the framework's 
built-in <c>BasicCallLogger</c>.  Non-Spring
+ *     deployments have an empty overriding-parent layer, so the chain 
naturally collapses to
+ *     {@code @RestInject > default}.
+ * </p>
+ * <p>
+ *     Prior to 9.5 the order was {@code @RestInject > Spring > default}.  See 
the 9.5.0 release notes for migration
+ *     guidance if you need to keep that legacy behavior (typically by 
removing the Spring <c>&#64;Bean</c> or marking the
+ *     {@code @RestInject} method's type with a Spring-native override such as 
<c>&#64;Primary</c>).
+ * </p>
+ *
  * <p>
  * Any of the following types can be customized via injection:
  * <table class='w800 styled'>
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/commons/inject/BasicBeanStore_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/commons/inject/BasicBeanStore_Test.java
index a838cd453a..f269dfba8f 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/commons/inject/BasicBeanStore_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/commons/inject/BasicBeanStore_Test.java
@@ -916,5 +916,196 @@ class BasicBeanStore_Test extends TestBase {
                assertNotNull(result);
                assertFalse(result.isEmpty());
        }
+
+       
//====================================================================================================
+       // addDefaultSupplier(...) and overriding-parent precedence
+       
//====================================================================================================
+
+       @Test
+       void r01_addDefaultSupplier_unnamed_fallsBackWhenNoEntry() {
+               var store = new BasicBeanStore2(null);
+               var defaultBean = new TestBean("default");
+               store.addDefaultSupplier(TestBean.class, () -> defaultBean);
+
+               assertTrue(store.getBean(TestBean.class).isPresent());
+               assertSame(defaultBean, store.getBean(TestBean.class).get());
+       }
+
+       @Test
+       void r02_addDefaultSupplier_localEntryBeatsDefault() {
+               var store = new BasicBeanStore2(null);
+               var defaultBean = new TestBean("default");
+               var localBean = new TestBean("local");
+               store.addDefaultSupplier(TestBean.class, () -> defaultBean);
+               store.addBean(TestBean.class, localBean);
+
+               assertSame(localBean, 
store.getBean(TestBean.class).orElseThrow());
+       }
+
+       @Test
+       void r03_addDefaultSupplier_regularParentBeatsDefault() {
+               var parent = new BasicBeanStore2(null);
+               parent.addBean(TestBean.class, new TestBean("parent"));
+
+               var store = new BasicBeanStore2(parent);
+               store.addDefaultSupplier(TestBean.class, () -> new 
TestBean("default"));
+
+               assertEquals("parent", 
store.getBean(TestBean.class).orElseThrow().getName());
+       }
+
+       @Test
+       void r04_addDefaultSupplier_named() {
+               var store = new BasicBeanStore2(null);
+               store.addDefaultSupplier(TestBean.class, () -> new 
TestBean("dn"), "n1");
+
+               assertTrue(store.getBean(TestBean.class, "n1").isPresent());
+               assertEquals("dn", store.getBean(TestBean.class, 
"n1").orElseThrow().getName());
+               assertFalse(store.getBean(TestBean.class).isPresent());
+               assertFalse(store.getBean(TestBean.class, "other").isPresent());
+       }
+
+       @Test
+       void r05_addDefaultSupplier_clearedByClear() {
+               var store = new BasicBeanStore2(null);
+               store.addDefaultSupplier(TestBean.class, () -> new 
TestBean("d"));
+               assertTrue(store.getBean(TestBean.class).isPresent());
+
+               store.clear();
+               assertFalse(store.getBean(TestBean.class).isPresent());
+       }
+
+       @Test
+       void s01_overridingParent_beatsLocalEntry() {
+               var spring = new BasicBeanStore2(null);
+               spring.addBean(TestBean.class, new TestBean("spring"));
+
+               var store = new BasicBeanStore2(null, spring);
+               store.addBean(TestBean.class, new TestBean("local"));
+
+               assertEquals("spring", 
store.getBean(TestBean.class).orElseThrow().getName());
+       }
+
+       @Test
+       void s02_overridingParent_beatsDefault() {
+               var spring = new BasicBeanStore2(null);
+               spring.addBean(TestBean.class, new TestBean("spring"));
+
+               var store = new BasicBeanStore2(null, spring);
+               store.addDefaultSupplier(TestBean.class, () -> new 
TestBean("default"));
+
+               assertEquals("spring", 
store.getBean(TestBean.class).orElseThrow().getName());
+       }
+
+       @Test
+       void s03_overridingParent_localEntryBeatsRegularParent() {
+               var regularParent = new BasicBeanStore2(null);
+               regularParent.addBean(TestBean.class, new 
TestBean("regular-parent"));
+
+               var spring = new BasicBeanStore2(null);
+               // no spring binding for TestBean
+
+               var store = new BasicBeanStore2(regularParent, spring);
+               store.addBean(TestBean.class, new TestBean("local"));
+
+               assertEquals("local", 
store.getBean(TestBean.class).orElseThrow().getName());
+       }
+
+       @Test
+       void s04_overridingParent_namedLookup() {
+               var spring = new BasicBeanStore2(null);
+               spring.addBean(TestBean.class, new TestBean("spring"), 
"primary");
+
+               var store = new BasicBeanStore2(null, spring);
+               store.addBean(TestBean.class, new TestBean("local"), "primary");
+
+               assertEquals("spring", store.getBean(TestBean.class, 
"primary").orElseThrow().getName());
+               assertFalse(store.getBean(TestBean.class, "other").isPresent());
+       }
+
+       @Test
+       void s05_fullPrecedenceOrder() {
+               // Set up: overriding parent (Spring), regular parent, local 
entry, local default
+               var regularParent = new BasicBeanStore2(null);
+               regularParent.addBean(TestBean.class, new 
TestBean("regular-parent"));
+
+               var spring = new BasicBeanStore2(null);
+               spring.addBean(TestBean.class, new TestBean("spring"));
+
+               var store = new BasicBeanStore2(regularParent, spring);
+               store.addBean(TestBean.class, new TestBean("local"));
+               store.addDefaultSupplier(TestBean.class, () -> new 
TestBean("default"));
+
+               // Spring (overriding) wins.
+               assertEquals("spring", 
store.getBean(TestBean.class).orElseThrow().getName());
+       }
+
+       @Test
+       void s06_precedenceOrder_noOverriding_noEntry() {
+               // Only regular parent and default — regular parent wins over 
default.
+               var regularParent = new BasicBeanStore2(null);
+               regularParent.addBean(TestBean.class, new 
TestBean("regular-parent"));
+
+               var store = new BasicBeanStore2(regularParent);
+               store.addDefaultSupplier(TestBean.class, () -> new 
TestBean("default"));
+
+               assertEquals("regular-parent", 
store.getBean(TestBean.class).orElseThrow().getName());
+       }
+
+       @Test
+       void s07_precedenceOrder_noOverridingMatch_fallsThroughToLocal() {
+               // Spring has no match, local entry should be returned.
+               var spring = new BasicBeanStore2(null);
+               // no binding for TestBean
+
+               var store = new BasicBeanStore2(null, spring);
+               store.addBean(TestBean.class, new TestBean("local"));
+
+               assertEquals("local", 
store.getBean(TestBean.class).orElseThrow().getName());
+       }
+
+       @Test
+       void s08_overridingParent_getBeanSupplier() {
+               var spring = new BasicBeanStore2(null);
+               spring.addBean(TestBean.class, new TestBean("spring"));
+
+               var store = new BasicBeanStore2(null, spring);
+               store.addBean(TestBean.class, new TestBean("local"));
+
+               var supplier = store.getBeanSupplier(TestBean.class);
+               assertTrue(supplier.isPresent());
+               assertEquals("spring", supplier.get().get().getName());
+       }
+
+       @Test
+       void s09_overridingParent_hasBean() {
+               var spring = new BasicBeanStore2(null);
+               spring.addBean(TestBean.class, new TestBean("spring"));
+
+               var store = new BasicBeanStore2(null, spring);
+               assertTrue(store.hasBean(TestBean.class));
+               assertFalse(store.hasBean(AnotherBean.class));
+       }
+
+       @Test
+       void s10_overridingParent_getBeansOfType_overridesLocalNamed() {
+               var spring = new BasicBeanStore2(null);
+               spring.addBean(TestBean.class, new TestBean("spring-a"), "a");
+               spring.addBean(TestBean.class, new TestBean("spring-b"), "b");
+
+               var store = new BasicBeanStore2(null, spring);
+               store.addBean(TestBean.class, new TestBean("local-a"), "a");
+               store.addBean(TestBean.class, new TestBean("local-c"), "c");
+               store.addDefaultSupplier(TestBean.class, () -> new 
TestBean("default-d"), "d");
+
+               var beans = store.getBeansOfType(TestBean.class);
+               // "a" is in both local and overriding parent — overriding wins.
+               assertEquals("spring-a", beans.get("a").getName());
+               // "b" only in overriding parent.
+               assertEquals("spring-b", beans.get("b").getName());
+               // "c" only local.
+               assertEquals("local-c", beans.get("c").getName());
+               // "d" only in defaults.
+               assertEquals("default-d", beans.get("d").getName());
+       }
 }
 
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/cp/BeanStore_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/cp/BeanStore_Test.java
index 239b1ec617..f0706203e9 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/cp/BeanStore_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/cp/BeanStore_Test.java
@@ -723,6 +723,95 @@ class BeanStore_Test extends TestBase {
                assertThrowsWithMessage(ExecutableException.class, "Could not 
instantiate class "+D17.class.getName()+": Protected constructor found but 
could not find prerequisites: Builder or Builder,Integer or Integer.", 
()->BeanCreator.<D17>of(D17.class, bs).builder(Boolean.class, true).run());
        }
 
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Default suppliers and overriding-parent precedence
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       @Test void e01_addDefaultSupplier_unnamed_fallsBackWhenNoEntry() {
+               var bs = BasicBeanStore.create().build();
+               bs.addDefaultSupplier(String.class, () -> "default");
+               assertString("default", bs.getBean(String.class).orElseThrow());
+       }
+
+       @Test void e02_addDefaultSupplier_localEntryBeatsDefault() {
+               var bs = BasicBeanStore.create().build();
+               bs.addDefaultSupplier(String.class, () -> "default");
+               bs.addBean(String.class, "local");
+               assertString("local", bs.getBean(String.class).orElseThrow());
+       }
+
+       @Test void e03_addDefaultSupplier_regularParentBeatsDefault() {
+               var parent = 
BasicBeanStore.create().build().addBean(String.class, "parent");
+               var bs = BasicBeanStore.create().parent(parent).build();
+               bs.addDefaultSupplier(String.class, () -> "default");
+               assertString("parent", bs.getBean(String.class).orElseThrow());
+       }
+
+       @Test void e04_addDefaultSupplier_named() {
+               var bs = BasicBeanStore.create().build();
+               bs.addDefaultSupplier(String.class, () -> "named-default", 
"n1");
+               assertString("named-default", bs.getBean(String.class, 
"n1").orElseThrow());
+               assertFalse(bs.getBean(String.class).isPresent());
+               assertFalse(bs.getBean(String.class, "other").isPresent());
+       }
+
+       @Test void e05_addDefaultSupplier_clearedByClear() {
+               var bs = BasicBeanStore.create().build();
+               bs.addDefaultSupplier(String.class, () -> "default");
+               assertTrue(bs.getBean(String.class).isPresent());
+               bs.clear();
+               assertFalse(bs.getBean(String.class).isPresent());
+       }
+
+       @Test void e06_overridingParent_beatsLocalEntry() {
+               var spring = 
BasicBeanStore.create().build().addBean(String.class, "spring");
+               var bs = 
BasicBeanStore.create().overridingParent(spring).build();
+               bs.addBean(String.class, "local");
+               assertString("spring", bs.getBean(String.class).orElseThrow());
+       }
+
+       @Test void e07_overridingParent_beatsDefault() {
+               var spring = 
BasicBeanStore.create().build().addBean(String.class, "spring");
+               var bs = 
BasicBeanStore.create().overridingParent(spring).build();
+               bs.addDefaultSupplier(String.class, () -> "default");
+               assertString("spring", bs.getBean(String.class).orElseThrow());
+       }
+
+       @Test void e08_overridingParent_localEntryBeatsRegularParent() {
+               var regularParent = 
BasicBeanStore.create().build().addBean(String.class, "regular-parent");
+               var spring = BasicBeanStore.create().build();
+               var bs = 
BasicBeanStore.create().parent(regularParent).overridingParent(spring).build();
+               bs.addBean(String.class, "local");
+               assertString("local", bs.getBean(String.class).orElseThrow());
+       }
+
+       @Test void e09_overridingParent_namedLookup() {
+               var spring = 
BasicBeanStore.create().build().addBean(String.class, "spring", "primary");
+               var bs = 
BasicBeanStore.create().overridingParent(spring).build();
+               bs.addBean(String.class, "local", "primary");
+               assertString("spring", bs.getBean(String.class, 
"primary").orElseThrow());
+       }
+
+       @Test void e10_fullPrecedenceOrder() {
+               var regularParent = 
BasicBeanStore.create().build().addBean(String.class, "regular-parent");
+               var spring = 
BasicBeanStore.create().build().addBean(String.class, "spring");
+               var bs = 
BasicBeanStore.create().parent(regularParent).overridingParent(spring).build();
+               bs.addBean(String.class, "local");
+               bs.addDefaultSupplier(String.class, () -> "default");
+               assertString("spring", bs.getBean(String.class).orElseThrow());
+       }
+
+       @Test void e11_hasBean_includesAllTiers() {
+               var spring = 
BasicBeanStore.create().build().addBean(Integer.class, 1);
+               var bs = 
BasicBeanStore.create().overridingParent(spring).build();
+               bs.addBean(String.class, "local");
+               bs.addDefaultSupplier(Long.class, () -> 99L);
+               assertTrue(bs.hasBean(Integer.class));    // overriding parent
+               assertTrue(bs.hasBean(String.class));     // local entry
+               assertTrue(bs.hasBean(Long.class));       // default
+               assertFalse(bs.hasBean(Double.class));    // nowhere
+       }
+
        
//-----------------------------------------------------------------------------------------------------------------
        // Helpers
        
//-----------------------------------------------------------------------------------------------------------------
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/rest/RestContext_Precedence_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/rest/RestContext_Precedence_Test.java
new file mode 100644
index 0000000000..5f371d30af
--- /dev/null
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/rest/RestContext_Precedence_Test.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.juneau.rest;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.cp.*;
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.rest.logger.*;
+import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.stats.*;
+import org.junit.jupiter.api.*;
+
+/**
+ * Validates the 9.5 precedence model for framework-managed beans on a {@link 
RestContext}:
+ * <ol>
+ *     <li>Beans inherited from an "overriding parent" bean store (e.g. 
Spring) win.
+ *     <li>{@code @RestInject} factory methods on the resource win over 
defaults.
+ *     <li>Memoizer-backed framework defaults are the last-resort fallback.
+ * </ol>
+ *
+ * <p>
+ * Spring is simulated here by wiring a {@link BasicBeanStore} as the {@code 
overridingParent} of the
+ * resource's bean store via {@link Rest#beanStore()} on a custom {@link 
BasicBeanStore} subclass.  This
+ * avoids pulling in spring-boot at test time but exercises the same code path 
that
+ * {@code SpringRestServlet.createBeanStore(...)} drives at runtime.
+ */
+class RestContext_Precedence_Test extends TestBase {
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Marker beans
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       private static final CallLogger SPRING_LOGGER = 
BasicCallLogger.create(BasicBeanStore.INSTANCE).build();
+       private static final CallLogger RESTINJECT_LOGGER = 
BasicCallLogger.create(BasicBeanStore.INSTANCE).build();
+       private static final ThrownStore RESTINJECT_THROWN_STORE = 
ThrownStore.create().build();
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Spring-substitute bean store (acts as the overriding parent layer)
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       /** A bean store seeded with a "Spring" {@link CallLogger} via the 
overriding-parent mechanism. */
+       public static class SpringLikeBeanStore extends BasicBeanStore {
+               protected SpringLikeBeanStore(Builder builder) {
+                       
super(builder.overridingParent(BasicBeanStore.create().build().addBean(CallLogger.class,
 SPRING_LOGGER)));
+               }
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // 1. @RestInject beats default (no Spring layer present)
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       @Rest
+       public static class A_RestInjectOnly {
+               @RestInject static CallLogger callLoggerCapture;
+               @RestInject public CallLogger callLogger() { return 
RESTINJECT_LOGGER; }
+       }
+
+       @Test
+       void a01_restInject_beatsDefault() {
+               MockRestClient.buildLax(A_RestInjectOnly.class);
+               assertSame(RESTINJECT_LOGGER, 
A_RestInjectOnly.callLoggerCapture);
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // 2. Spring (overriding parent) beats @RestInject
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       @Rest(beanStore=SpringLikeBeanStore.class)
+       public static class B_SpringWins {
+               @RestInject static CallLogger callLoggerCapture;
+               @RestInject public CallLogger callLogger() { return 
RESTINJECT_LOGGER; }
+       }
+
+       @Test
+       void b01_spring_beatsRestInject() {
+               MockRestClient.buildLax(B_SpringWins.class);
+               assertSame(SPRING_LOGGER, B_SpringWins.callLoggerCapture, 
"Spring (overriding parent) should win over @RestInject method");
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // 3. Spring (overriding parent) beats default (no @RestInject method)
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       @Rest(beanStore=SpringLikeBeanStore.class)
+       public static class C_SpringOnly {
+               @RestInject static CallLogger callLoggerCapture;
+       }
+
+       @Test
+       void c01_spring_beatsDefault() {
+               MockRestClient.buildLax(C_SpringOnly.class);
+               assertSame(SPRING_LOGGER, C_SpringOnly.callLoggerCapture);
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // 4. With NO overriding-parent binding for the type, @RestInject still 
wins over the default
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       @Rest(beanStore=SpringLikeBeanStore.class)
+       public static class D_PartialSpring {
+               @RestInject static CallLogger callLoggerCapture;
+               @RestInject static ThrownStore thrownStoreCapture;
+               @RestInject public ThrownStore thrownStore() { return 
RESTINJECT_THROWN_STORE; }
+       }
+
+       @Test
+       void d01_partialSpring_restInjectStillBeatsDefaultForUnboundType() {
+               MockRestClient.buildLax(D_PartialSpring.class);
+               assertSame(SPRING_LOGGER, D_PartialSpring.callLoggerCapture);   
               // Spring binding wins
+               assertSame(RESTINJECT_THROWN_STORE, 
D_PartialSpring.thrownStoreCapture);       // @RestInject wins (Spring has no 
binding)
+       }
+}


Reply via email to