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 3f9ad97f0a refactor: rename BeanCreator2 to BeanInstantiator, add 
BeanStore.createBeanFromMethod() API
3f9ad97f0a is described below

commit 3f9ad97f0a1aaffe0df31065081445ad0f7318a5
Author: James Bognar <[email protected]>
AuthorDate: Thu May 7 15:10:14 2026 -0400

    refactor: rename BeanCreator2 to BeanInstantiator, add 
BeanStore.createBeanFromMethod() API
---
 .../juneau/commons/inject/BasicBeanStore2.java     | 40 +++++++++
 .../commons/inject/BeanCreationException.java      | 62 ++++++++++++++
 .../{BeanCreator2.java => BeanInstantiator.java}   | 92 ++++++++++-----------
 .../apache/juneau/commons/inject/BeanStore.java    | 76 ++++++++++++++++-
 .../juneau/commons/inject/CreatableBeanStore.java  | 50 +++++------
 .../java/org/apache/juneau/cp/BeanCreator.java     |  5 +-
 ...eator2_Test.java => BeanInstantiator_Test.java} | 96 +++++++++++-----------
 todo/TODO-14-move-svl-to-commons.md                |  2 +-
 todo/TODO-15-replace-basicbeanstore-with-v2.md     | 70 +++++++++++-----
 todo/TODO-23-commons-inject-framework-roadmap.md   |  2 +-
 todo/TODO-24-jsr330-and-spring-lite-support.md     |  4 +-
 11 files changed, 353 insertions(+), 146 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 1c5fed3531..b82e548e39 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
@@ -16,6 +16,7 @@
  */
 package org.apache.juneau.commons.inject;
 
+import static org.apache.juneau.commons.reflect.ReflectionUtils.*;
 import static org.apache.juneau.commons.utils.CollectionUtils.*;
 import static org.apache.juneau.commons.utils.Utils.*;
 
@@ -24,6 +25,7 @@ import java.util.concurrent.*;
 import java.util.function.*;
 
 import org.apache.juneau.commons.collections.*;
