001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.commons.inject; 018 019import static java.util.Collections.*; 020import static java.util.Comparator.*; 021import static org.apache.juneau.commons.function.Suppliers.*; 022import static org.apache.juneau.commons.reflect.ElementFlag.*; 023import static org.apache.juneau.commons.reflect.ReflectionUtils.*; 024import static org.apache.juneau.commons.utils.CollectionUtils.*; 025import static org.apache.juneau.commons.utils.Shorts.*; 026 027import java.util.*; 028import java.util.function.*; 029 030import org.apache.juneau.commons.concurrent.*; 031import org.apache.juneau.commons.function.*; 032import org.apache.juneau.commons.logging.*; 033import org.apache.juneau.commons.reflect.*; 034 035/** 036 * Utility class for creating beans through constructors, creator methods, and builders. 037 * 038 * <p> 039 * Uses a {@link BeanStore} to find available ways to construct beans via injection of beans from the store. 040 * 041 * <p> 042 * This class is instantiated through the following method: 043 * <ul class='javatree'> 044 * <li class='jm'>{@link BeanInstantiator#of(Class)} 045 * </ul> 046 * 047 * <h5 class='section'>Example:</h5> 048 * <p class='bjava'> 049 * <jc>// Bean with builder pattern</jc> 050 * <jk>public class</jk> MyBean { 051 * <jk>private final</jk> String <jf>value</jf>; 052 * 053 * <jk>private</jk> MyBean(String <jv>value</jv>) { 054 * <jk>this</jk>.<jf>value</jf> = <jv>value</jv>; 055 * } 056 * 057 * <jk>public static</jk> Builder <jsm>create</jsm>() { 058 * <jk>return new</jk> Builder(); 059 * } 060 * 061 * <jk>public static class</jk> Builder { 062 * <jk>private</jk> String <jf>value</jf>; 063 * 064 * <jk>public</jk> Builder value(String <jv>value</jv>) { 065 * <jk>this</jk>.<jf>value</jf> = <jv>value</jv>; 066 * <jk>return this</jk>; 067 * } 068 * 069 * <jk>public</jk> MyBean build() { 070 * <jk>return new</jk> MyBean(<jf>value</jf>); 071 * } 072 * } 073 * 074 * <jc>// Builder with @Inject on build() method</jc> 075 * <jk>public class</jk> MyBean2 { 076 * <jk>private final</jk> String <jf>value</jf>; 077 * <jk>private final</jk> MyDependency <jf>dependency</jf>; 078 * 079 * <jk>private</jk> MyBean2(String <jv>value</jv>, MyDependency <jv>dependency</jv>) { 080 * <jk>this</jk>.<jf>value</jf> = <jv>value</jv>; 081 * <jk>this</jk>.<jf>dependency</jf> = <jv>dependency</jv>; 082 * } 083 * 084 * <jk>public static class</jk> Builder { 085 * <jk>private</jk> String <jf>value</jf>; 086 * 087 * <jk>public</jk> Builder value(String <jv>value</jv>) { 088 * <jk>this</jk>.<jf>value</jf> = <jv>value</jv>; 089 * <jk>return this</jk>; 090 * } 091 * 092 * <ja>@Inject</ja> 093 * <jk>public</jk> MyBean2 build(MyDependency <jv>dependency</jv>) { 094 * <jk>return new</jk> MyBean2(<jv>value</jv>, <jv>dependency</jv>); 095 * } 096 * } 097 * } 098 * } 099 * 100 * <jc>// Create bean using BeanInstantiator</jc> 101 * MyBean <jv>bean</jv> = BeanInstantiator 102 * .<jsm>of</jsm>(MyBean.<jk>class</jk>, <jv>myBeanStore</jv>) 103 * .run(); 104 * </p> 105 * 106 * <h5 class='section'>Bean Creation Order:</h5> 107 * <p> 108 * The creator attempts to instantiate beans in the following order: 109 * <ol class='spaced-list'> 110 * <li><b>Using a Builder</b> (if a builder is found or specified): 111 * <ol> 112 * <li>Calls a <c>build()</c>/<c>create()</c>/<c>get()</c> method on the builder that returns the bean type. 113 * <ul> 114 * <li>The method is <b>required</b> - if no such method exists, bean creation fails. 115 * <li>If the method has <c>@Inject</c> or <c>@Autowired</c> annotation, its parameters are resolved from the bean store. 116 * <li>If the method does not have <c>@Inject</c> annotation, it must have no parameters. 117 * </ul> 118 * </ol> 119 * <li><b>Without a Builder</b>: 120 * <ol> 121 * <li>Calls a static no-arg <c>getInstance()</c> method on the bean class. 122 * <li>Calls a public constructor with parameters that can be resolved from the bean store. 123 * <li>Falls back to a protected constructor with parameters that can be resolved from the bean store. 124 * <li>Falls back to a package-private constructor with parameters that can be resolved from the bean store. 125 * Private constructors are deliberately excluded. 126 * </ol> 127 * </ol> 128 * 129 * <h5 class='section'>Builder Detection:</h5> 130 * <p> 131 * Builders are detected in the following priority order: 132 * <ol class='spaced-list'> 133 * <li>Explicitly set via {@link Builder#builder(Object)} or {@link Builder#builder(Class)}. 134 * <li>{@link org.apache.juneau.commons.Builder @Builder} annotation on the bean subtype. 135 * <li>{@link org.apache.juneau.commons.Builder @Builder} annotation on the bean type. 136 * <li>Auto-detection: 137 * <ul> 138 * <li>Static <c>create()</c> or <c>builder()</c> method that returns a builder type 139 * (method names can be customized via {@link Builder#builderMethodNames(String...)}). 140 * <li>Inner class named <c>Builder</c>. 141 * </ul> 142 * </ol> 143 * 144 * <h5 class='section'>Dependency Injection:</h5> 145 * <p> 146 * Both builder instances and the final bean have automatic dependency injection performed via 147 * {@link ClassInfo#inject(Object, BeanStore)}, which processes {@code @Inject} and {@code @Autowired} annotations 148 * on fields and methods. 149 * 150 * <p> 151 * This means that after a bean is created, all of its fields and methods annotated with {@code @Inject} or {@code @Autowired} 152 * will automatically be populated with beans from the bean store. 153 * 154 * <h5 class='section'>Caching:</h5> 155 * <p> 156 * By default, each call to {@link #run()} creates a new bean instance. To enable caching, call {@link Builder#cached()}. 157 * When caching is enabled, bean instances are cached using {@link Memoizer}, so multiple calls to {@link #run()} 158 * will return the same instance unless {@link #reset()} is called or configuration changes. Explicit implementations set via 159 * {@link Builder#impl(Object)} and explicit builder instances set via {@link Builder#builder(Object)} are preserved 160 * across resets. 161 * 162 * <h5 class='section'>Thread Safety:</h5> 163 * <p> 164 * Configuration is performed on the inner {@link Builder} which is <b>not</b> thread-safe. Configure on a single 165 * thread, then call {@link Builder#build()} to produce an immutable {@link BeanInstantiator} that is safe for 166 * shared concurrent use. The {@link Builder#run()} shorthand is equivalent to {@code build().run()} and is 167 * appropriate for one-shot bean creation from a single thread. 168 * 169 * <h5 class='section'>Notes:</h5><ul> 170 * <li class='note'>Builders must have a <c>build()</c>, <c>create()</c>, or <c>get()</c> method that returns the bean type. 171 * This method is required - constructors accepting builders are no longer supported. 172 * <li class='note'>The builder's <c>build()</c>/<c>create()</c>/<c>get()</c> method may have <c>@Inject</c> or <c>@Autowired</c> 173 * annotation to allow dependency injection of parameters from the bean store. 174 * <li class='note'>If the builder's <c>build()</c>/<c>create()</c>/<c>get()</c> method does not have <c>@Inject</c> annotation, 175 * it must have no parameters. 176 * <li class='note'>All constructors and methods except {@link Optional} and {@link List} parameters 177 * must have beans available in the store. 178 * <li class='note'>If multiple constructors/methods are found, the one with the most matching parameters is used. 179 * <li class='note'>Deprecated and <a class="doclink" href="https://juneau.apache.org/site/apidocs/org/apache/juneau/commons/bean/BeanIgnore.html">@BeanIgnore</a>-annotated methods/constructors are ignored. 180 * </ul> 181 * 182 * <h5 class='section'>See Also:</h5><ul> 183 * <li class='jc'>{@link BasicBeanStore} 184 * </ul> 185 * 186 * @param <T> The bean type being created. 187 */ 188@SuppressWarnings({ 189 "java:S115", // Constants use UPPER_snakeCase convention 190 "java:S1192", // Duplicated literals (argument/property names) read more clearly inline than as constants 191 "java:S3776", // findBeanImpl() nests fallbacks across instantiation strategies; splitting it would obscure the ordering 192 "java:S6539", // Monster class; BeanInstantiator intentionally centralizes multi-strategy bean-instantiation auto-wiring 193 "java:S6541", // findBeanImpl() tries subtype, builder, factory-method and constructor strategies in sequence, so it is one long method by design 194 "resource", // transient build-time scratch store; lifetime is bounded by the Builder itself, no foreign resources are captured 195 "unchecked" // (T) beanType.cast(...) results and the (Class<? extends T>) narrowing in type() are guarded by the runtime beanType check 196}) 197public class BeanInstantiator<T> { 198 199 private static final String CONST_usingFallbackSupplier = "Using fallback supplier"; 200 201 /** Default factory method names used for bean instantiation. */ 202 protected static final Set<String> DEFAULT_FACTORY_METHOD_NAMES = u(set("getInstance")); 203 204 /** Default builder method names used for builder factory methods (static methods that create/return a builder). */ 205 protected static final Set<String> DEFAULT_BUILDER_METHOD_NAMES = u(set("create", "builder")); 206 207 /** Default build method names used for builder build methods (instance methods on builder that build/return the bean). */ 208 protected static final Set<String> DEFAULT_BUILD_METHOD_NAMES = u(set("build", "create", "get")); 209 210 /** Default builder class names for auto-detection. */ 211 protected static final Set<String> DEFAULT_BUILDER_CLASS_NAMES = u(set("Builder")); 212 213 private static final RichLogger logger = RichLogger.getLogger(BeanInstantiator.class); 214 215 /** 216 * Lifecycle scope for the bean being created. 217 * 218 * <p> 219 * Maps to {@link Builder#cached()} so that {@link Builder#scope(Scope)} provides a more declarative alternative. 220 * 221 * @see Builder#scope(Scope) 222 */ 223 public enum Scope { 224 /** A new bean instance is produced on every call to {@link Builder#run()}. */ 225 PROTOTYPE, 226 /** A single bean instance is created and reused for the lifetime of the builder. */ 227 SINGLETON 228 } 229 230 /** 231 * Creates a new bean creator builder. 232 * 233 * @param <T> The bean type to create. 234 * @param beanType The bean type to create. Must not be <jk>null</jk>. 235 * @return A new bean creator builder. 236 */ 237 public static <T> Builder<T> of(Class<T> beanType) { 238 return new Builder<>(beanType, null, null, null); 239 } 240 241 /** 242 * Creates a new bean creator builder with a parent bean store. 243 * 244 * @param <T> The bean type to create. 245 * @param beanType The bean type to create. Must not be <jk>null</jk>. 246 * @param parentStore The parent bean store to use for resolving dependencies. Can be <jk>null</jk> (the internal bean store then has no parent fallback). 247 * @return A new bean creator builder. 248 */ 249 public static <T> Builder<T> of(Class<T> beanType, BeanStore parentStore) { 250 return new Builder<>(beanType, parentStore, null, null); 251 } 252 253 /** 254 * Creates a new bean creator builder with a parent bean store, name, and enclosing instance. 255 * 256 * @param <T> The bean type to create. 257 * @param beanType The bean type to create. Must not be <jk>null</jk>. 258 * @param parentStore The parent bean store to use for resolving dependencies. Can be <jk>null</jk> (the internal bean store then has no parent fallback). 259 * @param name The bean name. Can be <jk>null</jk> for unnamed beans. 260 * @param enclosingInstance The enclosing instance object. Can be <jk>null</jk> (the outer-instance skip rule is then never applied). 261 * @return A new bean creator builder. 262 */ 263 public static <T> Builder<T> of(Class<T> beanType, BeanStore parentStore, String name, Object enclosingInstance) { 264 return new Builder<>(beanType, parentStore, name, enclosingInstance); 265 } 266 267 /** 268 * Instantiates a bean of the given type, or returns <jk>null</jk> if the type is <jk>null</jk> or instantiation fails. 269 * 270 * <p> 271 * Shorthand for the common pattern: 272 * <p class='bjava'> 273 * <jv>cls</jv> == <jk>null</jk> ? <jk>null</jk> : BeanInstantiator.<jsm>of</jsm>(<jv>cls</jv>).fallback(() -> <jk>null</jk>).run() 274 * </p> 275 * 276 * @param <T> The bean type to create. 277 * @param beanType The bean type to create. Can be <jk>null</jk>. 278 * @return A new bean instance, or <jk>null</jk> if the type is <jk>null</jk> or instantiation fails. 279 */ 280 public static <T> T createOrNull(Class<T> beanType) { 281 return beanType == null ? null : of(beanType).fallback(() -> null).run(); 282 } 283 284 /** 285 * Instantiates a bean of the given type and wraps it in an {@link Optional}, or returns {@link Optional#empty()} 286 * if the type is <jk>null</jk> or instantiation fails. 287 * 288 * <p> 289 * Shorthand for the common pattern: 290 * <p class='bjava'> 291 * <jv>cls</jv> == <jk>null</jk> ? Optional.empty() : BeanInstantiator.<jsm>of</jsm>(<jv>cls</jv>).asOptional() 292 * </p> 293 * 294 * @param <T> The bean type to create. 295 * @param beanType The bean type to create. Can be <jk>null</jk>. 296 * @return An {@link Optional} containing the created bean, or {@link Optional#empty()} if the type is <jk>null</jk> or instantiation fails. 297 */ 298 public static <T> Optional<T> optionalOf(Class<T> beanType) { 299 return beanType == null ? oe() : of(beanType).asOptional(); 300 } 301 302 /** 303 * Instantiates a bean of the given type, or returns a default value if the type is <jk>null</jk>. 304 * 305 * <p> 306 * Shorthand for the common pattern: 307 * <p class='bjava'> 308 * <jv>cls</jv> == <jk>null</jk> ? <jv>defaultValue</jv> : BeanInstantiator.<jsm>of</jsm>(<jv>cls</jv>).run() 309 * </p> 310 * 311 * @param <T> The bean type to create. 312 * @param beanType The bean type to create. Can be <jk>null</jk>. 313 * @param defaultValue The value to return if {@code beanType} is <jk>null</jk>. Can be <jk>null</jk>. 314 * @return A new bean instance, or {@code defaultValue} if the type is <jk>null</jk>. 315 */ 316 public static <T> T createOrDefault(Class<T> beanType, T defaultValue) { 317 return beanType == null ? defaultValue : of(beanType).run(); 318 } 319 320 // ========================================================================= 321 // Outer (immutable) wrapper state and methods 322 // ========================================================================= 323 324 private final Builder<T> b; 325 326 BeanInstantiator(Builder<T> b) { 327 this.b = b; 328 } 329 330 /** 331 * Creates the bean. 332 * 333 * <p> 334 * After creating the bean, this method automatically injects dependencies into fields and methods 335 * annotated with {@code @Inject} or {@code @Autowired} using {@link ClassInfo#inject(Object, BeanStore)}. 336 * 337 * @return A new bean with all dependencies injected. 338 * @throws ExecutableException if bean could not be created. 339 */ 340 public T run() { 341 return b.runImpl(); 342 } 343 344 /** 345 * Attempts to create the bean, returning an {@link Optional} instead of throwing an exception on failure. 346 * 347 * @return An {@link Optional} containing the created bean, or {@link Optional#empty()} if creation failed. 348 */ 349 public Optional<T> asOptional() { 350 try { 351 return o(run()); 352 } catch (@SuppressWarnings("unused") ExecutableException e) { 353 return oe(); 354 } 355 } 356 357 /** 358 * Converts this creator into a memoizer. 359 * 360 * @return A resettable supplier that caches the created bean until reset. 361 */ 362 public Memoizer<T> asMemoizer() { 363 return new Memoizer<>(this::run); 364 } 365 366 /** 367 * Converts this creator into a supplier. 368 * 369 * @return A supplier that returns the results of the {@link #run()} method. 370 */ 371 public Supplier<T> asSupplier() { 372 return this::run; 373 } 374 375 /** 376 * Resets the cached bean instance and the inner Builder's resolved memoizers. 377 * 378 * @return This object. 379 */ 380 public BeanInstantiator<T> reset() { 381 b.reset(); 382 return this; 383 } 384 385 /** 386 * Returns the name of the bean being created. 387 * 388 * @return The bean name, or <jk>null</jk> if not set. 389 */ 390 public String getName() { 391 return b.name; 392 } 393 394 /** 395 * Returns the bean subtype class info if specified, or the normal bean type if not. 396 * 397 * @return The bean subtype class info, or the bean type class info if no subtype was specified. 398 */ 399 protected ClassInfo getBeanSubType() { 400 return b.beanSubType; 401 } 402 403 /** 404 * Returns the list of bean subtype classes, including the bean subtype, bean type, and all classes in between. 405 * 406 * @return A list of bean subtype class info objects, never <jk>null</jk>. 407 */ 408 protected List<ClassInfo> getBeanSubTypes() { 409 return b.getBeanSubTypes(); 410 } 411 412 /** 413 * Returns the builder instance if one has been created or specified. 414 * 415 * @param <B> The builder type. 416 * @return The builder instance wrapped in an {@link Optional}, or an empty optional if no builder exists. 417 */ 418 public <B> Optional<B> getBuilder() { 419 return b.getBuilder(); 420 } 421 422 /** 423 * Returns the builder type class info determined by builder type detection. 424 * 425 * @return The builder type class info, or <jk>null</jk> if no builder type was determined. 426 */ 427 protected ClassInfo getBuilderType() { 428 return b.getBuilderType(); 429 } 430 431 /** 432 * Returns the list of builder types, including the primary builder type and any builder types found in the builder's parent hierarchy. 433 * 434 * @return A list of builder type class info objects, never <jk>null</jk>. 435 */ 436 protected List<ClassInfo> getBuilderTypes() { 437 return b.getBuilderTypes(); 438 } 439 440 /** 441 * Returns an unmodifiable list of debug log entries from the last bean creation attempt. 442 * 443 * @return An unmodifiable list of debug log entries. 444 */ 445 public List<String> getDebugLog() { 446 return b.getDebugLog(); 447 } 448 449 // ========================================================================= 450 // Builder (mutable, single-thread configuration) inner class 451 // ========================================================================= 452 453 /** 454 * Builder for {@link BeanInstantiator}. 455 * 456 * <p> 457 * Holds all mutable configuration. Configure on a single thread, then call {@link #build()} to obtain 458 * an immutable {@link BeanInstantiator} suitable for shared concurrent use. Most call sites use the 459 * {@link #run()} shorthand which is equivalent to {@code build().run()}. 460 * 461 * <h5 class='section'>Thread Safety:</h5> 462 * <p> 463 * Builder instances are <b>not</b> thread-safe. Configure on one thread, then either call {@link #build()} 464 * to produce a thread-safe immutable {@link BeanInstantiator}, or call {@link #run()} to one-shot create a 465 * bean from a single thread. 466 * 467 * @param <T> The bean type being created. 468 */ 469 public static class Builder<T> { 470 471 final BeanStore parentStore; 472 final BasicBeanStore store; 473 final ClassInfoTyped<T> beanType; 474 final NullableReference<List<String>> debug = NullableReference.empty(); 475 476 private ClassInfoTyped<? extends T> beanSubType; 477 private ClassInfo explicitBuilderType = null; 478 private Object explicitBuilder = null; 479 private final Object enclosingInstance; 480 private T explicitImplementation = null; 481 private List<Consumer<T>> postCreateHooks = l(); 482 private Set<String> factoryMethodNames = DEFAULT_FACTORY_METHOD_NAMES; 483 private Set<String> builderMethodNames = DEFAULT_BUILDER_METHOD_NAMES; 484 private Set<String> buildMethodNames = DEFAULT_BUILD_METHOD_NAMES; 485 private Set<String> builderClassNames = DEFAULT_BUILDER_CLASS_NAMES; 486 private Supplier<? extends T> fallbackSupplier = null; 487 private final String name; 488 private boolean cached = false; 489 private boolean factoryAbstainOnNull = false; 490 private boolean preferZeroArgConstructor = false; 491 private boolean silent = false; 492 private String description = null; 493 private List<UnaryOperator<T>> wrappers = l(); 494 private List<Validation<T>> validators = l(); 495 private List<Builder<? extends T>> alternatives = l(); 496 private List<Consumer<Object>> builderInitializers = l(); 497 private boolean injectBuilder = false; 498 private boolean autoWireBuilder = false; 499 boolean autoWireUnwrapSuppliers = true; 500 private boolean noBuilder = false; 501 502 private final Memoizer<ClassInfo> builderType = memoizer(() -> findBuilderType()); 503 private final Memoizer<List<ClassInfo>> builderTypes = memoizer(() -> findBuilderTypes()); 504 private final Memoizer<List<ClassInfo>> beanSubTypes = memoizer(() -> findBeanSubTypes()); 505 private final Memoizer<Object> builderMemoizer = memoizer(() -> findBuilder()); 506 private final Memoizer<T> beanImpl = memoizer(() -> processBean(findBeanImpl())); 507 508 /** 509 * Constructor. 510 * 511 * @param beanType The bean type being created. Must not be <jk>null</jk>. 512 * @param parentStore The parent bean store to use for resolving dependencies. Can be <jk>null</jk> (the internal bean store then has no parent fallback). 513 * @param name The bean name. Can be <jk>null</jk> for unnamed beans. 514 * @param enclosingInstance The enclosing instance object. Can be <jk>null</jk> (the outer-instance skip rule is then never applied). 515 */ 516 protected Builder(Class<T> beanType, BeanStore parentStore, String name, Object enclosingInstance) { 517 this.beanType = info(reqnn("beanType", beanType)); 518 this.beanSubType = this.beanType; 519 this.parentStore = parentStore; 520 this.store = new BasicBeanStore(this.parentStore); 521 this.name = name; 522 this.enclosingInstance = enclosingInstance; 523 } 524 525 /** 526 * Adds a bean to the internal bean store and returns it. 527 * 528 * @param <T2> The bean type. 529 * @param type The bean type. Must not be <jk>null</jk>. 530 * @param bean The bean instance. Can be <jk>null</jk> (stored as an explicit <jk>null</jk> binding, distinct from no binding at all). 531 * @return The bean that was added. 532 */ 533 public <T2> T2 add(Class<T2> type, T2 bean) { 534 store.add(type, bean); 535 reset(); 536 return bean; 537 } 538 539 /** 540 * Adds a bean to the internal bean store. 541 * 542 * @param <T2> The bean type. 543 * @param type The bean type. Must not be <jk>null</jk>. 544 * @param bean The bean instance. Can be <jk>null</jk> (stored as an explicit <jk>null</jk> binding, distinct from no binding at all). 545 * @return This object. 546 */ 547 public <T2> Builder<T> addBean(Class<T2> type, T2 bean) { 548 store.add(type, bean); 549 reset(); 550 return this; 551 } 552 553 /** 554 * Adds a named bean to the internal bean store. 555 * 556 * @param <T2> The bean type. 557 * @param type The bean type. Must not be <jk>null</jk>. 558 * @param bean The bean instance. Can be <jk>null</jk> (stored as an explicit <jk>null</jk> binding, distinct from no binding at all). 559 * @param name The bean name. Can be <jk>null</jk> for unnamed beans. 560 * @return This object. 561 */ 562 public <T2> Builder<T> addBean(Class<T2> type, T2 bean, String name) { 563 store.add(type, bean, name); 564 reset(); 565 return this; 566 } 567 568 /** 569 * Attempts to create the bean, returning an {@link Optional} instead of throwing an exception on failure. 570 * 571 * <p> 572 * This is a non-throwing variant of {@link #run()} that wraps the result in an {@link Optional}. 573 * If bean creation fails for any reason (missing dependencies, abstract class, interface, no matching constructor, etc.), 574 * this method returns {@link Optional#empty()} instead of throwing {@link ExecutableException}. 575 * 576 * <p> 577 * This method is useful when bean creation failure is expected and should not be treated as exceptional, 578 * such as when implementing optional features or trying multiple creation strategies. 579 * 580 * <h5 class='section'>Notes:</h5><ul> 581 * <li class='note'>Unlike {@link #run()}, this method catches {@link ExecutableException} and returns empty. 582 * <li class='note'>If a fallback is registered via {@link #fallback(Supplier)}, 583 * it will be used before returning empty, so this method will only return empty if both 584 * normal creation AND fallback fail. 585 * <li class='note'>The created bean is cached via {@link Memoizer}, so subsequent calls return the same instance 586 * unless {@link #reset()} is called or configuration changes. 587 * <li class='note'>Post-creation hooks are still executed if creation succeeds. 588 * <li class='note'>Other exceptions (e.g., from post-creation hooks or fallback suppliers) are NOT caught 589 * and will propagate to the caller. 590 * </ul> 591 * 592 * <h5 class='section'>Example:</h5> 593 * <p class='bjava'> 594 * <jc>// Try to create, use default if it fails</jc> 595 * MyBean <jv>bean</jv> = BeanInstantiator 596 * .<jsm>of</jsm>(MyBean.<jk>class</jk>, <jv>myBeanStore</jv>) 597 * .asOptional() 598 * .orElse(<jk>new</jk> DefaultMyBean()); 599 * 600 * <jc>// Chain multiple creation attempts</jc> 601 * MyService <jv>service</jv> = BeanInstantiator.<jsm>of</jsm>(AdvancedService.<jk>class</jk>, <jv>store</jv>) 602 * .asOptional() 603 * .or(() -> BeanInstantiator.<jsm>of</jsm>(BasicService.<jk>class</jk>, <jv>store</jv>) 604 * .asOptional()) 605 * .orElseGet(() -> <jk>new</jk> FallbackService()); 606 * 607 * <jc>// Check if optional feature is available</jc> 608 * Optional<OptionalFeature> <jv>feature</jv> = BeanInstantiator 609 * .<jsm>of</jsm>(OptionalFeature.<jk>class</jk>, <jv>store</jv>) 610 * .asOptional(); 611 * <jk>if</jk> (<jv>feature</jv>.isPresent()) { 612 * <jv>feature</jv>.get().enable(); 613 * } 614 * </p> 615 * 616 * @return An {@link Optional} containing the created bean, or {@link Optional#empty()} if creation failed. 617 */ 618 public Optional<T> asOptional() { 619 return build().asOptional(); 620 } 621 622 /** 623 * Converts this creator into a memoizer. 624 * 625 * <p> 626 * A {@link Memoizer} caches the result of the first {@link Memoizer#get()} call 627 * and returns that cached value for subsequent calls. The {@link Memoizer#reset()} method 628 * can be used to clear the cache, forcing the bean to be recreated on the next get() call. 629 * 630 * <p> 631 * This is particularly useful when the bean store contents change and you want to recreate the bean 632 * with updated dependencies. 633 * 634 * <h5 class='section'>Notes:</h5><ul> 635 * <li class='note'>The returned {@link Memoizer} is thread-safe. 636 * <li class='note'>Each call to {@link Memoizer#get()} after a reset() will invoke 637 * {@link #run()}, which may trigger dependency injection and post-creation hooks. 638 * <li class='note'>The memoizer inherits all Optional-like methods from {@link NullableSupplier}. 639 * </ul> 640 * 641 * <h5 class='section'>Example:</h5> 642 * <p class='bjava'> 643 * <jc>// Create a memoizer for a bean with dependencies</jc> 644 * BeanStore <jv>store</jv> = <jk>new</jk> BasicBeanStore(<jk>null</jk>); 645 * <jv>store</jv>.addBean(String.<jk>class</jk>, <js>"initial"</js>); 646 * 647 * Memoizer<MyBean> <jv>supplier</jv> = BeanInstantiator 648 * .<jsm>of</jsm>(MyBean.<jk>class</jk>, <jv>store</jv>) 649 * .asMemoizer(); 650 * 651 * <jc>// First call creates and caches the bean</jc> 652 * MyBean <jv>bean1</jv> = <jv>supplier</jv>.get(); 653 * 654 * <jc>// Subsequent calls return the cached bean</jc> 655 * MyBean <jv>bean2</jv> = <jv>supplier</jv>.get(); 656 * <jsm>assertSame</jsm>(<jv>bean1</jv>, <jv>bean2</jv>); 657 * 658 * <jc>// Update the bean store</jc> 659 * <jv>store</jv>.addBean(String.<jk>class</jk>, <js>"updated"</js>); 660 * 661 * <jc>// Reset forces recreation with updated dependencies</jc> 662 * <jv>supplier</jv>.reset(); 663 * MyBean <jv>bean3</jv> = <jv>supplier</jv>.get(); 664 * <jsm>assertNotSame</jsm>(<jv>bean1</jv>, <jv>bean3</jv>); <jc>// New instance with updated deps</jc> 665 * </p> 666 * 667 * @return A resettable supplier that caches the created bean until reset. 668 */ 669 public Memoizer<T> asMemoizer() { 670 return build().asMemoizer(); 671 } 672 673 /** 674 * Converts this creator into a supplier. 675 * 676 * @return A supplier that returns the results of the {@link #run()} method. 677 */ 678 public Supplier<T> asSupplier() { 679 return build().asSupplier(); 680 } 681 682 /** 683 * Specifies a subclass of the bean type to create. 684 * 685 * <p> 686 * This allows you to create a specific implementation when the bean type is an interface, abstract class, 687 * or when you want to instantiate a customized subclass of a concrete class. 688 * 689 * @param value The subclass type to create. Cannot be <jk>null</jk>. Must be a subclass of {@code beanType}. 690 * @return This object. 691 * @throws IllegalArgumentException If value is not a subclass of {@code beanType}. 692 */ 693 public Builder<T> type(Class<? extends T> value) { 694 reqnn("value", value); 695 beanSubType = info(value); 696 req(beanType.isAssignableFrom(beanSubType), "type must be a subclass of beanType. beanType=%s, type=%s", cn(beanType), cn(beanSubType)); 697 reset(); 698 return this; 699 } 700 701 /** 702 * Specifies a subclass of the bean type to create, via a {@link ClassInfo} reference. 703 * 704 * <p> 705 * Convenience overload of {@link #type(Class)} that accepts {@link ClassInfo} (or any subtype such 706 * as {@code ClassMeta}). The underlying class is extracted via {@link ClassInfo#inner()} and the 707 * subtype-relationship check happens at runtime. 708 * 709 * @param value The subclass type to create. Cannot be <jk>null</jk>. 710 * @return This object. 711 * @throws IllegalArgumentException If {@code value} is <jk>null</jk> or its underlying class is not a subclass of {@code beanType}. 712 */ 713 public Builder<T> type(ClassInfo value) { 714 reqnn("value", value); 715 return type((Class<? extends T>) value.inner()); 716 } 717 718 /** 719 * Specifies the builder type to use for creating the bean. 720 * 721 * <p> 722 * This method triggers builder type detection and instantiation for the specified type. 723 * 724 * <p> 725 * The builder type must be valid, meaning it must have a <c>build()</c>, <c>create()</c>, or <c>get()</c> method 726 * that returns the bean type (or a parent of the bean type). The method may have <c>@Inject</c> or <c>@Autowired</c> 727 * annotation to allow injected parameters; otherwise, it must have no parameters. 728 * 729 * <p> 730 * If the builder type is invalid (does not have a valid build method), this method throws an 731 * {@link IllegalArgumentException}. 732 * 733 * <p> 734 * The builder will be instantiated by looking for: 735 * <ol> 736 * <li>A static <c>create()</c> or <c>builder()</c> method that returns the builder type. 737 * <li>A public constructor on the builder type with parameters that can be resolved from the bean store. 738 * <li>A protected constructor on the builder type with parameters that can be resolved from the bean store. 739 * <li>A package-private constructor on the builder type with parameters that can be resolved from the bean store. 740 * Private constructors are deliberately excluded. 741 * </ol> 742 * 743 * @param value The builder type. Cannot be <jk>null</jk>. 744 * @return This object. 745 * @throws IllegalArgumentException If the builder type is invalid (does not have a valid build/create/get method). 746 */ 747 public Builder<T> builder(Class<?> value) { 748 explicitBuilderType = info(reqnn("value", value)); 749 builderType.set(explicitBuilderType); 750 req(isValidBuilderType(explicitBuilderType), "Invalid builder type %1$s for bean type %2$s. Builder must have a build(), create(), or get() method that returns %2$s (or a parent of %2$s). The method may have @Inject annotation to allow injected parameters; otherwise, it must have no parameters.", cn(explicitBuilderType), cn(beanType)); 751 builderTypes.get(); // Triggers validation on type hierarchy. 752 reset(); 753 return this; 754 } 755 756 /** 757 * Specifies an existing builder instance to use for creating the bean. 758 * 759 * <p> 760 * The builder instance's class must be a valid builder type, meaning it must have a <c>build()</c>, <c>create()</c>, 761 * or <c>get()</c> method that returns the bean type (or a parent of the bean type). The method may have 762 * <c>@Inject</c> or <c>@Autowired</c> annotation to allow injected parameters; otherwise, it must have no parameters. 763 * 764 * <p> 765 * If the builder instance's class is invalid (does not have a valid build method), this method throws an 766 * {@link IllegalArgumentException}. 767 * 768 * <h5 class='section'>Notes:</h5><ul> 769 * <li class='note'>When specified, the builder type detection is bypassed. 770 * <li class='note'>The builder will be used to create the bean via: 771 * <ul> 772 * <li>A <c>build()</c>/<c>create()</c>/<c>get()</c> method on the builder (required). 773 * The method may have <c>@Inject</c> annotation to allow injected parameters. 774 * </ul> 775 * <li class='note'>The explicit builder instance is preserved even when {@link #reset()} is called, 776 * unlike cached results from suppliers. 777 * </ul> 778 * 779 * @param value The builder instance. Cannot be <jk>null</jk>. 780 * @return This object. 781 * @throws IllegalArgumentException If the builder instance's class is invalid (does not have a valid build/create/get method). 782 */ 783 public Builder<T> builder(Object value) { 784 builder(value.getClass()); 785 explicitBuilder = reqnn("value", value); 786 reset(); 787 return this; 788 } 789 790 /** 791 * Specifies custom class names to look for when auto-detecting builder inner classes. 792 * 793 * <p> 794 * By default, {@code BeanInstantiator} looks for inner classes named {@code "Builder"}. 795 * This method allows you to specify alternative class names. 796 * 797 * <h5 class='section'>Notes:</h5><ul> 798 * <li class='note'>Inner builder classes must be public, static, and pass builder validation 799 * (have a build/create/get method or be accepted by a bean constructor). 800 * <li class='note'>If multiple inner classes match, the first valid one found will be used. 801 * <li class='note'>This only affects inner class detection. It does not affect builders specified via 802 * {@link #builder(Class)}, {@link #builder(Object)}, or the {@link Builder @Builder} annotation. 803 * <li class='note'>Calling this method replaces the default builder class names. 804 * </ul> 805 * 806 * <h5 class='section'>Example:</h5> 807 * <p class='bjava'> 808 * <jc>// Support alternative builder class naming conventions</jc> 809 * MyBean <jv>bean</jv> = BeanInstantiator 810 * .<jsm>of</jsm>(MyBean.<jk>class</jk>, <jv>myBeanStore</jv>) 811 * .builderClassNames(<js>"BuilderImpl"</js>, <js>"Factory"</js>) 812 * .run(); 813 * </p> 814 * 815 * @param names The builder class names to look for. Cannot be <jk>null</jk> or contain <jk>null</jk> elements. 816 * @return This object. 817 */ 818 public Builder<T> builderClassNames(String... names) { 819 builderClassNames = set(reqnns("names", names)); 820 reset(); 821 return this; 822 } 823 824 /** 825 * Specifies custom method names to look for when auto-detecting builder factory methods. 826 * 827 * <p> 828 * By default, {@code BeanInstantiator} looks for static methods named {@code "create"} or {@code "builder"} 829 * that return a builder type. This method allows you to specify alternative method names. 830 * 831 * <h5 class='section'>Notes:</h5><ul> 832 * <li class='note'>Builder factory methods must be public, static, non-deprecated, and return a builder type 833 * (not the bean type itself). 834 * <li class='note'>If multiple builder factory methods match, the one with the most parameters that can be 835 * resolved from the bean store will be used. 836 * <li class='note'>This affects both builder type detection and builder instance creation. 837 * <li class='note'>Calling this method replaces the default builder method names. 838 * </ul> 839 * 840 * <h5 class='section'>Example:</h5> 841 * <p class='bjava'> 842 * <jc>// Support alternative builder factory method naming conventions</jc> 843 * MyBean <jv>bean</jv> = BeanInstantiator 844 * .<jsm>of</jsm>(MyBean.<jk>class</jk>) 845 * .builderMethodNames(<js>"newBuilder"</js>, <js>"instance"</js>) 846 .run(); 847 * </p> 848 * 849 * @param names The builder factory method names to look for. Cannot be <jk>null</jk> or contain <jk>null</jk> elements. 850 * @return This object. 851 */ 852 public Builder<T> builderMethodNames(String... names) { 853 builderMethodNames = set(reqnns("names", names)); 854 reset(); 855 return this; 856 } 857 858 /** 859 * Specifies custom method names to look for when calling build methods on builder instances. 860 * 861 * <p> 862 * By default, {@code BeanInstantiator} looks for instance methods named {@code "build"}, {@code "create"}, or {@code "get"} 863 * on the builder that return the bean type. This method allows you to specify alternative method names. 864 * 865 * <h5 class='section'>Notes:</h5><ul> 866 * <li class='note'>Build methods must be public, non-static, non-deprecated, and return the bean type 867 * (or a parent type of the bean type). 868 * <li class='note'>If the method has {@code @Inject} or {@code @Autowired} annotation, its parameters are resolved from the bean store. 869 * <li class='note'>If the method does not have {@code @Inject} annotation, it must have no parameters. 870 * <li class='note'>Calling this method replaces the default build method names. 871 * </ul> 872 * 873 * <h5 class='section'>Example:</h5> 874 * <p class='bjava'> 875 * <jc>// Support alternative build method naming conventions</jc> 876 * MyBean <jv>bean</jv> = BeanInstantiator 877 * .<jsm>of</jsm>(MyBean.<jk>class</jk>) 878 * .buildMethodNames(<js>"execute"</js>, <js>"make"</js>) 879 .run(); 880 * </p> 881 * 882 * @param names The build method names to look for. Cannot be <jk>null</jk> or contain <jk>null</jk> elements. 883 * @return This object. 884 */ 885 public Builder<T> buildMethodNames(String... names) { 886 buildMethodNames = set(reqnns("names", names)); 887 reset(); 888 return this; 889 } 890 891 /** 892 * Enables caching mode. 893 * 894 * <p> 895 * When caching mode is enabled, bean instances are cached using {@link Memoizer}, 896 * so multiple calls to {@link #run()} will return the same instance unless {@link #reset()} is called 897 * or configuration changes. 898 * 899 * <p> 900 * When caching mode is disabled (the default), each call to {@link #run()} will create a new bean instance 901 * by calling {@link #findBeanImpl()} directly. 902 * 903 * <h5 class='section'>Example:</h5> 904 * <p class='bjava'> 905 * <jc>// Enable caching mode - same instance returned on each run()</jc> 906 * <jk>var</jk> <jv>creator</jv> = BeanInstantiator 907 * .<jsm>of</jsm>(MyBean.<jk>class</jk>) 908 * .<jsm>cached</jsm>(); 909 * MyBean <jv>bean1</jv> = <jv>creator</jv>.<jsm>run</jsm>(); 910 * MyBean <jv>bean2</jv> = <jv>creator</jv>.<jsm>run</jsm>(); 911 * <jc>// bean1 and bean2 are the same instance</jc> 912 * </p> 913 * 914 * @return This object. 915 */ 916 public Builder<T> cached() { 917 cached = true; 918 return this; 919 } 920 921 /** 922 * Treat a {@code null} return value from a static factory method as a deliberate "abstain" signal. 923 * 924 * <p> 925 * By default, when a static factory method (one of {@link #factoryMethodNames(String...)}) matches and is 926 * invoked, but returns {@code null}, {@link #run()} falls through to constructor lookup as if the factory 927 * method weren't there. This works well when the factory method is just an alternate construction path. 928 * 929 * <p> 930 * Some factory-method patterns instead use a {@code null} return value as a deliberate "this implementation 931 * does not handle the input — try the next strategy" signal, expecting the caller to interpret the {@code null} 932 * as a definitive answer. The classic example is a {@code RestOpArg} subclass whose 933 * {@code static create(ParameterInfo)} returns {@code null} when the parameter isn't annotated with the 934 * marker the subclass handles, so the caller can move on to the next subclass in the chain. Falling through 935 * to the (always-present) constructor in that case would silently materialize an arg that doesn't apply. 936 * 937 * <p> 938 * When this flag is enabled, a {@code null} return from the matching factory method is propagated out of 939 * {@link #run()} unchanged — constructor lookup is skipped. This matches legacy {@code BeanCreator} 940 * semantics for static {@code create()} / {@code builder()} / {@code getInstance()} methods. 941 * 942 * <h5 class='section'>Example:</h5> 943 * <p class='bjava'> 944 * <jc>// AttributeArg.create(ParameterInfo) returns null if @Attr is not present.</jc> 945 * <jc>// Without factoryAbstainOnNull, BeanInstantiator would then invoke the AttributeArg(ParameterInfo)</jc> 946 * <jc>// constructor and return a bogus instance.</jc> 947 * RestOpArg <jv>arg</jv> = BeanInstantiator 948 * .<jsm>of</jsm>(RestOpArg.<jk>class</jk>, <jv>store</jv>) 949 * .type(AttributeArg.<jk>class</jk>) 950 * .factoryMethodNames(<js>"getInstance"</js>, <js>"create"</js>) 951 * .factoryAbstainOnNull() 952 * .run(); 953 * </p> 954 * 955 * @return This object. 956 */ 957 public Builder<T> factoryAbstainOnNull() { 958 factoryAbstainOnNull = true; 959 return this; 960 } 961 962 /** 963 * Prefer a zero-argument constructor when one exists, instead of injecting via the longest constructor. 964 * 965 * <p> 966 * By default, {@code BeanInstantiator} sorts public constructors by parameter count <i>descending</i>: the 967 * constructor with the most resolvable parameters wins, encouraging full constructor injection. This is the 968 * right default for most beans, but it doesn't fit every use case. 969 * 970 * <p> 971 * The classic mismatch is parameterized container types like {@link TreeMap}, which expose: 972 * <ul> 973 * <li>{@code TreeMap()} 974 * <li>{@code TreeMap(Comparator)} 975 * <li>{@code TreeMap(Map<? extends K,? extends V>)} 976 * <li>{@code TreeMap(SortedMap)} 977 * </ul> 978 * The default selection picks the {@code Map} copy-constructor — but that {@code Map<? extends K,? extends V>} 979 * parameter doesn't satisfy v2 inject-collection auto-resolution (which only handles {@code Map<String,T>}), 980 * so injection fails at runtime even though {@link ParameterInfo#canResolve(BeanStore, Object...)} optimistically 981 * said yes. Callers that just want "give me a fresh empty container" should use this flag. 982 * 983 * <p> 984 * When this flag is enabled, if {@code beanSubType} declares a public no-arg constructor, that constructor is 985 * used unconditionally and other constructors are ignored. This matches legacy {@code BeanCreator} behavior for 986 * the same use case (legacy filtered out the multi-arg ctors via {@code hasAllParams} returning false, since the 987 * legacy bean store didn't auto-resolve raw {@code Map}/{@code Collection} parameter types). 988 * 989 * <h5 class='section'>Example:</h5> 990 * <p class='bjava'> 991 * <jc>// Instantiating an arbitrary Map subclass — prefer the no-arg ctor over copy-ctors.</jc> 992 * Map<?,?> <jv>m</jv> = BeanInstantiator 993 * .<jsm>of</jsm>(Map.<jk>class</jk>) 994 * .type(treeMapClass) 995 * .preferZeroArgConstructor() 996 * .run(); 997 * </p> 998 * 999 * @return This object. 1000 */ 1001 public Builder<T> preferZeroArgConstructor() { 1002 preferZeroArgConstructor = true; 1003 return this; 1004 } 1005 1006 /** 1007 * Compiles this builder into a {@link BeanInstantiator}. 1008 * 1009 * <p> 1010 * The returned instance exposes only run/read methods (no setters). The compiled instance shares 1011 * its caching state with this builder so that {@link #cached()} memoization is consistent across 1012 * both compiled and shorthand call paths. 1013 * 1014 * @return A new {@link BeanInstantiator} backed by this builder's configuration. 1015 */ 1016 public BeanInstantiator<T> build() { 1017 return new BeanInstantiator<>(this); 1018 } 1019 1020 /** 1021 * Shortcut for {@code build().run()}. 1022 * 1023 * <p> 1024 * Most call sites do not store the {@link BeanInstantiator} and therefore call this shortcut. 1025 * Repeated calls share caching with any compiled {@link BeanInstantiator} produced by {@link #build()}. 1026 * 1027 * @return A new bean with all dependencies injected. 1028 * @throws ExecutableException if bean could not be created. 1029 */ 1030 public T run() { 1031 return runImpl(); 1032 } 1033 1034 T runImpl() { 1035 debug.ifPresent(x -> x.clear()); 1036 1037 try { 1038 return runImplOnce(); 1039 } catch (RuntimeException e) { 1040 if (alternatives.isEmpty()) 1041 throw e; 1042 for (var alt : alternatives) { 1043 try { 1044 return processBean(alt.runImpl()); 1045 } catch (@SuppressWarnings("unused") RuntimeException ignored) { 1046 // Try next alternative 1047 } 1048 } 1049 throw e; 1050 } 1051 } 1052 1053 private T runImplOnce() { 1054 if (neq(beanSubType, beanType)) 1055 log("Subtype specified: %s", beanSubType.getName()); 1056 1057 if (explicitImplementation != null) { 1058 log("Using pre-configured impl() instance"); 1059 return processBean(runPostCreateHooks(inject(explicitImplementation))); 1060 } 1061 1062 if (cached) { 1063 log("Using cached instance"); 1064 return beanImpl.get(); 1065 } 1066 1067 log("Using new instance"); 1068 return processBean(findBeanImpl()); 1069 } 1070 1071 private T processBean(T bean) { 1072 for (var w : wrappers) 1073 bean = w.apply(bean); 1074 for (var v : validators) { 1075 if (! v.predicate().test(bean)) 1076 throw new ExecutableException(v.message() + " (bean=" + bean + ")"); 1077 } 1078 return bean; 1079 } 1080 1081 /** 1082 * Enables debug mode to track the bean creation process. 1083 * 1084 * <p> 1085 * When debug mode is enabled, the creator logs each step of the bean creation process 1086 * to an internal list. This log can be retrieved via {@link #getDebugLog()} to understand 1087 * which creation path was taken, why creation might have failed, or to troubleshoot 1088 * unexpected behavior. 1089 * 1090 * <h5 class='section'>Notes:</h5><ul> 1091 * <li class='note'>Debug logs include: builder detection, factory method attempts, constructor attempts, 1092 * dependency resolution, injection, hooks execution, validation, and fallback usage. 1093 * <li class='note'>The debug log is reset each time {@link #run()} or {@link #asOptional()} is called. 1094 * <li class='note'>Debug mode has minimal performance impact but should generally be disabled in production. 1095 * <li class='note'>The debug log is stored in memory and can be retrieved after bean creation. 1096 * <li class='note'>When caching is enabled via {@link #cached()}, the log reflects the first creation only 1097 * (subsequent calls return the cached instance unless {@link #reset()} is called). 1098 * </ul> 1099 * 1100 * <h5 class='section'>Example:</h5> 1101 * <p class='bjava'> 1102 * <jc>// Enable debug mode</jc> 1103 * <jk>var</jk> <jv>creator</jv> = BeanInstantiator 1104 * .<jsm>of</jsm>(MyBean.<jk>class</jk>, <jv>store</jv>) 1105 * .debug(); 1106 * 1107 * MyBean <jv>bean</jv> = <jv>creator</jv>.run(); 1108 * 1109 * <jc>// Print debug log</jc> 1110 * <jv>creator</jv>.getDebugLog().forEach(System.<jf>out</jf>::println); 1111 * </p> 1112 * 1113 * @return This object. 1114 */ 1115 public Builder<T> debug() { 1116 debug.set(synchronizedList(new ArrayList<>())); 1117 return this; 1118 } 1119 1120 1121 /** 1122 * Specifies custom static factory method names to look for when creating the bean. 1123 * 1124 * <p> 1125 * By default, {@link BeanInstantiator} looks for a static {@code getInstance()} method when attempting 1126 * to create beans without a builder. This method allows you to specify alternative 1127 * factory method names to support non-standard naming conventions. 1128 * 1129 * <h5 class='section'>Notes:</h5><ul> 1130 * <li class='note'>Factory methods must be public, static, non-deprecated, and return the bean type. 1131 * <li class='note'>If multiple factory methods match, the one with the most parameters that can be 1132 * resolved from the bean store will be used. 1133 * <li class='note'>Factory methods are attempted before constructors in the bean creation order. 1134 * <li class='note'>This setting only affects factory method detection; it does not affect builder detection. 1135 * <li class='note'>Calling this method replaces the default factory method names. 1136 * </ul> 1137 * 1138 * <h5 class='section'>Example:</h5> 1139 * <p class='bjava'> 1140 * <jc>// Support multiple factory method naming conventions</jc> 1141 * MyBean <jv>bean</jv> = BeanInstantiator 1142 * .<jsm>of</jsm>(MyBean.<jk>class</jk>, <jv>myBeanStore</jv>) 1143 * .factoryMethodNames(<js>"of"</js>, <js>"from"</js>, <js>"create"</js>, <js>"newInstance"</js>) 1144 * .run(); 1145 * </p> 1146 * 1147 * @param names The factory method names to look for. Cannot be <jk>null</jk> or contain <jk>null</jk> elements. 1148 * @return This object. 1149 */ 1150 public Builder<T> factoryMethodNames(String... names) { 1151 factoryMethodNames = set(reqnns("names", names)); 1152 reset(); 1153 return this; 1154 } 1155 1156 /** 1157 * Specifies a fallback supplier to use if bean creation fails. 1158 * 1159 * <p> 1160 * When a fallback supplier is registered, if bean creation fails (throws {@link ExecutableException}), 1161 * instead of propagating the exception, the fallback supplier will be invoked to provide a default instance. 1162 * 1163 * <p> 1164 * This enables graceful degradation when bean creation cannot succeed, such as when optional features 1165 * or dependencies are not available. 1166 * 1167 * <h5 class='section'>Notes:</h5><ul> 1168 * <li class='note'>The fallback supplier is only invoked if bean creation fails. 1169 * If bean creation succeeds normally, the fallback is never called. 1170 * <li class='note'>Fallbacks are checked after all normal creation attempts (builders, factory methods, constructors). 1171 * <li class='note'>The fallback-provided instance will have post-creation hooks executed on it. 1172 * <li class='note'>If the fallback is used, that instance is cached via {@link Memoizer} and returned on subsequent calls 1173 * unless {@link #reset()} is called or configuration changes. 1174 * <li class='note'>Only one fallback can be registered. Subsequent calls to this method will replace 1175 * the previous fallback. 1176 * <li class='note'>If the fallback supplier itself throws an exception, that exception will propagate to the caller. 1177 * <li class='note'>To use a pre-created instance as a fallback, wrap it in a supplier: <c>fallback(() -> myInstance)</c>. 1178 * </ul> 1179 * 1180 * <h5 class='section'>Example:</h5> 1181 * <p class='bjava'> 1182 * <jc>// Provide a default instance if creation fails</jc> 1183 * MyService <jv>service</jv> = BeanInstantiator 1184 * .<jsm>of</jsm>(MyService.<jk>class</jk>, <jv>myBeanStore</jv>) 1185 * .fallback(() -> <jk>new</jk> DefaultMyService()) 1186 * .run(); 1187 * 1188 * <jc>// Use a pre-created instance as fallback</jc> 1189 * MyService <jv>defaultService</jv> = <jk>new</jk> DefaultMyService(); 1190 * MyService <jv>service2</jv> = BeanInstantiator 1191 * .<jsm>of</jsm>(MyService.<jk>class</jk>, <jv>myBeanStore</jv>) 1192 * .fallback(() -> <jv>defaultService</jv>) 1193 * .run(); 1194 * </p> 1195 * 1196 * @param fallback The fallback supplier. Cannot be <jk>null</jk>. 1197 * @return This object. 1198 */ 1199 public Builder<T> fallback(Supplier<? extends T> fallback) { 1200 reqnn("fallback", fallback); 1201 this.fallbackSupplier = fallback; 1202 return this; 1203 } 1204 1205 /** 1206 * Returns the bean subtype class info if specified, or the normal bean type if not. 1207 * 1208 * <p> 1209 * If {@link #type(Class)} was called to specify a subtype, returns that subtype. 1210 * Otherwise, returns the original bean type passed to {@link #of(Class)}. 1211 * 1212 * @return The bean subtype class info, or the bean type class info if no subtype was specified. 1213 */ 1214 protected ClassInfo getBeanSubType() { 1215 return beanSubType; 1216 } 1217 1218 /** 1219 * Returns the name of the bean being created. 1220 * 1221 * <p> 1222 * Returns the name that was passed to {@link #of(Class, BeanStore, String, Object)}, or <jk>null</jk> if no name was specified. 1223 * 1224 * @return The bean name, or <jk>null</jk> if not set. 1225 */ 1226 public String getName() { 1227 return name; 1228 } 1229 1230 /** 1231 * Returns the list of bean subtype classes, including the bean subtype, bean type, and all classes in between. 1232 * 1233 * <p> 1234 * This method returns a list that starts with the bean subtype (if different from bean type) and includes 1235 * all parent classes up to and including the bean type. If no subtype was specified, the list will contain 1236 * only the bean type. 1237 * 1238 * <h5 class='section'>Example:</h5> 1239 * <p class='bjava'> 1240 * <jc>// If beanType is A and beanSubType is C (extends B extends A)</jc> 1241 * <jc>// getBeanSubTypes() returns: [C, B, A]</jc> 1242 * </p> 1243 * 1244 * @return A list of bean subtype class info objects, never <jk>null</jk>. 1245 */ 1246 protected List<ClassInfo> getBeanSubTypes() { 1247 return beanSubTypes.get(); 1248 } 1249 1250 /** 1251 * Returns the builder instance if one has been created or specified. 1252 * 1253 * @param <B> The builder type. 1254 * @return The builder instance wrapped in an {@link Optional}, or an empty optional if no builder exists. 1255 */ 1256 public <B> Optional<B> getBuilder() { 1257 beanImpl.reset(); 1258 return (Optional<B>)builderMemoizer.toOptional(); 1259 } 1260 1261 /** 1262 * Returns the builder type class info determined by {@link #findBuilderType()}. 1263 * 1264 * @return The builder type class info, or <jk>null</jk> if no builder type was determined. 1265 */ 1266 protected ClassInfo getBuilderType() { 1267 return builderType.get(); 1268 } 1269 1270 /** 1271 * Returns the list of builder types, including the primary builder type and any builder types found in the builder's parent hierarchy. 1272 * 1273 * <p> 1274 * This method returns a list that includes the primary builder type and all builder types found by traversing 1275 * the builder's parent hierarchy. This allows parent builders to be resolved as injectable types. 1276 * 1277 * <h5 class='section'>Example:</h5> 1278 * <p class='bjava'> 1279 * <jc>// Class A with builder</jc> 1280 * <jk>class</jk> A { 1281 * <jk>static class</jk> Builder { 1282 * A create() { <jk>return new</jk> A(); } 1283 * } 1284 * } 1285 * 1286 * <jc>// Class B extends A with builder</jc> 1287 * <jk>class</jk> B <jk>extends</jk> A { 1288 * <jk>static class</jk> Builder <jk>extends</jk> A.Builder { 1289 * B create() { <jk>return new</jk> B(); } 1290 * } 1291 * } 1292 * 1293 * <jc>// When creating B, getBuilderTypes() returns: [B.Builder, A.Builder]</jc> 1294 * </p> 1295 * 1296 * @return A list of builder type class info objects, never <jk>null</jk>. 1297 */ 1298 protected List<ClassInfo> getBuilderTypes() { 1299 return builderTypes.get(); 1300 } 1301 1302 /** 1303 * Returns an unmodifiable list of debug log entries from the last bean creation attempt. 1304 * 1305 * <p> 1306 * This method returns the detailed log of steps taken during the most recent call to 1307 * {@link #run()} or {@link #asOptional()}. The log is only populated when {@link #debug()} 1308 * mode is enabled. 1309 * 1310 * <h5 class='section'>Notes:</h5><ul> 1311 * <li class='note'>Returns an empty list if {@link #debug()} was not called or if no creation has been attempted. 1312 * <li class='note'>The log is reset at the beginning of each {@link #run()} call. 1313 * <li class='note'>Since {@link #run()} uses a cached {@link Memoizer}, the log reflects only the first creation 1314 * (subsequent calls return the cached instance unless {@link #reset()} is called). 1315 * <li class='note'>The returned list is unmodifiable. 1316 * </ul> 1317 * 1318 * <h5 class='section'>Example:</h5> 1319 * <p class='bjava'> 1320 * <jk>var</jk> <jv>creator</jv> = BeanInstantiator.<jsm>of</jsm>(MyBean.<jk>class</jk>, <jv>store</jv>) 1321 * .debug(); 1322 * 1323 * <jk>try</jk> { 1324 <jv>creator</jv>.run(); 1325 * } <jk>catch</jk> (ExecutableException <jv>e</jv>) { 1326 * <jc>// Print debug log to understand why creation failed</jc> 1327 * <jv>creator</jv>.getDebugLog().forEach(System.<jf>err</jf>::println); 1328 * } 1329 * </p> 1330 * 1331 * @return An unmodifiable list of debug log entries. 1332 */ 1333 public List<String> getDebugLog() { 1334 return debug.map(x -> u(cp(debug.get()))).orElse(emptyList()); 1335 } 1336 1337 /** 1338 * Specifies an existing bean implementation to use instead of creating a new instance. 1339 * 1340 * <p> 1341 * When specified, the bean creation logic is bypassed and this implementation is returned 1342 * directly from {@link #run()}, after performing dependency injection on it. 1343 * 1344 * <h5 class='section'>Notes:</h5><ul> 1345 * <li class='note'>The bean implementation will still have its fields and methods injected via {@link ClassInfo#inject(Object, BeanStore)}. 1346 * <li class='note'>This is useful when you want to provide a pre-configured instance but still benefit from dependency injection. 1347 * <li class='note'>The explicit implementation is preserved even when {@link #reset()} is called, unlike cached results from suppliers. 1348 * </ul> 1349 * 1350 * @param value The bean implementation instance. Can be <jk>null</jk>, in which case no explicit implementation is used. 1351 * @return This object. 1352 */ 1353 public Builder<T> impl(T value) { 1354 this.explicitImplementation = value; 1355 return this; 1356 } 1357 1358 /** 1359 * Registers a post-creation hook to run after the bean is created. 1360 * 1361 * <p> 1362 * Post-creation hooks are executed after the bean is instantiated and after dependency injection 1363 * has been performed via {@link ClassInfo#inject(Object, BeanStore)}. 1364 * 1365 * <p> 1366 * Multiple hooks can be registered and they will be executed in the order they were added. 1367 * 1368 * <h5 class='section'>Notes:</h5><ul> 1369 * <li class='note'>Hooks are executed every time {@link #run()} is called. Since {@link #run()} uses a cached 1370 * {@link Memoizer}, hooks are only executed once unless {@link #reset()} is called. 1371 * <li class='note'>Hooks are executed after dependency injection, so all {@code @Inject} fields and methods 1372 * will have been populated before the hook runs. 1373 * <li class='note'>Hooks can be used for custom initialization logic, logging, wrapping beans with proxies, 1374 * or any other post-creation processing. 1375 * <li class='note'>If a hook throws an exception, bean creation will fail and the exception will propagate to the caller. 1376 * <li class='note'>The hook receives the fully initialized bean instance as its parameter. 1377 * </ul> 1378 * 1379 * <h5 class='section'>Example:</h5> 1380 * <p class='bjava'> 1381 * <jc>// Register multiple post-creation hooks</jc> 1382 * MyService <jv>service</jv> = BeanInstantiator 1383 * .<jsm>of</jsm>(MyService.<jk>class</jk>, <jv>myBeanStore</jv>) 1384 * .postCreateHook(<jv>s</jv> -> <jv>s</jv>.initialize()) 1385 * .postCreateHook(<jv>s</jv> -> <jv>s</jv>.loadConfiguration()) 1386 * .postCreateHook(<jv>s</jv> -> <jv>logger</jv>.info(<js>"Created service: "</js> + <jv>s</jv>)) 1387 .run(); 1388 * </p> 1389 * 1390 * @param hook The post-creation hook to run after bean creation. Cannot be <jk>null</jk>. 1391 * @return This object. 1392 */ 1393 public Builder<T> postCreateHook(Consumer<T> hook) { 1394 reqnn("hook", hook); 1395 postCreateHooks.add(hook); 1396 return this; 1397 } 1398 1399 /** 1400 * Suppresses warning-level log output from this builder. 1401 * 1402 * <p> 1403 * Useful when {@link #asOptional()} is preferred and you don't want the underlying log noise that 1404 * accompanies fallback or factory-abstention paths. 1405 * 1406 * <p> 1407 * Errors and exceptions are still thrown normally; only descriptive log entries are suppressed. 1408 * 1409 * @return This object. 1410 */ 1411 public Builder<T> silent() { 1412 silent = true; 1413 return this; 1414 } 1415 1416 /** 1417 * Sets a human-readable description used in log entries and error messages. 1418 * 1419 * <p> 1420 * Useful when the bean type alone doesn't provide enough context (e.g. multiple instances of the same type). 1421 * 1422 * @param value The description. Cannot be <jk>null</jk>. 1423 * @return This object. 1424 */ 1425 public Builder<T> description(String value) { 1426 reqnn("value", value); 1427 description = value; 1428 return this; 1429 } 1430 1431 /** 1432 * Registers a transformation to apply to the created bean before it is returned. 1433 * 1434 * <p> 1435 * Multiple wrappers may be registered; they are applied in registration order. Each wrapper receives 1436 * the output of the previous wrapper. 1437 * 1438 * <h5 class='section'>Example:</h5> 1439 * <p class='bjava'> 1440 * BeanInstantiator.<jsm>of</jsm>(MyService.<jk>class</jk>, store) 1441 * .wrap(LoggingProxy::wrap) 1442 * .wrap(MetricsProxy::wrap) 1443 * .run(); 1444 * </p> 1445 * 1446 * @param wrapper The wrapper. Cannot be <jk>null</jk>. 1447 * @return This object. 1448 */ 1449 public Builder<T> wrap(UnaryOperator<T> wrapper) { 1450 reqnn("value", wrapper); 1451 wrappers.add(wrapper); 1452 return this; 1453 } 1454 1455 /** 1456 * Registers a post-creation validator. 1457 * 1458 * <p> 1459 * The predicate is invoked on the created bean. If it returns <jk>false</jk>, an 1460 * {@link ExecutableException} is thrown with the supplied message. 1461 * 1462 * @param predicate The predicate. Cannot be <jk>null</jk>. 1463 * @param message The error message used when the predicate returns <jk>false</jk>. Cannot be <jk>null</jk>. 1464 * @return This object. 1465 */ 1466 public Builder<T> validate(Predicate<T> predicate, String message) { 1467 reqnn("value", predicate); 1468 reqnn("value", message); 1469 validators.add(new Validation<>(predicate, message)); 1470 return this; 1471 } 1472 1473 /** 1474 * Registers an alternative {@link BeanInstantiator.Builder} to consult if this builder fails to create the bean. 1475 * 1476 * <p> 1477 * Multiple alternatives may be registered. They are tried in registration order. The first one that 1478 * succeeds returns its bean; if all fail, the last exception is propagated. 1479 * 1480 * @param alternative The alternative builder. Cannot be <jk>null</jk>. 1481 * @return This object. 1482 */ 1483 public Builder<T> or(Builder<? extends T> alternative) { 1484 reqnn("value", alternative); 1485 alternatives.add(alternative); 1486 return this; 1487 } 1488 1489 /** 1490 * Registers a callback that is invoked on the builder instance before {@code build()} is called. 1491 * 1492 * <p> 1493 * Multiple initializers may be registered; they are applied in registration order. The callback 1494 * receives the builder instance after it has been retrieved (from the bean store, static factory, 1495 * or constructor) but before any auto-wiring or {@link #injectBuilder() inject-based} processing. 1496 * 1497 * <p> 1498 * The callback is typed as {@code Consumer<Object>} because the builder type is generally not 1499 * statically known at the call site (an unchecked cast will typically be required inside the 1500 * lambda). 1501 * 1502 * @param initializer The initializer. Cannot be <jk>null</jk>. 1503 * @return This object. 1504 */ 1505 public Builder<T> builderInitializer(Consumer<Object> initializer) { 1506 reqnn("value", initializer); 1507 builderInitializers.add(initializer); 1508 return this; 1509 } 1510 1511 /** 1512 * Enables {@code @Inject} / {@code @Autowired} field and method injection on the builder instance. 1513 * 1514 * <p> 1515 * When set, after the builder is retrieved (from the bean store, static factory, or constructor), 1516 * its fields and methods annotated with {@code @Inject} or {@code @Autowired} are auto-resolved 1517 * from the bean store. This is similar to the post-construction injection performed on the 1518 * resulting bean, but applied to the builder. 1519 * 1520 * <p> 1521 * Default is <jk>false</jk> (opt-in). 1522 * 1523 * @return This object. 1524 */ 1525 public Builder<T> injectBuilder() { 1526 injectBuilder = true; 1527 return this; 1528 } 1529 1530 /** 1531 * Enables auto-wiring of bean store entries into matching setter methods on the builder. 1532 * 1533 * <p> 1534 * When set, after the builder is retrieved, every public single-argument setter method is 1535 * inspected. If the bean store has a bean of a type assignable to the setter's parameter type, 1536 * the setter is invoked with that bean. 1537 * 1538 * <p> 1539 * If a parameter is of type {@code Supplier<X>} and the bean store has a bean of type {@code X}, 1540 * the bean is wrapped in a supplier and passed to the setter (when {@code unwrapSuppliers} 1541 * defaulting to true). 1542 * 1543 * <p> 1544 * Default is <jk>false</jk> (opt-in). 1545 * 1546 * @return This object. 1547 */ 1548 public Builder<T> autoWireBuilder() { 1549 autoWireBuilder = true; 1550 return this; 1551 } 1552 1553 /** 1554 * Disables builder-based bean creation entirely. 1555 * 1556 * <p> 1557 * When set, builder detection is skipped and the bean is instantiated directly via static factory 1558 * methods or constructors. This is useful when a Builder class is co-located with the bean type 1559 * (e.g. {@code Foo.Builder}) but the caller wants to use a builder-taking constructor instead. 1560 * 1561 * <h5 class='section'>Example:</h5> 1562 * <p class='bjava'> 1563 * BeanInstantiator.<jsm>of</jsm>(BasicSwaggerProvider.<jk>class</jk>, beanStore) 1564 * .add(SwaggerProvider.Builder.<jk>class</jk>, <jv>this</jv>) 1565 * .noBuilder() 1566 * .run(); 1567 * </p> 1568 * 1569 * @return This object. 1570 */ 1571 public Builder<T> noBuilder() { 1572 noBuilder = true; 1573 return this; 1574 } 1575 1576 /** 1577 * Sets the lifecycle scope of the bean being created. 1578 * 1579 * <p> 1580 * {@link Scope#SINGLETON} is equivalent to calling {@link #cached()}; 1581 * {@link Scope#PROTOTYPE} resets the cached flag. 1582 * 1583 * @param value The scope. Cannot be <jk>null</jk>. 1584 * @return This object. 1585 */ 1586 public Builder<T> scope(Scope value) { 1587 reqnn("value", value); 1588 cached = (value == Scope.SINGLETON); 1589 return this; 1590 } 1591 1592 /** 1593 * Returns a copy of this builder with the same configuration. 1594 * 1595 * <p> 1596 * The returned builder shares no mutable state with this one and may be configured independently. 1597 * 1598 * @return A new builder pre-populated with this builder's configuration. 1599 */ 1600 public Builder<T> copy() { 1601 var c = new Builder<T>(beanType.inner(), parentStore, name, enclosingInstance); 1602 c.beanSubType = beanSubType; 1603 c.explicitBuilderType = explicitBuilderType; 1604 c.explicitBuilder = explicitBuilder; 1605 c.explicitImplementation = explicitImplementation; 1606 c.postCreateHooks = new ArrayList<>(postCreateHooks); 1607 c.factoryMethodNames = factoryMethodNames; 1608 c.builderMethodNames = builderMethodNames; 1609 c.buildMethodNames = buildMethodNames; 1610 c.builderClassNames = builderClassNames; 1611 c.fallbackSupplier = fallbackSupplier; 1612 c.cached = cached; 1613 c.factoryAbstainOnNull = factoryAbstainOnNull; 1614 c.preferZeroArgConstructor = preferZeroArgConstructor; 1615 c.silent = silent; 1616 c.description = description; 1617 c.wrappers = new ArrayList<>(wrappers); 1618 c.validators = new ArrayList<>(validators); 1619 c.alternatives = new ArrayList<>(alternatives); 1620 c.builderInitializers = new ArrayList<>(builderInitializers); 1621 c.injectBuilder = injectBuilder; 1622 c.autoWireBuilder = autoWireBuilder; 1623 c.autoWireUnwrapSuppliers = autoWireUnwrapSuppliers; 1624 c.noBuilder = noBuilder; 1625 debug.ifPresent(x -> c.debug.set(l())); 1626 return c; 1627 } 1628 1629 /** 1630 * Holds a single validator predicate plus its error message. 1631 */ 1632 private static record Validation<T>(Predicate<T> predicate, String message) {} 1633 1634 /** 1635 * Resets the builder, builderType, and beanImpl suppliers. 1636 * 1637 * <p> 1638 * This causes them to be re-evaluated on the next call to {@link #run()}. 1639 * 1640 * <h5 class='section'>Notes:</h5><ul> 1641 * <li class='note'>If an explicit builder instance was set via {@link #builder(Object)}, 1642 * it is preserved and not cleared by this method. 1643 * <li class='note'>If an explicit implementation was set via {@link #impl(Object)}, 1644 * it is preserved and not cleared by this method. 1645 * <li class='note'>Only the cached results from suppliers are reset, not the configuration itself. 1646 * </ul> 1647 * 1648 * @return This object. 1649 */ 1650 public Builder<T> reset() { 1651 if (explicitBuilder == null) { 1652 builderMemoizer.reset(); 1653 } 1654 builderType.reset(); 1655 if (explicitImplementation == null) { 1656 beanImpl.reset(); 1657 } 1658 return this; 1659 } 1660 1661 /** 1662 * Finds and creates the bean implementation. 1663 * 1664 * <p> 1665 * This method contains all the logic for creating beans via builders, factory methods, constructors, or fallbacks. 1666 * 1667 * @return The created bean. 1668 * @throws ExecutableException if bean could not be created. 1669 */ 1670 private T findBeanImpl() { 1671 var store2 = this.store; 1672 var builder2 = explicitBuilder != null ? explicitBuilder : this.builderMemoizer.get(); // Use explicit builder if set, otherwise get from supplier 1673 T bean = null; 1674 var methodComparator = comparing(MethodInfo::getParameterCount).reversed(); 1675 var constructorComparator = comparing(ConstructorInfo::getParameterCount).reversed(); 1676 1677 boolean builderAttempted = false; 1678 if (builder2 != null) { 1679 log("Builder detected: %s", cn(builder2)); 1680 1681 // Initialization hooks: builder initializers, then optional inject, then optional auto-wire. 1682 for (var init : builderInitializers) 1683 init.accept(builder2); 1684 if (injectBuilder) { 1685 log("Injecting builder via @Inject/@Autowired"); 1686 inject(builder2); 1687 } 1688 if (autoWireBuilder) { 1689 log("Auto-wiring builder setters from bean store"); 1690 autoWireBuilder(builder2, store2); 1691 } 1692 1693 // Look for Builder.build()/create()/get() - REQUIRED 1694 // Uses buildMethodNames configuration (defaults to "build", "create", "get") 1695 // Check declared methods first to get the most specific override, then fall back to public methods 1696 var buildMethod = info(builder2.getClass()).getPublicMethods().stream() 1697 .filter(x -> x.isAll(NOT_STATIC, NOT_DEPRECATED, NOT_SYNTHETIC, NOT_BRIDGE)) 1698 .filter(x -> buildMethodNames.contains(x.getNameSimple())) 1699 .filter(x -> o(x).map(x2 -> x2.getReturnType()).filter(x2 -> x2.is(beanSubType.inner()) || x2.isParentOf(beanSubType)).isPresent()) // Accept methods that return beanSubType or a parent type of beanSubType 1700 .filter(x -> x.getAnnotations().stream().anyMatch(JsrSupport::isInjectAnnotation) ? x.canResolveAllParameters(store2) : x.getParameterCount() == 0) 1701 .sorted(methodComparator) 1702 .findFirst(); 1703 1704 if (buildMethod.isPresent()) { 1705 var method = buildMethod.get(); 1706 log("Found build method: %s", method.getNameFull()); 1707 log("Method declaring class: %s", method.getDeclaringClass().getName()); 1708 log("Builder class: %s", cn(builder2)); 1709 var returnType = method.getReturnType(); 1710 log("Method return type: %s", returnType.getName()); 1711 log("Expected beanSubType: %s", beanSubType.getName()); 1712 1713 // Check if method has @Inject annotation 1714 boolean hasInject = method.getAnnotations().stream().anyMatch(JsrSupport::isInjectAnnotation); 1715 if (hasInject) { 1716 log("Method has @Inject annotation, resolving parameters from bean store"); 1717 } else { 1718 log("Method has no parameters, calling without injection"); 1719 } 1720 1721 builderAttempted = true; 1722 // Call the builder method 1723 Object builtBean = method.inject(store2, builder2); 1724 1725 // Validate the produced bean (loose-builder mode). We accept the result if either: 1726 // 1. The build method's declared return type is exactly beanSubType, OR 1727 // 2. The runtime instance produced by the build method is assignment-compatible with beanSubType. 1728 // Case 2 supports the legacy pattern where a parent class's Builder.build() declares the parent 1729 // type but constructs a configured subclass at runtime because the builder's internal 1730 // type-binding was preset. 1731 // If neither matches, we fall through to factory-method / constructor resolution on beanSubType 1732 // rather than throwing — that lets standard "subclass adds its own constructor" patterns succeed. 1733 if (returnType.is(beanSubType.inner()) || (builtBean != null && beanSubType.inner().isInstance(builtBean))) { 1734 bean = (T)beanType.cast(builtBean); 1735 } else { 1736 log("Builder method %s returned %s but expected %s; falling through to factory methods/constructors", method.getNameFull(), builtBean == null ? "null" : cn(builtBean), beanSubType.getName()); 1737 } 1738 } 1739 1740 if (bean != null) { 1741 log("Bean created successfully via builder"); 1742 bean = inject(bean); 1743 runPostCreateHooks(bean); 1744 return bean; 1745 } 1746 1747 // Builder was found but no appropriate build method was found 1748 // Try fallback: look for ANY method on builder that returns the exact bean type 1749 log("Attempting Builder.anything()"); 1750 var anyMethod = info(builder2.getClass()).getPublicMethods().stream() 1751 .filter(x -> x.isAll(NOT_STATIC, NOT_DEPRECATED, NOT_SYNTHETIC, NOT_BRIDGE)) 1752 .filter(x -> !buildMethodNames.contains(x.getNameSimple())) // Skip standard build methods we already checked 1753 .filter(x -> x.getReturnType().is(beanSubType.inner())) // Must return exact beanSubType, not parent 1754 .filter(x -> x.getAnnotations().stream().anyMatch(JsrSupport::isInjectAnnotation) ? x.canResolveAllParameters(store2) : x.getParameterCount() == 0) 1755 .sorted(methodComparator) 1756 .findFirst(); 1757 1758 if (anyMethod.isPresent()) { 1759 var method = anyMethod.get(); 1760 log("Found builder method returning bean type: %s", method.getNameFull()); 1761 var returnType = method.getReturnType(); 1762 1763 // Call the builder method 1764 Object builtBean = method.inject(store2, builder2); 1765 1766 // Builder method must return the exact beanSubType 1767 if (!returnType.is(beanSubType.inner())) { 1768 log("Builder method %s returns %s, but must return %s", method.getNameFull(), returnType.getName(), beanSubType.getName()); 1769 throw exex("Builder method %s returns %s, but must return %s. Builder build methods must always return the exact bean subtype being created.", method.getNameFull(), returnType.getName(), beanSubType.getName()); 1770 } 1771 bean = (T)beanType.cast(builtBean); 1772 1773 if (bean != null) { 1774 log("Bean created successfully via builder fallback method"); 1775 bean = inject(bean); 1776 runPostCreateHooks(bean); 1777 return bean; 1778 } 1779 } 1780 1781 // Check if builder type has ANY method that returns the right type (even if not named build/create/get) 1782 // If so, log that builder was detected but no appropriate build method was found 1783 // Otherwise, log that builder type is invalid 1784 var builderTypeInfo = builderType.get(); 1785 boolean hasAnyMethodWithRightReturnType = builderTypeInfo != null && builderTypeInfo.getPublicMethods().stream() 1786 .filter(x -> x.isAll(NOT_STATIC, NOT_DEPRECATED, NOT_SYNTHETIC, NOT_BRIDGE)) 1787 .map(x -> x.getReturnType()) 1788 .anyMatch(x -> x.isAssignableFrom(beanSubType)); 1789 boolean hasBuildMethodWithRightReturnType = builderTypeInfo != null && builderTypeInfo.getPublicMethods().stream() 1790 .filter(x -> x.isAll(NOT_STATIC, NOT_DEPRECATED, NOT_SYNTHETIC, NOT_BRIDGE)) 1791 .filter(x -> buildMethodNames.contains(x.getNameSimple())) 1792 .map(x -> x.getReturnType()) 1793 .anyMatch(x -> x.isAssignableFrom(beanSubType)); 1794 boolean isExplicitBuilder = explicitBuilderType != null || explicitBuilder != null; 1795 boolean isValidBuilder = builderTypeInfo != null && isValidBuilderType(builderTypeInfo); 1796 1797 if (hasAnyMethodWithRightReturnType && !hasBuildMethodWithRightReturnType) { 1798 // Builder has a method returning the right type but not with the expected name 1799 log("Builder detected but no appropriate build method found. Builder type: %s. Expected method names: %s", cn(builder2), buildMethodNames); 1800 // Fall through to factory methods/constructors 1801 } else if (builderAttempted) { 1802 // We tried the builder's build method but it produced a runtime instance that wasn't the expected 1803 // beanSubType (loose-builder fallthrough above). Don't throw; fall through to factory-method / 1804 // constructor resolution on beanSubType so subclasses with their own constructor/factory still resolve. 1805 log("Builder %s build method produced wrong runtime type; falling through to factory methods/constructors", cn(builder2)); 1806 } else if (hasBuildMethodWithRightReturnType || isExplicitBuilder || isValidBuilder) { 1807 // Builder has a build method with right return type (even if can't be called) or was explicitly set 1808 // Throw exception unless fallback exists 1809 log("Builder detected but no appropriate build method found. Builder type: %s. Expected method names: %s", cn(builder2), buildMethodNames); 1810 1811 if (fallbackSupplier != null) { 1812 log(CONST_usingFallbackSupplier); 1813 T fallbackBean = fallbackSupplier.get(); 1814 runPostCreateHooks(fallbackBean); 1815 return fallbackBean; 1816 } 1817 1818 log("Failed to create bean using builder"); 1819 throw exex("Could not instantiate class %1$s using builder type %2$s. Builder must have a build(), create(), or get() method that returns %1$s. The method may have @Inject annotation to allow injected parameters.", beanSubType.getName(), builderTypeInfo != null ? builderTypeInfo.getName() : cn(builder2)); 1820 } else { 1821 // Builder type is invalid and was auto-detected - fall through to factory methods/constructors 1822 log("Builder detected but builder type is invalid. Builder type: %s. Falling back to factory methods/constructors.", cn(builder2)); 1823 } 1824 } 1825 1826 // Look for Bean.factoryMethod(). 1827 log("Attempting Bean.factoryMethod()"); 1828 // If builder was detected but has no build method, pass it as extra bean for factory methods 1829 Object[] factoryMethodExtraBeans = builder2 != null ? new Object[]{builder2} : new Object[0]; 1830 var factoryMethod = beanSubType.getPublicMethods().stream() 1831 .filter(x -> x.isAll(STATIC, NOT_DEPRECATED, NOT_SYNTHETIC, NOT_BRIDGE)) 1832 .filter(x -> factoryMethodNames.contains(x.getNameSimple())) 1833 .filter(x -> x.hasReturnType(beanSubType)) 1834 .filter(x -> x.canResolveAllParameters(store2, factoryMethodExtraBeans)) 1835 .sorted(methodComparator) 1836 .findFirst(); 1837 if (factoryMethod.isPresent()) { 1838 log("Found factory method: %s", factoryMethod.get().getNameFull()); 1839 bean = (T) beanType.cast(factoryMethod.get().inject(store2, null, factoryMethodExtraBeans)); 1840 // When factoryAbstainOnNull is set, treat a null result from the factory method as a 1841 // deliberate "abstain" signal and return null without falling through to constructor 1842 // lookup. Used by callers like RestOpArg subclasses whose create(ParameterInfo) 1843 // returns null when the parameter isn't annotated with the marker the subclass 1844 // handles (e.g. AttributeArg.create() returns null when @Attr isn't present). 1845 if (bean == null && factoryAbstainOnNull) 1846 return null; 1847 } 1848 1849 // Look for Bean(). 1850 // Skip constructor invocation when beanSubType is abstract or an interface — Class.newInstance() would 1851 // throw InstantiationException, masking the more useful "class is abstract"/"class is an interface" 1852 // fallthrough below (which honors the registered fallback supplier when present). 1853 if (bean == null && ! beanSubType.isInterface() && ! beanSubType.isAbstract()) { 1854 log("Attempting Bean() constructor"); 1855 // If preferZeroArgConstructor is set and a no-arg constructor exists, short-circuit to it. 1856 // This skips the longest-resolvable-constructor heuristic for callers that just want a fresh 1857 // empty instance — see preferZeroArgConstructor() Javadoc for the parameterized-container rationale. 1858 if (preferZeroArgConstructor) { 1859 var zeroArgCtor = beanSubType.getPublicConstructors().stream() 1860 .filter(x -> x.isAll(NOT_DEPRECATED)) 1861 .filter(x -> x.isDeclaringClass(beanSubType)) 1862 .filter(x -> x.getParameterCount() == 0) 1863 .findFirst(); 1864 if (zeroArgCtor.isPresent()) { 1865 log("Using zero-arg constructor (preferZeroArgConstructor): %s", zeroArgCtor.get().getNameFull()); 1866 bean = (T) beanType.cast(zeroArgCtor.get().inject(store2, enclosingInstance)); 1867 } 1868 } 1869 // If builder was detected but has no build method, pass it as extra bean for constructors 1870 Object[] constructorExtraBeans = builder2 != null ? new Object[]{builder2} : new Object[0]; 1871 if (bean == null) { 1872 bean = beanSubType.getPublicConstructors().stream() 1873 .filter(x -> x.isAll(NOT_DEPRECATED)) 1874 .filter(x -> x.isDeclaringClass(beanSubType)) 1875 .filter(x -> x.canResolveAllParameters(store2, enclosingInstance, constructorExtraBeans)) 1876 .sorted(constructorComparator) 1877 .findFirst() 1878 .map(x -> { 1879 log("Found constructor: %s", x.getNameFull()); 1880 return (T)beanType.cast(x.inject(store2, enclosingInstance, constructorExtraBeans)); 1881 }) 1882 .orElse(null); 1883 } 1884 // Fallback: try protected constructors (legacy BeanCreator behavior). 1885 // Many framework classes use a protected (Builder) constructor with public static create() factory. 1886 if (bean == null) { 1887 bean = beanSubType.getDeclaredConstructors().stream() 1888 .filter(x -> x.isAll(PROTECTED, NOT_DEPRECATED)) 1889 .filter(x -> x.isDeclaringClass(beanSubType)) 1890 .filter(x -> x.canResolveAllParameters(store2, enclosingInstance, constructorExtraBeans)) 1891 .sorted(constructorComparator) 1892 .findFirst() 1893 .map(x -> { 1894 log("Found protected constructor: %s", x.getNameFull()); 1895 return (T)beanType.cast(x.inject(store2, enclosingInstance, constructorExtraBeans)); 1896 }) 1897 .orElse(null); 1898 } 1899 // Fallback: try package-private constructors. 1900 // Useful for @Configuration classes and other framework types that intentionally restrict 1901 // instantiation to their declaring package but still want to participate in the bean store. 1902 // Private constructors are deliberately excluded — they signal "do not instantiate". 1903 if (bean == null) { 1904 bean = beanSubType.getDeclaredConstructors().stream() 1905 .filter(x -> x.isAll(NOT_PUBLIC, NOT_PROTECTED, NOT_PRIVATE, NOT_DEPRECATED)) 1906 .filter(x -> x.isDeclaringClass(beanSubType)) 1907 .filter(x -> x.canResolveAllParameters(store2, enclosingInstance, constructorExtraBeans)) 1908 .sorted(constructorComparator) 1909 .findFirst() 1910 .map(x -> { 1911 log("Found package-private constructor: %s", x.getNameFull()); 1912 return (T)beanType.cast(x.inject(store2, enclosingInstance, constructorExtraBeans)); 1913 }) 1914 .orElse(null); 1915 } 1916 } 1917 1918 if (bean != null) { 1919 log("Bean created successfully"); 1920 bean = inject(bean); 1921 runPostCreateHooks(bean); 1922 return bean; 1923 } 1924 1925 if (beanSubType.isInterface()) { 1926 log("Bean type is an interface"); 1927 if (fallbackSupplier != null) { 1928 log(CONST_usingFallbackSupplier); 1929 T fallbackBean = fallbackSupplier.get(); 1930 runPostCreateHooks(fallbackBean); 1931 return fallbackBean; 1932 } 1933 throw exex("Could not instantiate class %s: %s.", beanSubType.getName(), "Class is an interface"); 1934 } 1935 1936 if (beanSubType.isAbstract()) { 1937 log("Bean type is abstract"); 1938 if (fallbackSupplier != null) { 1939 log(CONST_usingFallbackSupplier); 1940 T fallbackBean = fallbackSupplier.get(); 1941 runPostCreateHooks(fallbackBean); 1942 return fallbackBean; 1943 } 1944 throw exex("Could not instantiate class %s: %s.", beanSubType.getName(), "Class is abstract"); 1945 } 1946 1947 if (fallbackSupplier != null) { 1948 log(CONST_usingFallbackSupplier); 1949 T fallbackBean = fallbackSupplier.get(); 1950 runPostCreateHooks(fallbackBean); 1951 return fallbackBean; 1952 } 1953 1954 log("Failed to create bean: no methods/constructors found with matching parameters"); 1955 throw exex("Could not instantiate class %s: No methods/constructors found with matching parameters", beanSubType.getName()); 1956 } 1957 1958 /** 1959 * Finds all bean subtypes, including beanSubType, beanType, and all classes in between. 1960 * 1961 * <p> 1962 * This method traverses the hierarchy from {@code beanSubType} up to {@code beanType}, collecting all classes 1963 * in the inheritance chain. This allows parent bean types to be resolved as injectable types. 1964 * 1965 * <h5 class='section'>Example:</h5> 1966 * <p class='bjava'> 1967 * <jc>// Class hierarchy</jc> 1968 * <jk>class</jk> A { } 1969 * <jk>class</jk> B <jk>extends</jk> A { } 1970 * <jk>class</jk> C <jk>extends</jk> B { } 1971 * 1972 * <jc>// When creating C with beanType=A, beanSubType=C</jc> 1973 * <jc>// This method returns: [C, B, A]</jc> 1974 * </p> 1975 * 1976 * @return A list of bean subtypes from beanSubType to beanType, never <jk>null</jk>. 1977 */ 1978 private List<ClassInfo> findBeanSubTypes() { 1979 var result = new ArrayList<ClassInfo>(); 1980 1981 // If beanSubType is the same as beanType, just return a single-element list 1982 if (beanSubType.is(beanType.inner())) { 1983 result.add(beanSubType); 1984 return result; 1985 } 1986 1987 // Traverse from beanSubType up to beanType 1988 var parents = beanSubType.getParents(); 1989 for (var parent : parents) { 1990 result.add(parent); 1991 // Stop when we reach beanType 1992 if (parent.is(beanType.inner())) { 1993 break; 1994 } 1995 } 1996 1997 // This should never happen if beanSubType validation is correct, but check anyway 1998 if (result.isEmpty() || !result.get(result.size() - 1).is(beanType.inner())) { 1999 throw iaex("beanType %s was not found in the parent hierarchy of beanSubType %s. This indicates a validation error.", beanType.getName(), beanSubType.getName()); 2000 } 2001 2002 return result; 2003 } 2004 2005 private Object findBuilder() { 2006 2007 // noBuilder() short-circuits all builder detection. 2008 if (noBuilder) 2009 return null; 2010 2011 var bs = store; 2012 var builderType2 = this.builderType.get(); 2013 2014 // If no builder type was determined, return null (builder not needed) 2015 if (builderType2 == null) 2016 return null; 2017 2018 Optional<Object> r; 2019 2020 // Step 0: Look for a pre-registered builder of the builder type in the bean store. 2021 // This handles scenarios where the caller has already configured a builder externally 2022 // (e.g. legacy framework code that registers a configured builder bean). 2023 r = bs.getBean(builderType2.inner()).map(Object.class::cast); 2024 if (r.isPresent()) { 2025 log("Using pre-registered builder from bean store: %s", builderType2.getName()); 2026 return r.get(); 2027 } 2028 2029 // Step 1: Look for a static create/builder method that returns the builder type 2030 r = beanSubType.getPublicMethods().stream() 2031 .filter(x -> x.isAll(STATIC, NOT_DEPRECATED, NOT_SYNTHETIC, NOT_BRIDGE)) 2032 .filter(x -> builderMethodNames.contains(x.getNameSimple())) 2033 .filter(x -> x.hasReturnType(builderType2)) 2034 .filter(x -> x.canResolveAllParameters(bs, enclosingInstance)) 2035 .sorted(comparing(MethodInfo::getParameterCount).reversed()) 2036 .findFirst() 2037 .map(x -> inject(x.inject(bs, enclosingInstance))); 2038 if (r.isPresent()) 2039 return r.get(); 2040 2041 // Step 2: Look for a public constructor on the builder type 2042 r = builderType2.getPublicConstructors().stream() 2043 .filter(x -> x.isAll(NOT_DEPRECATED)) 2044 .filter(x -> x.canResolveAllParameters(bs, enclosingInstance)) 2045 .sorted(comparing(ConstructorInfo::getParameterCount).reversed()) 2046 .findFirst() 2047 .map(x -> inject(x.inject(bs, enclosingInstance))); 2048 2049 if (r.isPresent()) 2050 return r.get(); 2051 2052 // Step 3: Look for a protected constructor on the builder type 2053 r = builderType2.getDeclaredConstructors().stream() 2054 .filter(x -> x.isAll(ElementFlag.PROTECTED, NOT_DEPRECATED)) 2055 .filter(x -> x.canResolveAllParameters(bs, enclosingInstance)) 2056 .sorted(comparing(ConstructorInfo::getParameterCount).reversed()) 2057 .findFirst() 2058 .map(x -> inject(x.inject(bs, enclosingInstance))); 2059 if (r.isPresent()) 2060 return r.get(); 2061 2062 // Step 4: Look for a package-private constructor on the builder type. 2063 // Mirrors the package-private fallback in findBeanImpl() for symmetry: any builder co-located in 2064 // the bean's declaring package can be discovered without forcing the constructor to be public/protected. 2065 r = builderType2.getDeclaredConstructors().stream() 2066 .filter(x -> x.isAll(NOT_PUBLIC, NOT_PROTECTED, NOT_PRIVATE, NOT_DEPRECATED)) 2067 .filter(x -> x.canResolveAllParameters(bs, enclosingInstance)) 2068 .sorted(comparing(ConstructorInfo::getParameterCount).reversed()) 2069 .findFirst() 2070 .map(x -> inject(x.inject(bs, enclosingInstance))); 2071 2072 return r.orElse(null); 2073 } 2074 2075 /** 2076 * Finds the builder type based on priority: 2077 * 1. Explicitly set builderType 2078 * 2. @Builder annotation on beanSubType (includes inherited annotations) 2079 * 3. Autodetect from static methods or inner classes 2080 */ 2081 private ClassInfo findBuilderType() { 2082 log("Finding builder type..."); 2083 2084 // noBuilder() short-circuits all builder detection. 2085 if (noBuilder) { 2086 log("noBuilder() set; skipping builder type detection"); 2087 return null; 2088 } 2089 2090 // Priority 1: Explicitly set builderType 2091 if (explicitBuilderType != null) { 2092 log("Using explicitly set builder type: %s", explicitBuilderType.getName()); 2093 return explicitBuilderType; 2094 } 2095 2096 // Priority 2: @Builder annotation on beanSubType 2097 // Check declared annotations first to ensure child's annotation overrides parent's 2098 var r = beanSubType.getDeclaredAnnotations().stream() 2099 .filter(a -> a.isType(org.apache.juneau.commons.Builder.class)) 2100 .map(a -> (AnnotationInfo<org.apache.juneau.commons.Builder>)a) 2101 .map(x -> ClassInfo.class.cast(info(x.inner().value()))) 2102 .findFirst(); 2103 if (r.isPresent()) { 2104 log("Found builder via @Builder annotation on beanSubType: %s", r.get().getName()); 2105 return r.get(); 2106 } 2107 // Fall back to inherited annotations if no declared annotation found 2108 r = beanSubType.getAnnotations(org.apache.juneau.commons.Builder.class) 2109 .map(x -> ClassInfo.class.cast(info(x.inner().value()))) 2110 .findFirst(); 2111 if (r.isPresent()) { 2112 log("Found builder via @Builder annotation (inherited): %s", r.get().getName()); 2113 return r.get(); 2114 } 2115 2116 // Priority 3: Autodetect 2117 // 3a: Look for static create/builder method that returns a potential builder type. 2118 var staticBuilderTypes = beanSubType.getPublicMethods().stream() 2119 .filter(x -> x.isAll(STATIC, NOT_DEPRECATED, NOT_SYNTHETIC, NOT_BRIDGE)) 2120 .filter(x -> builderMethodNames.contains(x.getNameSimple())) 2121 .filter(x -> ! x.hasReturnType(beanSubType)) // Must not return the bean type itself 2122 .filter(x -> isValidBuilderType(x.getReturnType())) 2123 .map(MethodInfo::getReturnType) 2124 .toList(); 2125 if (! staticBuilderTypes.isEmpty()) { 2126 // Prefer a factory whose builder builds the EXACT requested type (or a 2127 // subtype) over one that only promises a supertype — e.g. an inherited generic builder(Class) 2128 // whose build() erases to a base class. A supertype-only factory must not displace a stricter path. 2129 var strict = staticBuilderTypes.stream().filter(this::isStrictBuilderType).findFirst(); 2130 if (strict.isPresent()) { 2131 log("Found builder via static method (strict): %s", strict.get().getName()); 2132 return strict.get(); 2133 } 2134 var weak = gateWeakBuilder(staticBuilderTypes.get(0)); 2135 if (weak != null) { 2136 log("Found builder via static method: %s", weak.getName()); 2137 return weak; 2138 } 2139 // Weak/supertype-only static factory rejected in favor of a direct constructor; fall through to 2140 // 3b/3c (a stricter inner Builder may still exist) and ultimately the constructor path. 2141 } 2142 2143 // 3b: Look for inner Builder class 2144 log("Looking for inner builder class (names: %s)...", builderClassNames); 2145 r = beanSubType.getDeclaredMemberClasses().stream() 2146 .filter(x -> builderClassNames.contains(x.getNameSimple())) 2147 .findFirst(); 2148 if (r.isPresent()) { 2149 var builderClass = r.get(); 2150 if (isValidBuilderType(builderClass)) { 2151 var gated = isStrictBuilderType(builderClass) ? builderClass : gateWeakBuilder(builderClass); 2152 if (gated != null) { 2153 log("Found builder via inner class: %s", gated.getName()); 2154 return gated; 2155 } 2156 // Weak inner builder rejected in favor of a direct constructor; fall through. 2157 } else { 2158 // Still return it so we can provide a better error message when trying to use it 2159 log("Found builder class via inner class but it is not valid: %s", builderClass.getName()); 2160 return builderClass; 2161 } 2162 } 2163 2164 // 3c: Look for builder in parent classes and implemented interfaces (skip beanSubType itself, 2165 // which was already searched in 3b). getAllParents returns parents (child-to-parent) followed by 2166 // interfaces, so we walk the whole chain in a uniform order. 2167 var allParents = beanSubType.getAllParents(); 2168 for (int i = 1; i < allParents.size(); i++) { 2169 var parentClass = allParents.get(i); 2170 r = parentClass.getDeclaredMemberClasses().stream() 2171 .filter(x -> builderClassNames.contains(x.getNameSimple())) 2172 .findFirst(); 2173 if (r.isPresent()) { 2174 var builderClass = r.get(); 2175 if (isValidBuilderType(builderClass)) { 2176 var gated = isStrictBuilderType(builderClass) ? builderClass : gateWeakBuilder(builderClass); 2177 if (gated != null) { 2178 log("Found builder via parent inner class: %s", gated.getName()); 2179 return gated; 2180 } 2181 // Weak parent inner builder rejected in favor of a direct constructor; keep scanning. 2182 continue; 2183 } 2184 // Still return it so we can provide a better error message when trying to use it 2185 log("Found builder class via parent inner class but it is not valid: %s", builderClass.getName()); 2186 return builderClass; 2187 } 2188 } 2189 2190 // No builder type found 2191 log("No builder type found"); 2192 return null; 2193 } 2194 2195 /** 2196 * Tests whether a builder candidate builds the <b>exact</b> requested bean type (or a subtype of it), 2197 * as opposed to only promising a supertype. 2198 * 2199 * <p> 2200 * Used by {@link #findBuilderType()} to prefer a precise builder over an inherited 2201 * generic base builder whose {@code build()} erases to a parent class (e.g. a self-typed REST 2202 * {@code DefaultBuilder} whose {@code build()} returns {@code RestMixin}). 2203 * 2204 * @param builderCandidate The builder type to test. 2205 * @return <jk>true</jk> if the candidate has a 0-arg (or {@code @Inject}) build/create/get method whose 2206 * return type is {@code beanSubType} or a subtype of it. 2207 */ 2208 private boolean isStrictBuilderType(ClassInfo builderCandidate) { 2209 return builderCandidate.getPublicMethods().stream() 2210 .filter(x -> x.isAll(NOT_STATIC, NOT_DEPRECATED, NOT_SYNTHETIC, NOT_BRIDGE)) 2211 .filter(x -> buildMethodNames.contains(x.getNameSimple())) 2212 .filter(x -> { var rt = x.getReturnType(); return rt.is(beanSubType.inner()) || beanSubType.isParentOf(rt); }) 2213 .anyMatch(x -> x.getAnnotations().stream().anyMatch(JsrSupport::isInjectAnnotation) || x.getParameterCount() == 0); 2214 } 2215 2216 /** 2217 * A builder candidate that only builds a <i>supertype</i> of the requested bean 2218 * type must not be used when the requested type is concretely instantiable via a direct constructor. 2219 * 2220 * <p> 2221 * Returns the candidate unchanged when it is safe to use, or {@code null} to signal "prefer the 2222 * constructor path". This is only invoked for non-strict (supertype-only) candidates. 2223 * 2224 * @param builderCandidate The (weak) builder candidate. 2225 * @return The candidate, or {@code null} to prefer the direct-constructor path. 2226 */ 2227 private ClassInfo gateWeakBuilder(ClassInfo builderCandidate) { 2228 if (hasUsableDirectConstructor()) { 2229 log("Builder candidate %s only builds a supertype of %s and a usable direct constructor exists; preferring the constructor.", builderCandidate.getName(), beanSubType.getName()); 2230 return null; 2231 } 2232 return builderCandidate; 2233 } 2234 2235 /** 2236 * Tests whether the requested bean type is concretely instantiable via a non-private constructor whose 2237 * parameters can all be resolved from the bean store (a no-arg constructor always qualifies). 2238 * 2239 * @return <jk>true</jk> if a usable direct constructor exists on {@code beanSubType}. 2240 */ 2241 private boolean hasUsableDirectConstructor() { 2242 if (beanSubType.isAbstract() || beanSubType.isInterface()) 2243 return false; 2244 return beanSubType.getDeclaredConstructors().stream() 2245 .filter(x -> x.isAll(NOT_DEPRECATED, NOT_PRIVATE)) 2246 .filter(x -> x.isDeclaringClass(beanSubType)) 2247 .anyMatch(x -> x.canResolveAllParameters(store, enclosingInstance)); 2248 } 2249 2250 /** 2251 * Finds all builder types, including the primary builder type and any builder types found in the builder's parent hierarchy. 2252 * 2253 * <p> 2254 * This method traverses the parent hierarchy of the primary builder type, looking for builder classes whose build methods 2255 * return types that are the same as or parents of {@code beanType}. This allows parent builders to be resolved as injectable types. 2256 * 2257 * <h5 class='section'>Example:</h5> 2258 * <p class='bjava'> 2259 * <jc>// Class A with builder</jc> 2260 * <jk>class</jk> A { 2261 * <jk>static class</jk> Builder { 2262 * A create() { <jk>return new</jk> A(); } 2263 * } 2264 * } 2265 * 2266 * <jc>// Class B extends A with builder</jc> 2267 * <jk>class</jk> B <jk>extends</jk> A { 2268 * <jk>static class</jk> Builder <jk>extends</jk> A.Builder { 2269 * B create() { <jk>return new</jk> B(); } 2270 * } 2271 * } 2272 * 2273 * <jc>// When creating B, this method returns: [B.Builder, A.Builder]</jc> 2274 * <jc>// Traverses B.Builder → A.Builder hierarchy</jc> 2275 * <jc>// B.Builder.create() returns B (matches beanType)</jc> 2276 * <jc>// A.Builder.create() returns A (A is parent of B)</jc> 2277 * </p> 2278 * 2279 * @return A list of builder types, never <jk>null</jk>. 2280 */ 2281 private List<ClassInfo> findBuilderTypes() { 2282 var result = new ArrayList<ClassInfo>(); 2283 2284 // Start with the primary builder type 2285 var primaryBuilderType = findBuilderType(); 2286 if (primaryBuilderType == null) { 2287 return result; 2288 } 2289 2290 // Add the primary builder type first 2291 result.add(primaryBuilderType); 2292 2293 // Traverse the parent hierarchy of the builder type itself (skip the first element which is the primary builder type itself) 2294 var builderParents = primaryBuilderType.getParents(); 2295 for (int i = 0; i < builderParents.size(); i++) { 2296 var builderParent = builderParents.get(i); 2297 builderParent.getPublicMethods().stream() 2298 .filter(m -> m.isAll(NOT_STATIC, NOT_DEPRECATED, NOT_SYNTHETIC, NOT_BRIDGE)) 2299 .filter(m -> buildMethodNames.contains(m.getNameSimple())) 2300 .filter(m -> m.getReturnType().isParentOf(beanType)) 2301 .findFirst() 2302 .ifPresent(x -> result.add(builderParent)); 2303 } 2304 2305 return result; 2306 } 2307 2308 /** 2309 * Helper method to inject beans into an object instance. 2310 * 2311 * <p> 2312 * If the instantiator's <b>declared target type</b> ({@code beanType.inner()}) carries a class-level 2313 * {@link ConfigProperties @ConfigProperties} annotation, also runs {@link ConfigPropertiesBinder} against 2314 * {@code bean} under the annotation's prefix. The bind is performed <i>between</i> {@code @Value}/{@code @Inject} 2315 * field-and-method injection and {@code @PostConstruct} dispatch (via 2316 * {@link ClassInfo#inject(Object, BeanStore, Runnable)}), so a {@code @PostConstruct} method observes the 2317 * fully-bound config fields. The instantiator's internal {@link #store} is handed to the binder so 2318 * caller-registered {@link org.apache.juneau.commons.settings.PropertySource PropertySource} beans participate 2319 * ahead of the global {@link org.apache.juneau.commons.settings.Settings Settings} chain. 2320 * 2321 * <p> 2322 * The bound instance is then auto-registered into the parent {@link BeanStore} — under the declared target type, 2323 * as a {@linkplain WritableBeanStore#addDefaultSupplier(Class, Supplier) tier-4 default supplier} so a caller's 2324 * explicit registration of the same type is never shadowed — when that store is a writable, non-shared store. 2325 * The annotation is <b>not inherited</b>: a subclass or interface implementor of an annotated type does not 2326 * trigger binding or registration. 2327 * 2328 * @param <T2> The bean type. 2329 * @param bean The object to inject beans into. 2330 * @return The same bean instance (for method chaining). 2331 */ 2332 private <T2> T2 inject(T2 bean) { 2333 // Probe the DECLARED target type directly (not a stream over the inherited annotation set). 2334 // @ConfigProperties is not @Inherited, so getAnnotation() on the declared type intentionally returns null for 2335 // a subclass/implementor of an annotated type, and the isInstance() guard skips builders and other 2336 // non-target objects that pass through this shared helper. 2337 var cp = beanType.inner().getAnnotation(ConfigProperties.class); 2338 if (cp == null || ! beanType.inner().isInstance(bean)) 2339 return ClassInfo.of(bean).inject(bean, store); 2340 // Bind between field/method injection and @PostConstruct. The binder defaults to Settings.get() and 2341 // sources the passed store's PropertySource beans ahead of it, so no explicit .settings(...) is needed. 2342 var bean2 = ClassInfo.of(bean).inject(bean, store, () -> 2343 ConfigPropertiesBinder.of(bean, cp.prefix()) 2344 .beanStore(store) 2345 .relaxed(cp.relaxed()) 2346 .run()); 2347 registerConfigBean(bean2); 2348 return bean2; 2349 } 2350 2351 /** 2352 * Registers a freshly-bound {@code @ConfigProperties} instance under the instantiator's declared target type. 2353 * 2354 * <p> 2355 * Registration is a no-op when the parent store is <jk>null</jk> or read-only (not a 2356 * {@link WritableBeanStore}), or when it's the shared read-only {@link BasicBeanStore#INSTANCE} — binding 2357 * still occurs regardless. When it does register, it uses a 2358 * {@linkplain WritableBeanStore#addDefaultSupplier(Class, Supplier) default supplier} so a caller's explicit 2359 * same-type registration takes precedence, registered under the declared target type. 2360 * 2361 * @param bean The bound instance (guaranteed by the caller to be an instance of {@code beanType.inner()}). 2362 */ 2363 private void registerConfigBean(Object bean) { 2364 if (parentStore instanceof WritableBeanStore ws && ws != BasicBeanStore.INSTANCE) { 2365 var declaredType = beanType.inner(); 2366 ws.addDefaultSupplier(declaredType, () -> declaredType.cast(bean)); 2367 } 2368 } 2369 2370 /** 2371 * Auto-wires bean store entries into matching public single-argument setter methods of the builder. 2372 * 2373 * <p> 2374 * Setters are public, non-static, non-deprecated methods taking exactly one argument. The bean store 2375 * is queried for a bean assignable to the parameter's type. If the parameter is {@code Supplier<X>} 2376 * and {@link #autoWireUnwrapSuppliers} is true, the bean of type {@code X} is wrapped before being 2377 * passed in. 2378 * 2379 * <p> 2380 * Setters whose argument cannot be resolved are silently skipped. 2381 */ 2382 @SuppressWarnings({ 2383 "java:S3011" // Reflection access override is required for invoking discovered setters uniformly. 2384 }) 2385 private void autoWireBuilder(Object builder2, BeanStore bs) { 2386 var ci = info(builder2.getClass()); 2387 ci.getPublicMethods().stream() 2388 .filter(m -> m.isAll(NOT_STATIC, NOT_DEPRECATED, NOT_SYNTHETIC, NOT_BRIDGE)) 2389 .filter(m -> m.getParameterCount() == 1) 2390 .forEach(m -> { 2391 try { 2392 var p0 = m.getParameterTypes().get(0); 2393 Class<?> rawType = p0.inner(); 2394 Object value = null; 2395 if (autoWireUnwrapSuppliers && Supplier.class.isAssignableFrom(rawType)) { 2396 // Best-effort: try to resolve the wrapped type from the parameter's parameterized signature. 2397 var generic = m.inner().getGenericParameterTypes()[0]; 2398 if (generic instanceof java.lang.reflect.ParameterizedType pt) { 2399 var args = pt.getActualTypeArguments(); 2400 if (args.length == 1 && args[0] instanceof Class<?> wrapped) { 2401 var wrappedBean = bs.getBean(wrapped); 2402 if (wrappedBean.isPresent()) { 2403 Object wb = wrappedBean.get(); 2404 value = (Supplier<Object>) () -> wb; 2405 } 2406 } 2407 } 2408 } else { 2409 var bean = bs.getBean(rawType); 2410 if (bean.isPresent()) 2411 value = bean.get(); 2412 } 2413 if (value != null) { 2414 m.inner().setAccessible(true); 2415 m.inner().invoke(builder2, value); 2416 log("Auto-wired setter %s with bean of type %s", m.getNameSimple(), rawType.getName()); 2417 } 2418 } catch (@SuppressWarnings("unused") Exception e) { 2419 // Swallow auto-wire errors silently; auto-wire is a best-effort. 2420 } 2421 }); 2422 } 2423 2424 /** 2425 * Checks if a type can be used as a builder. 2426 * A valid builder type must have: 2427 * - A build/create/get method that returns the bean type or a parent of the bean type 2428 * - The method may have @Inject annotation to allow injected parameters 2429 * - If no @Inject annotation, the method must have no parameters 2430 */ 2431 private boolean isValidBuilderType(ClassInfo builderCandidate) { 2432 log("Validating builder candidate: %s", builderCandidate.getName()); 2433 2434 // Check if it has a build/create/get method that returns beanSubType, beanType, or a parent of beanSubType 2435 var hasBuildMethod = builderCandidate.getPublicMethods().stream() 2436 .filter(x -> x.isAll(NOT_STATIC, NOT_DEPRECATED, NOT_SYNTHETIC, NOT_BRIDGE)) 2437 .filter(x -> buildMethodNames.contains(x.getNameSimple())) 2438 .filter(x -> { 2439 var returnType = x.getReturnType(); 2440 return returnType.is(beanSubType.inner()) || returnType.is(beanType.inner()) || returnType.isParentOf(beanSubType); 2441 }) 2442 .anyMatch(x -> x.getAnnotations().stream().anyMatch(JsrSupport::isInjectAnnotation) || x.getParameterCount() == 0); 2443 2444 if (hasBuildMethod) { 2445 log("Builder is valid: has build/create/get method returning bean type"); 2446 return true; 2447 } 2448 2449 log("Builder is NOT valid: no build/create/get method returning bean type"); 2450 return false; 2451 } 2452 2453 private void log(String message, Object... args) { 2454 if ((silent || ! logger.isLoggable(java.util.logging.Level.FINE)) && ! debug.isPresent()) 2455 return; 2456 var prefix = description != null ? (description + " (" + beanType.getName() + ")") : beanType.getName(); 2457 logger.fine(prefix + ": " + message, args); 2458 debug.ifPresent(x -> x.add(args.length == 0 ? message : f(message, args))); 2459 } 2460 2461 T runPostCreateHooks(T bean) { 2462 postCreateHooks.forEach(x -> x.accept(bean)); 2463 return bean; 2464 } 2465 } // class Builder 2466}