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(() ->
BeanCreator2.<jsm>of</jsm>(BasicService.<jk>class</jk>, <jv>store</jv>)
+ * .or(() ->
BeanInstantiator.<jsm>of</jsm>(BasicService.<jk>class</jk>, <jv>store</jv>)
* .asOptional())
* .orElseGet(() -> <jk>new</jk> FallbackService());
*
* <jc>// Check if optional feature is available</jc>
- * Optional<OptionalFeature> <jv>feature</jv> = BeanCreator2
+ * Optional<OptionalFeature> <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<MyBean> <jv>supplier</jv> = BeanCreator2
+ * Memoizer<MyBean> <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(() -> <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(() -> <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> ->
<jv>s</jv>.initialize())
* .postCreateHook(<jv>s</jv> ->
<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> ->
<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<MyBean> <jv>creator</jv> =
<jv>store</jv>.getCreator(MyBean.<jk>class</jk>);
+ * BeanInstantiator<MyBean> <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<MyBean> <jv>creator</jv> =
<jv>store</jv>.getCreator(MyBean.<jk>class</jk>);
+ * BeanInstantiator<MyBean> <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<MyBean> <jv>creator</jv> =
<jv>store</jv>.getCreator(MyBean.<jk>class</jk>, <js>"myBean"</js>);
+ * BeanInstantiator<MyBean> <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<MyBean> <jv>creator</jv> =
<jv>store</jv>.getCreator(MyBean.<jk>class</jk>);
+ * BeanInstantiator<MyBean> <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<MyBean> <jv>creator</jv> =
<jv>store</jv>.getCreator(MyBean.<jk>class</jk>, <js>"myBean"</js>);
+ * BeanInstantiator<MyBean> <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