+import org.apache.juneau.commons.reflect.*;
 
 /**
  * Basic implementation of {@link WritableBeanStore}.
@@ -428,6 +430,44 @@ public class BasicBeanStore2 implements WritableBeanStore {
                return resolve(beanType, name);
        }
 
+       /**
+        * Finds and invokes a factory method that produces a bean of type 
<c>beanType</c>.
+        *
+        * <p>
+        * If <c>onClassOrObject</c> is a {@link Class}, only static methods 
are eligible.
+        * Otherwise, both instance and static methods on the object's class 
are eligible.
+        * A <jk>null</jk> <c>filter</c> accepts any qualifying method.
+        *
+        * @param <T> The bean type.
+        * @param beanType The type of bean to create.  Must not be 
<jk>null</jk>.
+        * @param onClassOrObject The object instance or {@link Class} whose 
public methods are searched.
+        *      Must not be <jk>null</jk>.
+        * @param filter Optional predicate restricting which methods are 
eligible.  Can be <jk>null</jk>.
+        * @param extraBeans Optional bean instances visible to parameter 
resolution for this call only.
+        * @return The created bean wrapped in an {@link Optional}, or {@link 
Optional#empty()} if no matching
+        *      factory method was found.
+        * @throws BeanCreationException If a matching method was found but 
threw an exception during invocation.
+        */
+       @Override
+       public <T> Optional<T> createBeanFromMethod(Class<T> beanType, Object 
onClassOrObject, Predicate<MethodInfo> filter, Object... extraBeans) {
+               Object resource = onClassOrObject instanceof Class ? null : 
onClassOrObject;
+               Class<?> resourceClass = onClassOrObject instanceof Class<?> c 
? c : onClassOrObject.getClass();
+               return info(resourceClass)
+                       .getPublicMethod(m ->
+                               m.isNotDeprecated()
+                               && m.hasReturnType(beanType)
+                               && (filter == null || filter.test(m))
+                               && (m.isStatic() || nn(resource))
+                               && m.canResolveAllParameters(this, extraBeans))
+                       .map(m -> {
+                               try {
+                                       return m.<T>inject(this, resource, 
extraBeans);
+                               } catch (Exception e) {
+                                       throw new BeanCreationException("Failed 
to create bean of type [" + beanType.getSimpleName() + "] via method [" + 
m.getName() + "]", e);
+                               }
+                       });
+       }
+
        @Override /* Overridden from Object */
        public String toString() {
                return r(properties());
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanCreationException.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanCreationException.java
new file mode 100644
index 0000000000..d1e3d31bd4
--- /dev/null
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanCreationException.java
@@ -0,0 +1,62 @@
+/*
+ * 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.commons.inject;
+
+/**
+ * Unchecked exception thrown when a bean creator method is found but its 
invocation fails.
+ *
+ * <p>
+ * Thrown by {@link BeanStore#createBeanFromMethod(Class, Object, 
java.util.function.Predicate, Object[])} when a matching
+ * factory method is located but throws an exception during invocation.  
Wrapping in an unchecked type makes
+ * the exception compatible with {@link java.util.Optional} chaining and 
lambda contexts.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ *     <li class='jm'>{@link BeanStore#createBeanFromMethod(Class, Object, 
java.util.function.Predicate, Object[])}
+ * </ul>
+ */
+public class BeanCreationException extends RuntimeException {
+
+       private static final long serialVersionUID = 1L;
+
+       /**
+        * Constructor.
+        *
+        * @param message The detail message.
+        */
+       public BeanCreationException(String message) {
+               super(message);
+       }
+
+       /**
+        * Constructor.
+        *
+        * @param message The detail message.
+        * @param cause The cause.
+        */
+       public BeanCreationException(String message, Throwable cause) {
+               super(message, cause);
+       }
+
+       /**
+        * Constructor.
+        *
+        * @param cause The cause.
+        */
+       public BeanCreationException(Throwable cause) {
+               super(cause);
+       }
+}
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanCreator2.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanInstantiator.java
similarity index 95%
rename from 
juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanCreator2.java
rename to 
juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanInstantiator.java
index a260c2eecf..0bae47ad75 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanCreator2.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanInstantiator.java
@@ -43,7 +43,7 @@ import org.apache.juneau.commons.reflect.*;
  * <p>
  * This class is instantiated through the following method:
  * <ul class='javatree'>
- *     <li class='jm'>{@link BeanCreator2#of(Class)}
+ *     <li class='jm'>{@link BeanInstantiator#of(Class)}
  * </ul>
  *
  * <h5 class='section'>Example:</h5>
@@ -99,8 +99,8 @@ import org.apache.juneau.commons.reflect.*;
  *     }
  *     }
  *
- *     <jc>// Create bean using BeanCreator2</jc>
- *     MyBean <jv>bean</jv> = BeanCreator2
+ *     <jc>// Create bean using BeanInstantiator</jc>
+ *     MyBean <jv>bean</jv> = BeanInstantiator
  *             .<jsm>of</jsm>(MyBean.<jk>class</jk>, <jv>myBeanStore</jv>)
  *             .run();
  * </p>
@@ -186,7 +186,7 @@ import org.apache.juneau.commons.reflect.*;
 @SuppressWarnings({
        "java:S115" // Constants use UPPER_snakeCase convention
 })
-public class BeanCreator2<T> {
+public class BeanInstantiator<T> {
 
        private static final String CLASSNAME_Autowired = "Autowired";
        private static final String CLASSNAME_Inject = "Inject";
@@ -219,8 +219,8 @@ public class BeanCreator2<T> {
         * @param beanType The bean type to create.
         * @return A new bean creator.
         */
-       public static <T> BeanCreator2<T> of(Class<T> beanType) {
-               return new BeanCreator2<>(beanType, null, null, null);
+       public static <T> BeanInstantiator<T> of(Class<T> beanType) {
+               return new BeanInstantiator<>(beanType, null, null, null);
        }
 
        /**
@@ -231,8 +231,8 @@ public class BeanCreator2<T> {
         * @param parentStore The parent bean store to use for resolving 
dependencies. Can be <jk>null</jk>.
         * @return A new bean creator.
         */
-       public static <T> BeanCreator2<T> of(Class<T> beanType, BeanStore 
parentStore) {
-               return new BeanCreator2<>(beanType, parentStore, null, null);
+       public static <T> BeanInstantiator<T> of(Class<T> beanType, BeanStore 
parentStore) {
+               return new BeanInstantiator<>(beanType, parentStore, null, 
null);
        }
 
        /**
@@ -245,8 +245,8 @@ public class BeanCreator2<T> {
         * @param enclosingInstance The enclosing instance object. Can be 
<jk>null</jk>.
         * @return A new bean creator.
         */
-       public static <T> BeanCreator2<T> of(Class<T> beanType, BeanStore 
parentStore, String name, Object enclosingInstance) {
-               return new BeanCreator2<>(beanType, parentStore, name, 
enclosingInstance);
+       public static <T> BeanInstantiator<T> of(Class<T> beanType, BeanStore 
parentStore, String name, Object enclosingInstance) {
+               return new BeanInstantiator<>(beanType, parentStore, name, 
enclosingInstance);
        }
 
        private final BeanStore parentStore;
@@ -254,7 +254,7 @@ public class BeanCreator2<T> {
        private final ClassInfoTyped<T> beanType;
        private final SimpleReadWriteLock lock = new SimpleReadWriteLock();
        private final NullableReference<List<String>> debug = 
NullableReference.empty();
-       private static final Logger logger = 
Logger.getLogger(BeanCreator2.class);
+       private static final Logger logger = 
Logger.getLogger(BeanInstantiator.class);
 
        private ClassInfoTyped<? extends T> beanSubType;
        private ClassInfo explicitBuilderType = null;
@@ -284,7 +284,7 @@ public class BeanCreator2<T> {
         * @param name The bean name. Can be <jk>null</jk>.
         * @param enclosingInstance The enclosing instance object. Can be 
<jk>null</jk>.
         */
-       protected BeanCreator2(Class<T> beanType, BeanStore parentStore, String 
name, Object enclosingInstance) {
+       protected BeanInstantiator(Class<T> beanType, BeanStore parentStore, 
String name, Object enclosingInstance) {
                this.beanType = info(assertArgNotNull(ARG_beanType, beanType));
                this.beanSubType = this.beanType;
                this.parentStore = parentStore;
@@ -317,7 +317,7 @@ public class BeanCreator2<T> {
         * @param bean The bean instance.
         * @return This object.
         */
-       public <T2> BeanCreator2<T> addBean(Class<T2> type, T2 bean) {
+       public <T2> BeanInstantiator<T> addBean(Class<T2> type, T2 bean) {
                try (var writeLock = lock.write()) {
                        store.add(type, bean);
                        reset();
@@ -334,7 +334,7 @@ public class BeanCreator2<T> {
         * @param name The bean name.  Can be <jk>null</jk> for unnamed beans.
         * @return This object.
         */
-       public <T2> BeanCreator2<T> addBean(Class<T2> type, T2 bean, String 
name) {
+       public <T2> BeanInstantiator<T> addBean(Class<T2> type, T2 bean, String 
name) {
                try (var writeLock = lock.write()) {
                        store.add(type, bean, name);
                        reset();
@@ -369,20 +369,20 @@ public class BeanCreator2<T> {
         * <h5 class='section'>Example:</h5>
         * <p class='bjava'>
         *      <jc>// Try to create, use default if it fails</jc>
-        *      MyBean <jv>bean</jv> = BeanCreator2
+        *      MyBean <jv>bean</jv> = BeanInstantiator
         *              .<jsm>of</jsm>(MyBean.<jk>class</jk>, 
<jv>myBeanStore</jv>)
         *              .asOptional()
         *              .orElse(<jk>new</jk> DefaultMyBean());
         *
         *      <jc>// Chain multiple creation attempts</jc>
-        *      MyService <jv>service</jv> = 
BeanCreator2.<jsm>of</jsm>(AdvancedService.<jk>class</jk>, <jv>store</jv>)
+        *      MyService <jv>service</jv> = 
BeanInstantiator.<jsm>of</jsm>(AdvancedService.<jk>class</jk>, <jv>store</jv>)
         *              .asOptional()
-        *              .or(() -&gt; 
BeanCreator2.<jsm>of</jsm>(BasicService.<jk>class</jk>, <jv>store</jv>)
+        *              .or(() -&gt; 
BeanInstantiator.<jsm>of</jsm>(BasicService.<jk>class</jk>, <jv>store</jv>)
         *                      .asOptional())
         *              .orElseGet(() -&gt; <jk>new</jk> FallbackService());
         *
         *      <jc>// Check if optional feature is available</jc>
-        *      Optional&lt;OptionalFeature&gt; <jv>feature</jv> = BeanCreator2
+        *      Optional&lt;OptionalFeature&gt; <jv>feature</jv> = 
BeanInstantiator
         *              .<jsm>of</jsm>(OptionalFeature.<jk>class</jk>, 
<jv>store</jv>)
         *              .asOptional();
         *      <jk>if</jk> (<jv>feature</jv>.isPresent()) {
@@ -425,7 +425,7 @@ public class BeanCreator2<T> {
         *      BeanStore <jv>store</jv> = <jk>new</jk> 
BasicBeanStore2(<jk>null</jk>);
         *      <jv>store</jv>.addBean(String.<jk>class</jk>, 
<js>"initial"</js>);
         *
-        *      Memoizer&lt;MyBean&gt; <jv>supplier</jv> = BeanCreator2
+        *      Memoizer&lt;MyBean&gt; <jv>supplier</jv> = BeanInstantiator
         *              .<jsm>of</jsm>(MyBean.<jk>class</jk>, <jv>store</jv>)
         *              .asMemoizer();
         *
@@ -471,7 +471,7 @@ public class BeanCreator2<T> {
         * @return This object.
         * @throws IllegalArgumentException If value is not a subclass of 
{@code beanType}.
         */
-       public BeanCreator2<T> beanSubType(Class<? extends T> value) {
+       public BeanInstantiator<T> beanSubType(Class<? extends T> value) {
                assertArgNotNull(ARG_value, value);
                try (var writeLock = lock.write()) {
                        beanSubType = info(value);
@@ -508,7 +508,7 @@ public class BeanCreator2<T> {
         * @return This object.
         * @throws IllegalArgumentException If the builder type is invalid 
(does not have a valid build/create/get method).
         */
-       public BeanCreator2<T> builder(Class<?> value) {
+       public BeanInstantiator<T> builder(Class<?> value) {
                try (var writeLock = lock.write()) {
                        explicitBuilderType = info(assertArgNotNull(ARG_value, 
value));
                        builderType.set(explicitBuilderType);
@@ -546,7 +546,7 @@ public class BeanCreator2<T> {
         * @return This object.
         * @throws IllegalArgumentException If the builder instance's class is 
invalid (does not have a valid build/create/get method).
         */
-       public BeanCreator2<T> builder(Object value) {
+       public BeanInstantiator<T> builder(Object value) {
                try (var writeLock = lock.write()) {
                        builder(value.getClass());
                        explicitBuilder = assertArgNotNull(ARG_value, value);
@@ -559,7 +559,7 @@ public class BeanCreator2<T> {
         * Specifies custom class names to look for when auto-detecting builder 
inner classes.
         *
         * <p>
-        * By default, {@code BeanCreator2} looks for inner classes named 
{@code "Builder"}.
+        * By default, {@code BeanInstantiator} looks for inner classes named 
{@code "Builder"}.
         * This method allows you to specify alternative class names.
         *
         * <h5 class='section'>Notes:</h5><ul>
@@ -574,7 +574,7 @@ public class BeanCreator2<T> {
         * <h5 class='section'>Example:</h5>
         * <p class='bjava'>
         *      <jc>// Support alternative builder class naming conventions</jc>
-        *      MyBean <jv>bean</jv> = BeanCreator2
+        *      MyBean <jv>bean</jv> = BeanInstantiator
         *              .<jsm>of</jsm>(MyBean.<jk>class</jk>, 
<jv>myBeanStore</jv>)
         *              .builderClassNames(<js>"BuilderImpl"</js>, 
<js>"Factory"</js>)
         *              .run();
@@ -583,7 +583,7 @@ public class BeanCreator2<T> {
         * @param names The builder class names to look for. Cannot be 
<jk>null</jk> or contain <jk>null</jk> elements.
         * @return This object.
         */
-       public BeanCreator2<T> builderClassNames(String... names) {
+       public BeanInstantiator<T> builderClassNames(String... names) {
                try (var writeLock = lock.write()) {
                        builderClassNames = set(assertArgNoNulls(ARG_names, 
names));
                        reset();
@@ -595,7 +595,7 @@ public class BeanCreator2<T> {
         * Specifies custom method names to look for when auto-detecting 
builder factory methods.
         *
         * <p>
-        * By default, {@code BeanCreator2} looks for static methods named 
{@code "create"} or {@code "builder"}
+        * By default, {@code BeanInstantiator} looks for static methods named 
{@code "create"} or {@code "builder"}
         * that return a builder type. This method allows you to specify 
alternative method names.
         *
         * <h5 class='section'>Notes:</h5><ul>
@@ -610,7 +610,7 @@ public class BeanCreator2<T> {
         * <h5 class='section'>Example:</h5>
         * <p class='bjava'>
         *      <jc>// Support alternative builder factory method naming 
conventions</jc>
-        *      MyBean <jv>bean</jv> = BeanCreator2
+        *      MyBean <jv>bean</jv> = BeanInstantiator
         *              .<jsm>of</jsm>(MyBean.<jk>class</jk>)
         *              .builderMethodNames(<js>"newBuilder"</js>, 
<js>"instance"</js>)
                .run();
@@ -619,7 +619,7 @@ public class BeanCreator2<T> {
         * @param names The builder factory method names to look for. Cannot be 
<jk>null</jk> or contain <jk>null</jk> elements.
         * @return This object.
         */
-       public BeanCreator2<T> builderMethodNames(String... names) {
+       public BeanInstantiator<T> builderMethodNames(String... names) {
                try (var writeLock = lock.write()) {
                        builderMethodNames = set(assertArgNoNulls(ARG_names, 
names));
                        reset();
@@ -631,7 +631,7 @@ public class BeanCreator2<T> {
         * Specifies custom method names to look for when calling build methods 
on builder instances.
         *
         * <p>
-        * By default, {@code BeanCreator2} looks for instance methods named 
{@code "build"}, {@code "create"}, or {@code "get"}
+        * By default, {@code BeanInstantiator} looks for instance methods 
named {@code "build"}, {@code "create"}, or {@code "get"}
         * on the builder that return the bean type. This method allows you to 
specify alternative method names.
         *
         * <h5 class='section'>Notes:</h5><ul>
@@ -645,7 +645,7 @@ public class BeanCreator2<T> {
         * <h5 class='section'>Example:</h5>
         * <p class='bjava'>
         *      <jc>// Support alternative build method naming conventions</jc>
-        *      MyBean <jv>bean</jv> = BeanCreator2
+        *      MyBean <jv>bean</jv> = BeanInstantiator
         *              .<jsm>of</jsm>(MyBean.<jk>class</jk>)
         *              .buildMethodNames(<js>"execute"</js>, <js>"make"</js>)
                .run();
@@ -654,7 +654,7 @@ public class BeanCreator2<T> {
         * @param names The build method names to look for. Cannot be 
<jk>null</jk> or contain <jk>null</jk> elements.
         * @return This object.
         */
-       public BeanCreator2<T> buildMethodNames(String... names) {
+       public BeanInstantiator<T> buildMethodNames(String... names) {
                try (var writeLock = lock.write()) {
                        buildMethodNames = set(assertArgNoNulls(ARG_names, 
names));
                        reset();
@@ -677,7 +677,7 @@ public class BeanCreator2<T> {
         * <h5 class='section'>Example:</h5>
         * <p class='bjava'>
         *      <jc>// Enable caching mode - same instance returned on each 
run()</jc>
-        *      <jk>var</jk> <jv>creator</jv> = BeanCreator2
+        *      <jk>var</jk> <jv>creator</jv> = BeanInstantiator
         *              .<jsm>of</jsm>(MyBean.<jk>class</jk>)
         *              .<jsm>cached</jsm>();
         *      MyBean <jv>bean1</jv> = <jv>creator</jv>.<jsm>run</jsm>();
@@ -687,7 +687,7 @@ public class BeanCreator2<T> {
         *
         * @return This object.
         */
-       public BeanCreator2<T> cached() {
+       public BeanInstantiator<T> cached() {
                try (var writeLock = lock.write()) {
                        cached = true;
                }
@@ -749,7 +749,7 @@ public class BeanCreator2<T> {
         * <h5 class='section'>Example:</h5>
         * <p class='bjava'>
         *      <jc>// Enable debug mode</jc>
-        *      <jk>var</jk> <jv>creator</jv> = BeanCreator2
+        *      <jk>var</jk> <jv>creator</jv> = BeanInstantiator
         *              .<jsm>of</jsm>(MyBean.<jk>class</jk>, <jv>store</jv>)
         *              .debug();
         *
@@ -761,7 +761,7 @@ public class BeanCreator2<T> {
         *
         * @return This object.
         */
-       public BeanCreator2<T> debug() {
+       public BeanInstantiator<T> debug() {
                try (var writeLock = lock.write()) {
                        debug.set(synchronizedList(new ArrayList<>()));
                }
@@ -773,7 +773,7 @@ public class BeanCreator2<T> {
         * Specifies custom static factory method names to look for when 
creating the bean.
         *
         * <p>
-        * By default, {@link BeanCreator2} looks for a static {@code 
getInstance()} method when attempting
+        * By default, {@link BeanInstantiator} looks for a static {@code 
getInstance()} method when attempting
         * to create beans without a builder. This method allows you to specify 
alternative
         * factory method names to support non-standard naming conventions.
         *
@@ -789,7 +789,7 @@ public class BeanCreator2<T> {
         * <h5 class='section'>Example:</h5>
         * <p class='bjava'>
         *      <jc>// Support multiple factory method naming conventions</jc>
-        *      MyBean <jv>bean</jv> = BeanCreator2
+        *      MyBean <jv>bean</jv> = BeanInstantiator
         *              .<jsm>of</jsm>(MyBean.<jk>class</jk>, 
<jv>myBeanStore</jv>)
         *              .factoryMethodNames(<js>"of"</js>, <js>"from"</js>, 
<js>"create"</js>, <js>"newInstance"</js>)
         *              .run();
@@ -798,7 +798,7 @@ public class BeanCreator2<T> {
         * @param names The factory method names to look for. Cannot be 
<jk>null</jk> or contain <jk>null</jk> elements.
         * @return This object.
         */
-       public BeanCreator2<T> factoryMethodNames(String... names) {
+       public BeanInstantiator<T> factoryMethodNames(String... names) {
                try (var writeLock = lock.write()) {
                        factoryMethodNames = set(assertArgNoNulls(ARG_names, 
names));
                        reset();
@@ -833,14 +833,14 @@ public class BeanCreator2<T> {
         * <h5 class='section'>Example:</h5>
         * <p class='bjava'>
         *      <jc>// Provide a default instance if creation fails</jc>
-        *      MyService <jv>service</jv> = BeanCreator2
+        *      MyService <jv>service</jv> = BeanInstantiator
         *              .<jsm>of</jsm>(MyService.<jk>class</jk>, 
<jv>myBeanStore</jv>)
         *              .fallback(() -&gt; <jk>new</jk> DefaultMyService())
         *              .run();
         *
         *      <jc>// Use a pre-created instance as fallback</jc>
         *      MyService <jv>defaultService</jv> = <jk>new</jk> 
DefaultMyService();
-        *      MyService <jv>service2</jv> = BeanCreator2
+        *      MyService <jv>service2</jv> = BeanInstantiator
         *              .<jsm>of</jsm>(MyService.<jk>class</jk>, 
<jv>myBeanStore</jv>)
         *              .fallback(() -&gt; <jv>defaultService</jv>)
         *              .run();
@@ -849,7 +849,7 @@ public class BeanCreator2<T> {
         * @param fallback The fallback supplier. Cannot be <jk>null</jk>.
         * @return This object.
         */
-       public BeanCreator2<T> fallback(Supplier<? extends T> fallback) {
+       public BeanInstantiator<T> fallback(Supplier<? extends T> fallback) {
                assertArgNotNull(ARG_fallback, fallback);
                try (var writeLock = lock.write()) {
                        this.fallbackSupplier = fallback;
@@ -987,7 +987,7 @@ public class BeanCreator2<T> {
         *
         * <h5 class='section'>Example:</h5>
         * <p class='bjava'>
-        *      <jk>var</jk> <jv>creator</jv> = 
BeanCreator2.<jsm>of</jsm>(MyBean.<jk>class</jk>, <jv>store</jv>)
+        *      <jk>var</jk> <jv>creator</jv> = 
BeanInstantiator.<jsm>of</jsm>(MyBean.<jk>class</jk>, <jv>store</jv>)
         *              .debug();
         *
         *      <jk>try</jk> {
@@ -1020,7 +1020,7 @@ public class BeanCreator2<T> {
         * @param value The bean implementation instance.
         * @return This object.
         */
-       public BeanCreator2<T> implementation(T value) {
+       public BeanInstantiator<T> implementation(T value) {
                try (var writeLock = lock.write()) {
                        this.explicitImplementation = value;
                }
@@ -1051,7 +1051,7 @@ public class BeanCreator2<T> {
         * <h5 class='section'>Example:</h5>
         * <p class='bjava'>
         *      <jc>// Register multiple post-creation hooks</jc>
-        *      MyService <jv>service</jv> = BeanCreator2
+        *      MyService <jv>service</jv> = BeanInstantiator
         *              .<jsm>of</jsm>(MyService.<jk>class</jk>, 
<jv>myBeanStore</jv>)
         *              .postCreateHook(<jv>s</jv> -&gt; 
<jv>s</jv>.initialize())
         *              .postCreateHook(<jv>s</jv> -&gt; 
<jv>s</jv>.loadConfiguration())
@@ -1062,7 +1062,7 @@ public class BeanCreator2<T> {
         * @param hook The post-creation hook to run after bean creation. 
Cannot be <jk>null</jk>.
         * @return This object.
         */
-       public BeanCreator2<T> postCreateHook(Consumer<T> hook) {
+       public BeanInstantiator<T> postCreateHook(Consumer<T> hook) {
                assertArgNotNull(ARG_hook, hook);
                try (var writeLock = lock.write()) {
                        postCreateHooks.add(hook);
@@ -1087,7 +1087,7 @@ public class BeanCreator2<T> {
         *
         * @return This object.
         */
-       public BeanCreator2<T> reset() {
+       public BeanInstantiator<T> reset() {
                try (var writeLock = lock.write()) {
                        // Only reset builder if no explicit builder instance 
was set
                        // Explicit builder instances should be preserved 
across resets
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanStore.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanStore.java
index 1ab1109051..200857126d 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanStore.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanStore.java
@@ -17,7 +17,9 @@
 package org.apache.juneau.commons.inject;
 
 import java.util.*;
-import java.util.function.Supplier;
+import java.util.function.*;
+
+import org.apache.juneau.commons.reflect.*;
 
 /**
  * Spring-bean-like interface for looking up beans by type and name.
@@ -134,5 +136,77 @@ public interface BeanStore {
         * @return The supplier, or {@link Optional#empty()} if no supplier of 
the specified type and name exists.
         */
        <T> Optional<Supplier<T>> getBeanSupplier(Class<T> beanType, String 
name);
+
+       /**
+        * Finds and invokes a factory method that produces a bean of type 
<c>beanType</c>.
+        *
+        * <p>
+        * Scans all public methods of the resource class identified by 
<c>onClassOrObject</c>:
+        * <ul>
+        *      <li>If <c>onClassOrObject</c> is a {@link Class}, only 
<jk>static</jk> methods are eligible and
+        *              the instance parameter passed to the invoked method is 
<jk>null</jk>.
+        *      <li>If <c>onClassOrObject</c> is any other object, both 
instance and static methods on its class are
+        *              eligible, and the object itself is passed as the 
receiver.
+        * </ul>
+        *
+        * <p>
+        * The first method satisfying all of the following is invoked:
+        * <ol>
+        *      <li>Not deprecated.
+        *      <li>Return type is assignment-compatible with <c>beanType</c>.
+        *      <li>Accepted by <c>filter</c> (if non-<jk>null</jk>; otherwise 
any method qualifies).
+        *      <li>All parameters can be resolved from this store plus any 
<c>extraBeans</c>.
+        * </ol>
+        *
+        * <p>
+        * The default implementation returns {@link Optional#empty()}.
+        * Override in concrete stores (see {@link BasicBeanStore2}) to enable 
factory-method scanning.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      <jc>// Filter only</jc>
+        *      
<jv>beanStore</jv>.createBeanFromMethod(CallLogger.<jk>class</jk>, 
<jv>resource</jv>,
+        *              RestContext::isRestInjectMethod)
+        *              .ifPresent(<jv>creator</jv>::impl);
+        *
+        *      <jc>// Filter + extra bean not yet in the store</jc>
+        *      
<jv>beanStore</jv>.createBeanFromMethod(EncoderSet.<jk>class</jk>, 
<jv>resource</jv>,
+        *              RestContext::isRestInjectMethod, <jv>builder</jv>)
+        *              .ifPresent(<jv>x</jv> -&gt; 
<jv>builder</jv>.impl(<jv>x</jv>));
+        *
+        *      <jc>// No filter, no extra beans</jc>
+        *      
<jv>beanStore</jv>.createBeanFromMethod(CallLogger.<jk>class</jk>, 
<jv>resource</jv>);
+        * </p>
+        *
+        * @param <T> The bean type.
+        * @param beanType The type of bean to create.  Must not be 
<jk>null</jk>.
+        * @param onClassOrObject The object instance or {@link Class} whose 
public methods are searched.
+        *      Must not be <jk>null</jk>.
+        * @param filter Optional predicate restricting which methods are 
eligible.  Can be <jk>null</jk>.
+        * @param extraBeans Optional bean instances visible to parameter 
resolution for this call only.
+        *      These are <em>not</em> registered in the store.
+        * @return The created bean wrapped in an {@link Optional}, or {@link 
Optional#empty()} if no matching
+        *      factory method was found.
+        * @throws BeanCreationException If a matching method was found but 
threw an exception during invocation.
+        * @see BeanInstantiator BeanInstantiator — for instantiating a bean 
from its own constructors, builders, or factory methods
+        */
+       default <T> Optional<T> createBeanFromMethod(Class<T> beanType, Object 
onClassOrObject, Predicate<MethodInfo> filter, Object... extraBeans) {
+               return Optional.empty();
+       }
+
+       /**
+        * Convenience overload of {@link #createBeanFromMethod(Class, Object, 
Predicate, Object...)} with no filter and no extra beans.
+        *
+        * @param <T> The bean type.
+        * @param beanType The type of bean to create.  Must not be 
<jk>null</jk>.
+        * @param onClassOrObject The object instance or {@link Class} whose 
public methods are searched.
+        *      Must not be <jk>null</jk>.
+        * @return The created bean wrapped in an {@link Optional}, or {@link 
Optional#empty()} if no matching
+        *      factory method was found.
+        * @throws BeanCreationException If a matching method was found but 
threw an exception during invocation.
+        */
+       default <T> Optional<T> createBeanFromMethod(Class<T> beanType, Object 
onClassOrObject) {
+               return createBeanFromMethod(beanType, onClassOrObject, null);
+       }
 }
 
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/CreatableBeanStore.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/CreatableBeanStore.java
index 2dfef5aca3..fee680e5e6 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/CreatableBeanStore.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/CreatableBeanStore.java
@@ -24,10 +24,10 @@ import java.util.concurrent.*;
 import java.util.function.*;
 
 /**
- * A bean store that provides convenient access to {@link BeanCreator2} 
instances for creating beans.
+ * A bean store that provides convenient access to {@link BeanInstantiator} 
instances for creating beans.
  *
  * <p>
- * This class extends {@link BasicBeanStore2} and adds methods to manage 
{@link BeanCreator2} instances
+ * This class extends {@link BasicBeanStore2} and adds methods to manage 
{@link BeanInstantiator} instances
  * for different bean types. Creators are lazily created and cached for 
efficient reuse.
  *
  * <h5 class='section'>Example:</h5>
@@ -36,7 +36,7 @@ import java.util.function.*;
  *     CreatableBeanStore <jv>store</jv> = <jk>new</jk> 
CreatableBeanStore(<jk>null</jk>);
  *
  *     <jc>// Get or create a creator for MyBean</jc>
- *     BeanCreator2&lt;MyBean&gt; <jv>creator</jv> = 
<jv>store</jv>.getCreator(MyBean.<jk>class</jk>);
+ *     BeanInstantiator&lt;MyBean&gt; <jv>creator</jv> = 
<jv>store</jv>.getCreator(MyBean.<jk>class</jk>);
  *
  *     <jc>// Use the creator to create a bean</jc>
  *     MyBean <jv>bean</jv> = <jv>creator</jv>.create();
@@ -47,7 +47,7 @@ import java.util.function.*;
  *
  * <h5 class='section'>See Also:</h5><ul>
  *     <li class='jc'>{@link BasicBeanStore2}
- *     <li class='jc'>{@link BeanCreator2}
+ *     <li class='jc'>{@link BeanInstantiator}
  * </ul>
  */
 @SuppressWarnings({
@@ -58,7 +58,7 @@ public class CreatableBeanStore extends BasicBeanStore2 {
        // Argument name constants for assertArgNotNull
        private static final String ARG_beanType = "beanType";
 
-       private final ConcurrentHashMap<Class<?>, BeanCreator2<?>> creators = 
new ConcurrentHashMap<>();
+       private final ConcurrentHashMap<Class<?>, BeanInstantiator<?>> creators 
= new ConcurrentHashMap<>();
        private final Object enclosingInstance;
 
        /**
@@ -79,9 +79,9 @@ public class CreatableBeanStore extends BasicBeanStore2 {
         * @param beanType The bean type to create a creator for. Cannot be 
<jk>null</jk>.
         * @return The creator that was created and stored.
         */
-       public <T> BeanCreator2<T> add(Class<T> beanType) {
+       public <T> BeanInstantiator<T> add(Class<T> beanType) {
                assertArgNotNull(ARG_beanType, beanType);
-               var creator = BeanCreator2.of(beanType, this, null, 
enclosingInstance);
+               var creator = BeanInstantiator.of(beanType, this, null, 
enclosingInstance);
                creators.put(beanType, creator);
                return creator;
        }
@@ -94,15 +94,15 @@ public class CreatableBeanStore extends BasicBeanStore2 {
         * @param name The bean name. Can be <jk>null</jk>.
         * @return The creator that was created and stored.
         */
-       public <T> BeanCreator2<T> add(Class<T> beanType, String name) {
+       public <T> BeanInstantiator<T> add(Class<T> beanType, String name) {
                assertArgNotNull(ARG_beanType, beanType);
-               var creator = BeanCreator2.of(beanType, this, name, 
enclosingInstance);
+               var creator = BeanInstantiator.of(beanType, this, name, 
enclosingInstance);
                creators.put(beanType, creator);
                return creator;
        }
 
        /**
-        * Creates and stores a {@link BeanCreator2} for the specified bean 
type.
+        * Creates and stores a {@link BeanInstantiator} for the specified bean 
type.
         *
         * <p>
         * If a creator for this type already exists, it is replaced with a new 
one.
@@ -113,7 +113,7 @@ public class CreatableBeanStore extends BasicBeanStore2 {
         *      <jv>store</jv>.addCreator(MyBean.<jk>class</jk>);
         *
         *      <jc>// Get the creator</jc>
-        *      BeanCreator2&lt;MyBean&gt; <jv>creator</jv> = 
<jv>store</jv>.getCreator(MyBean.<jk>class</jk>);
+        *      BeanInstantiator&lt;MyBean&gt; <jv>creator</jv> = 
<jv>store</jv>.getCreator(MyBean.<jk>class</jk>);
         * </p>
         *
         * @param <T> The bean type.
@@ -122,13 +122,13 @@ public class CreatableBeanStore extends BasicBeanStore2 {
         */
        public <T> CreatableBeanStore addCreator(Class<T> beanType) {
                assertArgNotNull(ARG_beanType, beanType);
-               var creator = BeanCreator2.of(beanType, this, null, 
enclosingInstance);
+               var creator = BeanInstantiator.of(beanType, this, null, 
enclosingInstance);
                creators.put(beanType, creator);
                return this;
        }
 
        /**
-        * Creates and stores a {@link BeanCreator2} for the specified bean 
type with a name.
+        * Creates and stores a {@link BeanInstantiator} for the specified bean 
type with a name.
         *
         * <p>
         * If a creator for this type already exists, it is replaced with a new 
one.
@@ -139,7 +139,7 @@ public class CreatableBeanStore extends BasicBeanStore2 {
         *      <jv>store</jv>.addCreator(MyBean.<jk>class</jk>, 
<js>"myBean"</js>);
         *
         *      <jc>// Get the creator</jc>
-        *      BeanCreator2&lt;MyBean&gt; <jv>creator</jv> = 
<jv>store</jv>.getCreator(MyBean.<jk>class</jk>, <js>"myBean"</js>);
+        *      BeanInstantiator&lt;MyBean&gt; <jv>creator</jv> = 
<jv>store</jv>.getCreator(MyBean.<jk>class</jk>, <js>"myBean"</js>);
         * </p>
         *
         * @param <T> The bean type.
@@ -149,13 +149,13 @@ public class CreatableBeanStore extends BasicBeanStore2 {
         */
        public <T> CreatableBeanStore addCreator(Class<T> beanType, String 
name) {
                assertArgNotNull(ARG_beanType, beanType);
-               var creator = BeanCreator2.of(beanType, this, name, 
enclosingInstance);
+               var creator = BeanInstantiator.of(beanType, this, name, 
enclosingInstance);
                creators.put(beanType, creator);
                return this;
        }
 
        /**
-        * Returns the {@link BeanCreator2} for the specified bean type, 
creating it if it doesn't exist.
+        * Returns the {@link BeanInstantiator} for the specified bean type, 
creating it if it doesn't exist.
         *
         * <p>
         * If a creator for this type doesn't exist, a new one is created with 
this bean store configured
@@ -164,7 +164,7 @@ public class CreatableBeanStore extends BasicBeanStore2 {
         * <h5 class='section'>Example:</h5>
         * <p class='bjava'>
         *      <jc>// Get or create a creator</jc>
-        *      BeanCreator2&lt;MyBean&gt; <jv>creator</jv> = 
<jv>store</jv>.getCreator(MyBean.<jk>class</jk>);
+        *      BeanInstantiator&lt;MyBean&gt; <jv>creator</jv> = 
<jv>store</jv>.getCreator(MyBean.<jk>class</jk>);
         *
         *      <jc>// Use the creator to create a bean</jc>
         *      MyBean <jv>bean</jv> = <jv>creator</jv>.create();
@@ -175,15 +175,15 @@ public class CreatableBeanStore extends BasicBeanStore2 {
         * @return The creator for the specified bean type. Never <jk>null</jk>.
         */
        @SuppressWarnings({
-               "unchecked" // Type erasure requires cast to BeanCreator2<T>
+               "unchecked" // Type erasure requires cast to BeanInstantiator<T>
        })
-       public <T> BeanCreator2<T> getCreator(Class<T> beanType) {
+       public <T> BeanInstantiator<T> getCreator(Class<T> beanType) {
                assertArgNotNull(ARG_beanType, beanType);
-               return (BeanCreator2<T>)creators.computeIfAbsent(beanType, k -> 
BeanCreator2.of((Class<T>)k, this, null, enclosingInstance));
+               return (BeanInstantiator<T>)creators.computeIfAbsent(beanType, 
k -> BeanInstantiator.of((Class<T>)k, this, null, enclosingInstance));
        }
 
        /**
-        * Returns the {@link BeanCreator2} for the specified bean type with a 
name, creating it if it doesn't exist.
+        * Returns the {@link BeanInstantiator} for the specified bean type 
with a name, creating it if it doesn't exist.
         *
         * <p>
         * If a creator for this type doesn't exist, a new one is created with 
this bean store configured
@@ -192,7 +192,7 @@ public class CreatableBeanStore extends BasicBeanStore2 {
         * <h5 class='section'>Example:</h5>
         * <p class='bjava'>
         *      <jc>// Get or create a creator with a name</jc>
-        *      BeanCreator2&lt;MyBean&gt; <jv>creator</jv> = 
<jv>store</jv>.getCreator(MyBean.<jk>class</jk>, <js>"myBean"</js>);
+        *      BeanInstantiator&lt;MyBean&gt; <jv>creator</jv> = 
<jv>store</jv>.getCreator(MyBean.<jk>class</jk>, <js>"myBean"</js>);
         *
         *      <jc>// Use the creator to create a bean</jc>
         *      MyBean <jv>bean</jv> = <jv>creator</jv>.create();
@@ -204,11 +204,11 @@ public class CreatableBeanStore extends BasicBeanStore2 {
         * @return The creator for the specified bean type. Never <jk>null</jk>.
         */
        @SuppressWarnings({
-               "unchecked" // Type erasure requires cast to BeanCreator2<T>
+               "unchecked" // Type erasure requires cast to BeanInstantiator<T>
        })
-       public <T> BeanCreator2<T> getCreator(Class<T> beanType, String name) {
+       public <T> BeanInstantiator<T> getCreator(Class<T> beanType, String 
name) {
                assertArgNotNull(ARG_beanType, beanType);
-               return (BeanCreator2<T>)creators.computeIfAbsent(beanType, k -> 
BeanCreator2.of((Class<T>)k, this, name, enclosingInstance));
+               return (BeanInstantiator<T>)creators.computeIfAbsent(beanType, 
k -> BeanInstantiator.of((Class<T>)k, this, name, enclosingInstance));
        }
 
        /**
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanCreator.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanCreator.java
index 7467f8462f..a214543b03 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanCreator.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanCreator.java
@@ -268,7 +268,8 @@ public class BeanCreator<T> {
         * @throws ExecutableException if bean could not be created and {@link 
#silent()} was not enabled.
         */
        @SuppressWarnings({
-               "java:S3776" // Cognitive complexity acceptable for bean 
creation with multiple creation strategies
+               "java:S3776", // Cognitive complexity acceptable for bean 
creation with multiple creation strategies
+               "java:S6541"  // Brain Method: bean creation logic requires 
handling multiple strategies in sequence
        })
        public T run() {
 
@@ -343,7 +344,7 @@ public class BeanCreator<T> {
 
                // Look for public constructor.
                var constructorMatch = new Match<ConstructorInfo>();
-               type.getPublicConstructors().stream().forEach(x -> {
+               type.getPublicConstructors().forEach(x -> {
                        found.setIfEmpty("PUBLIC_CONSTRUCTOR");
                        if (hasAllParams(x))
                                constructorMatch.add(x);
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/commons/inject/BeanCreator2_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/commons/inject/BeanInstantiator_Test.java
similarity index 97%
rename from 
juneau-utest/src/test/java/org/apache/juneau/commons/inject/BeanCreator2_Test.java
rename to 
juneau-utest/src/test/java/org/apache/juneau/commons/inject/BeanInstantiator_Test.java
index be703ce8c1..ce13e39fb0 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/commons/inject/BeanCreator2_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/commons/inject/BeanInstantiator_Test.java
@@ -38,7 +38,7 @@ import java.util.logging.Level;
        "java:S1172", // Unused parameters in tests are intentional
        "java:S1186" // Empty test method intentional for framework testing
 })
-class BeanCreator2_Test extends TestBase {
+class BeanInstantiator_Test extends TestBase {
 
        private BasicBeanStore2 beanStore;
 
@@ -48,11 +48,11 @@ class BeanCreator2_Test extends TestBase {
        }
 
        /**
-        * Helper method to create a BeanCreator2 instance with the test's 
beanStore.
-        * Reduces repetition of BeanCreator2.of(Class, beanStore) pattern.
+        * Helper method to create a BeanInstantiator instance with the test's 
beanStore.
+        * Reduces repetition of BeanInstantiator.of(Class, beanStore) pattern.
         */
-       private <T> BeanCreator2<T> bc(Class<T> c) {
-               return BeanCreator2.of(c, beanStore);
+       private <T> BeanInstantiator<T> bc(Class<T> c) {
+               return BeanInstantiator.of(c, beanStore);
        }
 
        
//====================================================================================================
@@ -950,7 +950,7 @@ class BeanCreator2_Test extends TestBase {
 
                /**
                 * Tests creating a bean using builder pattern with 
auto-detected builder.
-                * Verifies that BeanCreator2 can automatically detect and use 
an inner Builder class
+                * Verifies that BeanInstantiator can automatically detect and 
use an inner Builder class
                 * when no explicit builder is specified. The builder is found 
via the static create()
                 * method that returns a Builder instance, demonstrating the 
default builder detection mechanism.
                 */
@@ -967,7 +967,7 @@ class BeanCreator2_Test extends TestBase {
                /**
                 * Tests creating a bean using an explicitly provided builder 
instance.
                 * Verifies that when a builder instance is explicitly provided 
via builder(),
-                * BeanCreator2 uses that instance instead of creating a new 
one. This allows
+                * BeanInstantiator uses that instance instead of creating a 
new one. This allows
                 * pre-configuring the builder with specific values before bean 
creation.
                 */
                @Test
@@ -987,7 +987,7 @@ class BeanCreator2_Test extends TestBase {
                /**
                 * Tests creating a bean using builder pattern with @Builder 
annotation.
                 * Verifies that when a bean class is annotated with @Builder 
specifying a builder type,
-                * BeanCreator2 uses that builder type instead of 
auto-detection. This provides explicit
+                * BeanInstantiator uses that builder type instead of 
auto-detection. This provides explicit
                 * control over which builder class to use for bean creation.
                 */
                @Test
@@ -1096,7 +1096,7 @@ class BeanCreator2_Test extends TestBase {
 
                /**
                 * Tests creating a bean using builder with protected 
constructor.
-                * Verifies that builders with protected constructors can be 
instantiated by BeanCreator2.
+                * Verifies that builders with protected constructors can be 
instantiated by BeanInstantiator.
                 * This tests the fallback mechanism that searches for 
protected constructors when no public
                 * constructor is available, enabling encapsulation while still 
allowing bean creation.
                 */
@@ -1181,7 +1181,7 @@ class BeanCreator2_Test extends TestBase {
                /**
                 * Tests creating a child bean using child's own builder that 
extends parent's builder.
                 * Verifies that when a child class has its own @Builder 
annotation pointing to a builder
-                * that extends the parent's builder, BeanCreator2 uses the 
child's builder annotation
+                * that extends the parent's builder, BeanInstantiator uses the 
child's builder annotation
                 * (which overrides the parent's). The child's builder must 
override build() to return
                 * the child type, ensuring type safety.
                 */
@@ -1274,7 +1274,7 @@ class BeanCreator2_Test extends TestBase {
                /**
                 * Tests creating a child bean using child's own builder that 
extends parent's inner Builder class.
                 * Verifies that when a child class has its own builder that 
extends the parent's inner Builder class,
-                * BeanCreator2 uses the child's builder. The child's builder 
must override build() to return the
+                * BeanInstantiator uses the child's builder. The child's 
builder must override build() to return the
                 * child type, ensuring type safety. The builder is discovered 
through the child class's static create() method.
                 */
                @Test
@@ -1329,7 +1329,7 @@ class BeanCreator2_Test extends TestBase {
 
                /**
                 * Tests creating a bean using builder pattern with static 
builder() method (instead of create()).
-                * Verifies that BeanCreator2 recognizes "builder" as a valid 
builder factory method name alongside
+                * Verifies that BeanInstantiator recognizes "builder" as a 
valid builder factory method name alongside
                 * the default "create" method. This supports alternative 
naming conventions where classes use
                 * builder() instead of create() to return builder instances.
                 */
@@ -1405,7 +1405,7 @@ class BeanCreator2_Test extends TestBase {
                /**
                 * Tests creating a bean using builder with create() method 
instead of build().
                 * Verifies that builders can use "create" as an alternative to 
"build" for the method that
-                * constructs the bean. BeanCreator2 searches for build(), 
create(), or get() methods on builders,
+                * constructs the bean. BeanInstantiator searches for build(), 
create(), or get() methods on builders,
                 * providing flexibility in builder method naming conventions.
                 */
                @Test
@@ -1486,7 +1486,7 @@ class BeanCreator2_Test extends TestBase {
 
                /**
                 * Tests creating a bean using builder with build() method that 
has parameters resolved from bean store.
-                * Verifies that when a builder's build() method requires 
parameters, BeanCreator2 resolves them from
+                * Verifies that when a builder's build() method requires 
parameters, BeanInstantiator resolves them from
                 * the bean store via dependency injection. This enables 
builders to accept additional dependencies
                 * beyond what's stored in builder fields, providing more 
flexible bean construction.
                 */
@@ -1533,7 +1533,7 @@ class BeanCreator2_Test extends TestBase {
 
                /**
                 * Tests that deprecated constructors are ignored in favor of 
non-deprecated ones.
-                * Verifies that when multiple constructors are available, 
BeanCreator2 skips deprecated ones
+                * Verifies that when multiple constructors are available, 
BeanInstantiator skips deprecated ones
                 * and prefers non-deprecated alternatives. This ensures that 
deprecated APIs don't interfere
                 * with bean creation, allowing graceful deprecation of old 
constructor signatures.
                 */
@@ -1568,7 +1568,7 @@ class BeanCreator2_Test extends TestBase {
 
                /**
                 * Tests that constructors with unresolvable parameters are 
ignored, falling back to no-arg constructor.
-                * Verifies that BeanCreator2 skips constructors whose 
parameters cannot be resolved from the bean store,
+                * Verifies that BeanInstantiator skips constructors whose 
parameters cannot be resolved from the bean store,
                 * preferring constructors with resolvable or no parameters. 
This ensures robust bean creation even when
                 * some constructor signatures cannot be satisfied.
                 */
@@ -1599,7 +1599,7 @@ class BeanCreator2_Test extends TestBase {
 
                /**
                 * Tests creating a bean via static factory method that accepts 
builder when builder has no build() method.
-                * Verifies that when a builder lacks build/create/get methods, 
BeanCreator2 falls back to static factory
+                * Verifies that when a builder lacks build/create/get methods, 
BeanInstantiator falls back to static factory
                 * methods on the bean class that accept the builder. Factory 
methods are preferred over constructors,
                 * demonstrating the priority order: builder methods > factory 
methods > constructors.
                 */
@@ -1748,7 +1748,7 @@ class BeanCreator2_Test extends TestBase {
 
                /**
                 * Tests creating a bean using builder with custom method name 
when no build/create/get method exists and no constructor accepts builder.
-                * Verifies the final fallback mechanism where BeanCreator2 
searches for any method on the builder that returns
+                * Verifies the final fallback mechanism where BeanInstantiator 
searches for any method on the builder that returns
                 * the bean type. When standard builder methods and 
constructors aren't available, this "anything" method search
                 * provides a last-resort mechanism for bean creation, 
demonstrating maximum flexibility in builder patterns.
                 */
@@ -1806,7 +1806,7 @@ class BeanCreator2_Test extends TestBase {
                /**
                 * Tests that invalid builders (no valid build method, no 
constructor accepting builder) fail validation and fall back to constructor.
                 * Verifies that when a builder candidate doesn't meet 
validation criteria (no valid build method returning bean type,
-                * no constructor accepting builder), BeanCreator2 rejects it 
and falls back to direct constructor-based creation.
+                * no constructor accepting builder), BeanInstantiator rejects 
it and falls back to direct constructor-based creation.
                 * This ensures that invalid builder configurations don't 
prevent bean creation, maintaining robustness.
                 */
                @Test
@@ -1856,7 +1856,7 @@ class BeanCreator2_Test extends TestBase {
                /**
                 * Tests that ExecutableException is thrown when builder fails 
to create bean and no fallback is provided.
                 * Verifies that when a builder's build() method requires 
unresolvable parameters and no alternative creation
-                * path exists (no factory methods, no valid constructors), 
BeanCreator2 throws an ExecutableException.
+                * path exists (no factory methods, no valid constructors), 
BeanInstantiator throws an ExecutableException.
                 * This ensures that unresolvable builder configurations result 
in clear error reporting rather than silent failures.
                 */
                @Test
@@ -1997,11 +1997,11 @@ class BeanCreator2_Test extends TestBase {
                 */
                @Test
                void f01_createInnerBean() {
-                       var outerInstance = new BeanCreator2_Test();
+                       var outerInstance = new BeanInstantiator_Test();
                        var value = "test";
                        beanStore.add(String.class, value);
 
-                       var bean = BeanCreator2.of(InnerBean.class, beanStore, 
null, outerInstance)
+                       var bean = BeanInstantiator.of(InnerBean.class, 
beanStore, null, outerInstance)
                                .run();
 
                        assertEquals(value, bean.getValue());
@@ -2178,7 +2178,7 @@ class BeanCreator2_Test extends TestBase {
        }
 
        /**
-        * Tests converting BeanCreator2 to Supplier interfaces:
+        * Tests converting BeanInstantiator to Supplier interfaces:
         * - asSupplier() conversion
         * - asMemoizer() with caching
         * - Optional-like methods on suppliers
@@ -2187,7 +2187,7 @@ class BeanCreator2_Test extends TestBase {
        @Nested class H_supplierConversion extends TestBase {
 
                /**
-                * Tests converting BeanCreator2 to a Supplier.
+                * Tests converting BeanInstantiator to a Supplier.
                 */
                @Test
                void h01_asSupplier() {
@@ -2212,7 +2212,7 @@ class BeanCreator2_Test extends TestBase {
                }
 
                /**
-                * Tests converting BeanCreator2 to a Memoizer.
+                * Tests converting BeanInstantiator to a Memoizer.
                 */
                @Test
                void h03_asMemoizer() {
@@ -2326,7 +2326,7 @@ class BeanCreator2_Test extends TestBase {
                 */
                @Test
                void i02_beanSubTypeReturnsThis() {
-                       var creator = BeanCreator2.of(ParentBean.class);
+                       var creator = BeanInstantiator.of(ParentBean.class);
                        var result = creator.beanSubType(ChildBean.class);
                        assertSame(creator, result);
                }
@@ -2336,7 +2336,7 @@ class BeanCreator2_Test extends TestBase {
                 */
                @Test
                void i03_addBeanReturnsThis() {
-                       var creator = BeanCreator2.of(SimpleBean.class);
+                       var creator = BeanInstantiator.of(SimpleBean.class);
                        var result = creator.addBean(TestService.class, new 
TestService("test"));
                        assertSame(creator, result);
                }
@@ -2346,7 +2346,7 @@ class BeanCreator2_Test extends TestBase {
                 */
                @Test
                void i05_builderReturnsThis() {
-                       var creator = BeanCreator2.of(BeanWithBuilder.class);
+                       var creator = 
BeanInstantiator.of(BeanWithBuilder.class);
                        var result = creator.builder(BeanWithBuilder.create());
                        assertSame(creator, result);
                }
@@ -2356,8 +2356,8 @@ class BeanCreator2_Test extends TestBase {
                 */
                @Test
                void i06_enclosingInstanceCanBeSetViaConstructor() {
-                       var outerInstance = new BeanCreator2_Test();
-                       var creator = BeanCreator2.of(InnerBean.class, null, 
null, outerInstance);
+                       var outerInstance = new BeanInstantiator_Test();
+                       var creator = BeanInstantiator.of(InnerBean.class, 
null, null, outerInstance);
                        // Verify creator was created successfully
                        assertNotNull(creator);
                }
@@ -2368,7 +2368,7 @@ class BeanCreator2_Test extends TestBase {
                @Test
                void i07_addMethodReturnsBean() {
                        var service = new TestService("test");
-                       var creator = 
BeanCreator2.of(BeanWithDependencies.class);
+                       var creator = 
BeanInstantiator.of(BeanWithDependencies.class);
 
                        var result = creator.add(TestService.class, service);
 
@@ -3356,7 +3356,7 @@ class BeanCreator2_Test extends TestBase {
                 */
                @Test
                void n12_beanSubTypeNullThrows() {
-                       var creator = BeanCreator2.of(SimpleBean.class);
+                       var creator = BeanInstantiator.of(SimpleBean.class);
                        assertThrows(IllegalArgumentException.class, () -> 
creator.beanSubType(null));
                }
        }
@@ -3381,7 +3381,7 @@ class BeanCreator2_Test extends TestBase {
                }
 
                /**
-                * Tests that BeanCreator2.of(Class, BeanStore) can resolve 
dependencies from parent bean store.
+                * Tests that BeanInstantiator.of(Class, BeanStore) can resolve 
dependencies from parent bean store.
                 */
                @Test
                void o02_ofWithParentStore() {
@@ -3389,7 +3389,7 @@ class BeanCreator2_Test extends TestBase {
                        var testService = new TestService("parent-service");
                        parentStore.addBean(TestService.class, testService);
 
-                       var bean = BeanCreator2.of(BeanWithDependencies.class, 
parentStore)
+                       var bean = 
BeanInstantiator.of(BeanWithDependencies.class, parentStore)
                                .addBean(AnotherService.class, new 
AnotherService(42))
                                .run();
 
@@ -3398,11 +3398,11 @@ class BeanCreator2_Test extends TestBase {
                }
 
                /**
-                * Tests that BeanCreator2.of(Class, null) works when no parent 
bean store is provided.
+                * Tests that BeanInstantiator.of(Class, null) works when no 
parent bean store is provided.
                 */
                @Test
                void o03_ofWithParentStoreNull() {
-                       var bean = BeanCreator2.of(SimpleBean.class, 
null).run();
+                       var bean = BeanInstantiator.of(SimpleBean.class, 
null).run();
 
                        assertInstanceOf(SimpleBean.class, bean);
                }
@@ -3417,7 +3417,7 @@ class BeanCreator2_Test extends TestBase {
                        parentStore.addBean(TestService.class, parentService);
 
                        var localService = new TestService("local");
-                       var bean = BeanCreator2.of(BeanWithDependencies.class, 
parentStore)
+                       var bean = 
BeanInstantiator.of(BeanWithDependencies.class, parentStore)
                                .addBean(TestService.class, localService) // 
Local overrides parent
                                .addBean(AnotherService.class, new 
AnotherService(42))
                                .run();
@@ -3465,7 +3465,7 @@ class BeanCreator2_Test extends TestBase {
                 */
                @Test
                void p03_getNameReturnsNullWhenNotSet() {
-                       var creator = BeanCreator2.of(SimpleBean.class);
+                       var creator = BeanInstantiator.of(SimpleBean.class);
                        var name = creator.getName();
 
                        assertNull(name, "getName() should return null when no 
name is set");
@@ -3476,7 +3476,7 @@ class BeanCreator2_Test extends TestBase {
                 */
                @Test
                void p04_getNameReturnsSetName() {
-                       var creator = BeanCreator2.of(SimpleBean.class, 
beanStore, "myBean", null);
+                       var creator = BeanInstantiator.of(SimpleBean.class, 
beanStore, "myBean", null);
                        var name = creator.getName();
 
                        assertEquals("myBean", name);
@@ -3487,7 +3487,7 @@ class BeanCreator2_Test extends TestBase {
                 */
                @Test
                void p05_getNameReturnsNullWhenSetToNull() {
-                       var creator = BeanCreator2.of(SimpleBean.class, 
beanStore, null, null);
+                       var creator = BeanInstantiator.of(SimpleBean.class, 
beanStore, null, null);
                        var name = creator.getName();
 
                        assertNull(name, "getName() should return null when 
name is set to null");
@@ -3645,7 +3645,7 @@ class BeanCreator2_Test extends TestBase {
                 */
                @Test
                void p17_nameCanBeSetViaConstructor() {
-                       var creator = BeanCreator2.of(SimpleBean.class, null, 
"testBean", null);
+                       var creator = BeanInstantiator.of(SimpleBean.class, 
null, "testBean", null);
 
                        assertEquals("testBean", creator.getName());
                }
@@ -3655,7 +3655,7 @@ class BeanCreator2_Test extends TestBase {
                 */
                @Test
                void p18_nameCanBeSetToNull() {
-                       var creator = BeanCreator2.of(SimpleBean.class, 
beanStore, null, null);
+                       var creator = BeanInstantiator.of(SimpleBean.class, 
beanStore, null, null);
                        assertNull(creator.getName(), "name should allow null 
value");
                }
 
@@ -3664,7 +3664,7 @@ class BeanCreator2_Test extends TestBase {
                 */
                @Test
                void p19_nameCanBeSetViaConstructor() {
-                       var creator = BeanCreator2.of(SimpleBean.class, 
beanStore, "final", null);
+                       var creator = BeanInstantiator.of(SimpleBean.class, 
beanStore, "final", null);
 
                        assertEquals("final", creator.getName());
                }
@@ -3736,9 +3736,9 @@ class BeanCreator2_Test extends TestBase {
                 */
                @Test
                void q01_loggingOnSimpleBeanCreation() {
-                       // Get the logger instance using the same method as 
BeanCreator2 static field
+                       // Get the logger instance using the same method as 
BeanInstantiator static field
                        // This ensures we get the same cached instance
-                       var logger = Logger.getLogger(BeanCreator2.class);
+                       var logger = Logger.getLogger(BeanInstantiator.class);
                        logger.setLevel(Level.FINE); // Enable FINE level 
logging
 
                        try (var capture = logger.captureEvents()) {
@@ -3767,7 +3767,7 @@ class BeanCreator2_Test extends TestBase {
                 */
                @Test
                void q02_loggingOnBuilderBeanCreation() {
-                       var logger = Logger.getLogger(BeanCreator2.class);
+                       var logger = Logger.getLogger(BeanInstantiator.class);
                        logger.setLevel(Level.FINE); // Enable FINE level 
logging
                        try (var capture = logger.captureEvents()) {
                                var bean = bc(Q02_BeanWithBuilder.class).run();
@@ -3789,7 +3789,7 @@ class BeanCreator2_Test extends TestBase {
                 */
                @Test
                void q03_logMessagesIncludeBeanTypePrefix() {
-                       var logger = Logger.getLogger(BeanCreator2.class);
+                       var logger = Logger.getLogger(BeanInstantiator.class);
                        logger.setLevel(Level.FINE); // Enable FINE level 
logging
                        try (var capture = logger.captureEvents()) {
                                var bean = bc(SimpleBean.class).run();
@@ -3814,7 +3814,7 @@ class BeanCreator2_Test extends TestBase {
                 */
                @Test
                void q04_logMessagesWithFormatArguments() {
-                       var logger = Logger.getLogger(BeanCreator2.class);
+                       var logger = Logger.getLogger(BeanInstantiator.class);
                        try (var capture = logger.captureEvents()) {
                                // Create a bean that will trigger logging with 
format arguments
                                var bean = bc(Q02_BeanWithBuilder.class).run();
diff --git a/todo/TODO-14-move-svl-to-commons.md 
b/todo/TODO-14-move-svl-to-commons.md
index 3e440bd426..ec1133463c 100644
--- a/todo/TODO-14-move-svl-to-commons.md
+++ b/todo/TODO-14-move-svl-to-commons.md
@@ -20,7 +20,7 @@ Relocate `org.apache.juneau.svl` (Simple Variable Language) 
from `juneau-marshal
 - Both expose an `Optional<String>`-returning API — callers perform any type 
conversion themselves via `Optional.map(...)`.
 - **Hard break on the package rename.** No deprecated shim classes left in 
`org.apache.juneau.svl.*`; callers update their imports. Acceptable because 9.5 
is the designated "simple breaking changes" release.
 - Marshall-side `collections.Args` and `utils.ManifestFile` are **deleted** in 
9.5 — callers move to `org.apache.juneau.commons.runtime.Args` / 
`ManifestFile`. (No deprecation cycle; 9.5 allows the break.)
-- SVL engine (`VarResolver` / `VarResolverSession`) retargets the commons 
bean-store stack **after** TODO-15 renames the `*2` classes to their final 
names. TODO-14 never references `BasicBeanStore2` / `BeanCreator2` directly.
+- SVL engine (`VarResolver` / `VarResolverSession`) retargets the commons 
bean-store stack **after** TODO-15 renames the `*2` classes to their final 
names. TODO-14 never references `BasicBeanStore2` / `BeanInstantiator` directly.
 
 ---
 
diff --git a/todo/TODO-15-replace-basicbeanstore-with-v2.md 
b/todo/TODO-15-replace-basicbeanstore-with-v2.md
index 3e411268e9..c7bb018fa0 100644
--- a/todo/TODO-15-replace-basicbeanstore-with-v2.md
+++ b/todo/TODO-15-replace-basicbeanstore-with-v2.md
@@ -1,15 +1,26 @@
 # Replace `BasicBeanStore` / `BeanCreator` with v2 equivalents
 
-Eliminate the legacy injection stack in `org.apache.juneau.cp` 
(`BasicBeanStore`, `BeanCreator`, `BeanBuilder`, `BeanCreateMethodFinder`, 
`ContextBeanCreator`) in favor of the rewritten classes already present in 
`org.apache.juneau.commons.inject` (`BasicBeanStore2`, `BeanCreator2`, 
`BeanStore`, `CreatableBeanStore`, etc.). Once the replacement lands, the `2` 
suffix is dropped and the legacy classes are removed.
+Eliminate the legacy injection stack in `org.apache.juneau.cp` 
(`BasicBeanStore`, `BeanCreator`, `BeanBuilder`, `BeanCreateMethodFinder`, 
`ContextBeanCreator`) in favor of the rewritten classes already present in 
`org.apache.juneau.commons.inject` (`BasicBeanStore2`, `BeanInstantiator`, 
`BeanStore`, `CreatableBeanStore`, etc.). Once the replacement lands, the `2` 
suffix is dropped from `BasicBeanStore2` (→ `BasicBeanStore`) and the legacy 
classes are removed. `BeanInstantiator` already h [...]
 
 **Target release:** **9.5.0** — semi-major release permitting simple breaking 
changes. Hard-break migration (no deprecation cycle on the final rename).
 
 **Sequencing:**
 - **Lands before TODO-14.** TODO-14 (SVL → commons) consumes the final, 
un-suffixed class names produced by this TODO, so this work must complete first.
-- TODO-1 (REST server API → `BeanStore2`) — prerequisite consumer migration, 
folded into Phase 3 below.
+- ~~TODO-1 (REST server API → `BeanStore2`)~~ — **DONE.** `RestContext` and 
all rest-server memoizers now use `BasicBeanStore2` / `WritableBeanStore` 
directly. No `cp.BasicBeanStore` imports remain in `juneau-rest-server` source 
files. Legacy references in `RestInject.java` / `RestInit.java` are 
**Javadoc-only**.
 
-**Related 9.5 work that shrinks this migration's footprint:**
-- **TODO-16** — replaces `RestContext.Builder` configuration with 
memoized/resettable fields on `RestContext` (reference pattern: 
`RestContext.allowedParserOptions`). Many of the `BeanBuilder<T>` / 
`BasicBeanStore` consumers currently living under `juneau-rest-server` will 
disappear as part of that refactor, independent of this TODO. **Consumer 
inventory (Phase 2 below) must run after TODO-16 Phase 1–2 lands** so we aren't 
migrating builders that are about to be deleted.
+**Current remaining footprint (as of 2026-05-07):**
+
+| Location | Legacy symbol | Nature |
+|---|---|---|
+| `RestContext.java` | `BeanCreateMethodFinder` | 33 live call sites — the 
dominant remaining work |
+| `RestOpContext.java` | `BeanCreateMethodFinder` | 16 live call sites |
+| `RestInject.java`, `RestInit.java` | `cp.BasicBeanStore` | Javadoc only — 
trivial update |
+| `McpPage.java`, `McpTypedHandlers.java` | `cp.BasicBeanStore` | live usage 
in rest-server-mcp module |
+| `Name.java`, `Named.java` | `cp.BasicBeanStore` | Javadoc / annotation 
`@see` only |
+| `HttpPartParser.java`, `HttpPartSerializer.java` | `BeanCreateMethodFinder` 
| 1 reference each — likely Javadoc |
+| `BeanStore_Test.java` | `BeanCreateMethodFinder` | 2 test references |
+
+**The v2 replacement API (`BeanStore.createBeanFromMethod`) is implemented. 
The critical path is now migrating the 49 `BeanCreateMethodFinder` call sites 
in `RestContext` and `RestOpContext` to use it.**
 
 ---
 
@@ -23,7 +34,7 @@ Low-risk, independent of the rest of this plan. Can land in 
an earlier release t
   - `org.apache.juneau.cp.BeanBuilder` *(consumer class 
`org.apache.juneau.BeanBuilder` — re-evaluate)*
   - `org.apache.juneau.cp.BeanCreateMethodFinder`
   - `org.apache.juneau.cp.ContextBeanCreator`
-- [ ] Do **not** use `forRemoval = true` yet — too many internal consumers 
still wired to these. Deletion happens in Phase 4.
+- [ ] Do **not** use `forRemoval = true` yet — remaining internal consumers 
still wired to these. Deletion happens in Phase 4.
 
 ---
 
@@ -49,29 +60,48 @@ Net new v2 surface from this decision: none. The `Builder` 
class simply goes awa
 - [ ] **`BasicBeanStore.Void.class`** — used as an annotation-default sentinel 
in `@Rest.beanStore()` and `RestAnnotation`. Either:
   - port a `BasicBeanStore2.Void` sentinel class, or
   - redesign those annotations (e.g., treat `BasicBeanStore2.class` itself as 
the sentinel and interpret "equal to default" as "unset").
-- [ ] **Executable-resolution helpers** — `getMissingParams(ExecutableInfo, 
Object)`, `getParams(ExecutableInfo, Object)`, `hasAllParams(ExecutableInfo, 
Object)`. v2 provides the same capability via 
`MethodInfo.canResolveAllParameters(store, extras)` and `ClassInfo.inject(bean, 
store)`. Plan: **migrate callers to the new API** rather than adding compat 
methods to the store. Verify no external API exposes these three legacy methods.
+- ~~**`BeanCreateMethodFinder` → v2 equivalent**~~ — **DONE.** Replaced by 
`BeanStore.createBeanFromMethod(Class<T>, Object, Predicate<MethodInfo>, 
Object...)`. The legacy DSL pattern:
+  ```java
+  new BeanCreateMethodFinder<>(Type.class, resource, beanStore)
+      .addBean(...)
+      .find(RestContext::isRestInjectMethod)
+      .run(result -> ...);
+  ```
+  migrates to:
+  ```java
+  beanStore.createBeanFromMethod(Type.class, resource,
+      RestContext::isRestInjectMethod, extraBean)
+      .ifPresent(result -> ...);
+  ```
+  Also introduced `BeanCreationException` (unchecked) and renamed 
`BeanCreator2` → `BeanInstantiator` to disambiguate the two APIs.
+- [ ] **Executable-resolution helpers** — `getMissingParams(ExecutableInfo, 
Object)`, `getParams(ExecutableInfo, Object)`, `hasAllParams(ExecutableInfo, 
Object)`. Still used in `RestContext` init path. Plan: **migrate callers to the 
new API** rather than adding compat methods to the store. Verify no external 
API exposes these three legacy methods.
 
 ### Still to survey
 
 - [ ] **`BasicBeanStore.Entry<T>`** (public/extendable entry record, exposed 
via protected `createEntry(...)`) — confirm no external subclassers before 
deleting.
-- [ ] Diff `cp.BeanCreator` vs `commons.inject.BeanCreator2` — note any 
legacy-only methods / behaviors that need to be ported.
-- [ ] Diff `cp.BeanCreateMethodFinder` and `cp.ContextBeanCreator` against 
`BeanCreator2` — confirm their functionality is subsumed; list any callers that 
need rewriting rather than a rename.
+- [ ] Diff `cp.BeanCreator` vs `commons.inject.BeanInstantiator` — note any 
legacy-only methods / behaviors that need to be ported.
+- [ ] Diff `cp.BeanCreateMethodFinder` and `cp.ContextBeanCreator` against 
`BeanInstantiator` — confirm their functionality is subsumed; list any callers 
that need rewriting rather than a rename.
 - [ ] Verify SVL's needs (`VarResolver(.Builder)` / `VarResolverSession`): 
constructor-based `Var` instantiation, optional session bean lookup, bean-store 
copy semantics. Cover any gaps here before TODO-14 starts.
 - [ ] Document any residual deltas (missing methods, renamed methods, behavior 
differences) in this file before proceeding to Phase 2.
 
 ## Phase 2 — Consumer inventory
 
-- [ ] Enumerate direct callers of each legacy class across all modules 
(`juneau-marshall`, `juneau-rest-*`, `juneau-microservice-*`, `juneau-config`, 
`juneau-utest`).
-- [ ] Classify each caller as:
-  - **mechanical** — straightforward switch to the `*2` equivalent
-  - **non-trivial** — needs an interface/adapter change (likely callers 
holding `BasicBeanStore` in public API)
-- [ ] List the public API surfaces that expose `BasicBeanStore` / 
`BeanCreator` directly (these are the hardest part — every such method is a 
breaking change when renamed).
+**Much of Phase 2 is already resolved.** The REST server `BasicBeanStore` 
migration (TODO-1) has landed, leaving only the items in the table above.
+
+Remaining inventory work:
+- [ ] Confirm the `BeanCreateMethodFinder` callers in `RestContext` (33) and 
`RestOpContext` (16) are all mechanical once the v2 finder API is settled.
+- [ ] Check `McpPage.java` / `McpTypedHandlers.java` in `rest-server-mcp` — 
likely mechanical.
+- [ ] Enumerate direct callers in `juneau-microservice-*` and `juneau-config` 
(not yet surveyed).
+- [ ] List any public API surfaces in `juneau-marshall` that still expose 
`BasicBeanStore` / `BeanCreator` (these are the hard breaking changes). 
`Name.java` / `Named.java` Javadoc refs are trivial.
 
 ## Phase 3 — Migrate consumers to `*2`
 
-- [ ] Migrate internal consumers first (no public API change, no compat risk).
-- [ ] Migrate each public API surface. Since 9.5 allows simple breaking 
changes, the old overloads can be **replaced** rather than overloaded — pick 
whichever path yields the cleaner API per case. Document any breaking signature 
change in the 9.5 release notes.
-- [ ] Include TODO-1 (REST server) as part of or prior to this phase.
+- ~~Settle and implement the `BeanCreateMethodFinder` → v2 replacement API~~ — 
**DONE.** `BeanStore.createBeanFromMethod()` is live.
+- [ ] Migrate `RestContext` and `RestOpContext` (49 `BeanCreateMethodFinder` 
call sites) — now mechanical.
+- [ ] Migrate `McpPage` / `McpTypedHandlers` in `rest-server-mcp`.
+- [ ] Migrate remaining `juneau-microservice-*` / `juneau-config` consumers 
(if any).
+- [ ] Update Javadoc-only references in `RestInject.java`, `RestInit.java`, 
`Name.java`, `Named.java`, `HttpPartParser.java`, `HttpPartSerializer.java`.
+- [ ] Migrate each public API surface in `juneau-marshall`. Since 9.5 allows 
simple breaking changes, replace rather than overload — document each signature 
change in the 9.5 release notes.
 
 ## Phase 4 — Cutover rename
 
@@ -80,9 +110,9 @@ Once nothing still references the legacy classes:
 - [ ] Delete `org.apache.juneau.cp.BasicBeanStore`, `BeanCreator`, 
`BeanBuilder`, `BeanCreateMethodFinder`, `ContextBeanCreator`.
 - [ ] Rename the commons classes in place (drop the `2` suffix):
   - `BasicBeanStore2` → `BasicBeanStore`
-  - `BeanCreator2`   → `BeanCreator`
+  - `BeanInstantiator` — **no rename needed** (already has its final name; was 
`BeanCreator2`)
   - (update any other `*2`-suffixed types and their references)
-- [ ] Repo-wide find/replace of remaining `BasicBeanStore2` / `BeanCreator2` 
references.
+- [ ] Repo-wide find/replace of remaining `BasicBeanStore2` / 
`BeanInstantiator` references.
 - [ ] Re-run `./scripts/test.py -f`.
 
 ## Phase 5 — Cleanup
@@ -121,9 +151,9 @@ Answer these before (or early in) Phase 1. They drive the 
shape of the v2 classe
      - b) Delete it and rewrite each surviving domain builder to hold a plain 
`BeanStore` reference.
      - c) Replace with a minimal commons equivalent 
(`org.apache.juneau.commons.inject.BeanBuilder`) with a trimmed surface.
 
-2. **`BeanCreateMethodFinder` replacement.** Used by rest-server / context 
builders to locate `static Optional<T> createX(...)` factory methods. Does 
`BeanCreator2`'s existing method discovery cover this, or do we port a 
dedicated finder?
+2. ~~**`BeanCreateMethodFinder` replacement.**~~ **RESOLVED.** 
`BeanStore.createBeanFromMethod(Class<T>, Object, Predicate<MethodInfo>, 
Object...)` is the v2 equivalent. `BeanInstantiator` handles 
self-instantiation; `createBeanFromMethod` handles external factory-method 
discovery.
 
-3. **`ContextBeanCreator` replacement.** Thin wrapper used during 
`Context.Builder` initialization. Is it subsumed by `BeanCreator2`, or does it 
need to be ported (possibly renamed)?
+3. **`ContextBeanCreator` replacement.** Thin wrapper used during 
`Context.Builder` initialization. Is it subsumed by `BeanInstantiator`, or does 
it need to be ported (possibly renamed)?
 
 4. **`BasicBeanStore.Void` sentinel.** Pick one of the two paths listed in 
Phase 1 (port `Void` vs. redesign `@Rest.beanStore()` default). Affects `@Rest` 
annotation processing code in rest-server.
 
diff --git a/todo/TODO-23-commons-inject-framework-roadmap.md 
b/todo/TODO-23-commons-inject-framework-roadmap.md
index 4922479b90..a1127205b1 100644
--- a/todo/TODO-23-commons-inject-framework-roadmap.md
+++ b/todo/TODO-23-commons-inject-framework-roadmap.md
@@ -14,7 +14,7 @@ Grow **`org.apache.juneau.commons.inject`** into a **small, 
predictable** compos
 
 ## Current baseline (inventory)
 
-Today the package is primarily the **bean store** stack (e.g. `BeanStore`, 
`WritableBeanStore`, `CreatableBeanStore`, `BasicBeanStore2`, `BeanCreator2`). 
Treat this document as a **wishlist / decision log**: each subsection needs a 
**yes/no** and **scope** before implementation.
+Today the package is primarily the **bean store** stack (e.g. `BeanStore`, 
`WritableBeanStore`, `CreatableBeanStore`, `BasicBeanStore2`, 
`BeanInstantiator`). Treat this document as a **wishlist / decision log**: each 
subsection needs a **yes/no** and **scope** before implementation.
 
 ---
 
diff --git a/todo/TODO-24-jsr330-and-spring-lite-support.md 
b/todo/TODO-24-jsr330-and-spring-lite-support.md
index 34c10ca28a..ecc5036df8 100644
--- a/todo/TODO-24-jsr330-and-spring-lite-support.md
+++ b/todo/TODO-24-jsr330-and-spring-lite-support.md
@@ -36,7 +36,7 @@ Make **`org.apache.juneau.commons.inject`** present a story 
we can summarize as:
 
 | JSR-330 element | Juneau plan | Notes |
 |------------------|------------|-------|
-| **`@Inject`** (constructor / method / field) | Provide 
**`org.apache.juneau.commons.inject.Inject`** with same targets and runtime 
retention; treat **`jakarta.inject.Inject`** / **`javax.inject.Inject`** as 
equivalent in lookup code. **Expose `@Inject` as a user-facing annotation** on 
REST resources — fields and methods on `@Rest` resources annotated `@Inject` 
are populated from the resource's `BeanStore` at initialization time. | 
Constructor injection is the primary pattern Juneau alr [...]
+| **`@Inject`** (constructor / method / field) | Provide 
**`org.apache.juneau.commons.inject.Inject`** with same targets and runtime 
retention; treat **`jakarta.inject.Inject`** / **`javax.inject.Inject`** as 
equivalent in lookup code. **Expose `@Inject` as a user-facing annotation** on 
REST resources — fields and methods on `@Rest` resources annotated `@Inject` 
are populated from the resource's `BeanStore` at initialization time. | 
Constructor injection is the primary pattern Juneau alr [...]
 | **`@Named`** | Keep / move Juneau **`@Named`**; recognize 
**`jakarta.inject.Named`** / **`javax.inject.Named`** for both **resolution** 
and as **qualifier** info. | `ParameterInfo.findQualifierInternal()` is the 
existing template — generalize to any FQN ending in `Named` from these two 
packages. |
 | **`@Qualifier`** (meta-annotation) | Add 
**`org.apache.juneau.commons.inject.Qualifier`** as a meta-annotation marker; 
treat **any** annotation that is itself meta-annotated with **Juneau 
`@Qualifier`** OR **`jakarta.inject.Qualifier`** OR 
**`javax.inject.Qualifier`** as a qualifier on a parameter / field. | Lookup 
keys: `(type, qualifier-set)`. Start by supporting **string-valued qualifiers** 
(mirror `@Named`) and exact-match annotation-type qualifiers; defer qualifier 
*attribute* equ [...]
 | **`@Scope` + `@Singleton`** | Add 
**`org.apache.juneau.commons.inject.Singleton`** as a scope marker; recognize 
JSR-330 `Singleton` by FQN. | Semantics in our model: a singleton is 
**registered once in a `BeanStore`** and reused; no proxying, no JVM-wide 
singleton. Custom `@Scope` annotations are **out of scope** for v1. |
@@ -89,7 +89,7 @@ Explicitly **declined** for v1 (revisit only with a real 
consumer):
    - `org.apache.juneau.commons.inject.Named` (and current 
`org.apache.juneau.annotation.Named` until/if moved)
    - `jakarta.inject.Named`, `javax.inject.Named`
    - any annotation meta-annotated with one of the recognized `@Qualifier` 
annotations.
-- [ ] Update bean-creation paths (`BeanCreator2` and equivalents) to honor 
`@Inject` on constructors / methods using the same FQN list.
+- [ ] Update bean-creation paths (`BeanInstantiator` and equivalents) to honor 
`@Inject` on constructors / methods using the same FQN list.
 
 ### Phase 4 — `Provider<T>` injection support
 

Reply via email to