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 java.util.function.*; 020 021/** 022 * Extends {@link BeanStore} with methods for adding beans. 023 * 024 * <p> 025 * This interface provides write operations for bean stores, allowing beans to be added 026 * either as direct instances or as suppliers for lazy initialization. 027 * 028 * <h5 class='section'>Example:</h5> 029 * <p class='bjava'> 030 * WritableBeanStore <jv>beanStore</jv> = ...; 031 * 032 * <jc>// Add unnamed bean</jc> 033 * <jv>beanStore</jv>.addBean(MyService.<jk>class</jk>, <jk>new</jk> MyService()); 034 * 035 * <jc>// Add named bean</jc> 036 * <jv>beanStore</jv>.addBean(MyService.<jk>class</jk>, <jk>new</jk> MyService(), <js>"primary"</js>); 037 * 038 * <jc>// Add bean supplier for lazy initialization</jc> 039 * <jv>beanStore</jv>.addSupplier(MyService.<jk>class</jk>, () -> <jk>new</jk> MyService()); 040 * 041 * <jc>// Add named bean supplier</jc> 042 * <jv>beanStore</jv>.addSupplier(MyService.<jk>class</jk>, () -> <jk>new</jk> MyService(), <js>"secondary"</js>); 043 * 044 * <jc>// Clear all beans</jc> 045 * <jv>beanStore</jv>.clear(); 046 * </p> 047 * 048 * <h5 class='section'>See Also:</h5><ul> 049 * <li class='jc'>{@link BeanStore} - Read-only bean lookup interface 050 * </ul> 051 */ 052@SuppressWarnings({ 053 "resource" // Fluent methods return the store itself (an AutoCloseable); callers chaining registrations must not be flagged for not closing each returned reference. 054}) 055public interface WritableBeanStore extends BeanStore, AutoCloseable { 056 057 /** 058 * Same as {@link #addBean(Class,Object)} but returns the bean instead of this object for fluent calls. 059 * 060 * @param <T> The bean type. 061 * @param beanType The bean type. 062 * @param bean The bean instance. Can be <jk>null</jk> (stored as an explicit <jk>null</jk> binding, distinct from no binding at all). 063 * @return The bean. 064 */ 065 default <T> T add(Class<T> beanType, T bean) { 066 addBean(beanType, bean); 067 return bean; 068 } 069 070 /** 071 * Same as {@link #addBean(Class,Object,String)} but returns the bean instead of this object for fluent calls. 072 * 073 * @param <T> The bean type. 074 * @param beanType The bean type. 075 * @param bean The bean instance. Can be <jk>null</jk> (stored as an explicit <jk>null</jk> binding, distinct from no binding at all). 076 * @param name The bean name. Can be <jk>null</jk> for unnamed beans. 077 * @return The bean. 078 */ 079 default <T> T add(Class<T> beanType, T bean, String name) { 080 addBean(beanType, bean, name); 081 return bean; 082 } 083 084 /** 085 * Adds an unnamed bean of the specified type to this store. 086 * 087 * @param <T> The bean type. 088 * @param beanType The bean type. 089 * @param bean The bean instance. Can be <jk>null</jk> (stored as an explicit <jk>null</jk> binding, distinct from no binding at all). 090 * @return This object for method chaining. 091 */ 092 <T> WritableBeanStore addBean(Class<T> beanType, T bean); 093 094 /** 095 * Adds a named bean of the specified type to this store. 096 * 097 * @param <T> The bean type. 098 * @param beanType The bean type. 099 * @param bean The bean instance. Can be <jk>null</jk> (stored as an explicit <jk>null</jk> binding, distinct from no binding at all). 100 * @param name The bean name. Can be <jk>null</jk> for unnamed beans. 101 * @return This object for method chaining. 102 */ 103 <T> WritableBeanStore addBean(Class<T> beanType, T bean, String name); 104 105 /** 106 * Adds a supplier for an unnamed bean of the specified type to this store. 107 * 108 * <p> 109 * The supplier will be invoked lazily when the bean is first requested. 110 * 111 * @param <T> The bean type. 112 * @param beanType The bean type. 113 * @param supplier The bean supplier. Must not be <jk>null</jk>. 114 * @return This object for method chaining. 115 */ 116 <T> WritableBeanStore addSupplier(Class<T> beanType, Supplier<T> supplier); 117 118 /** 119 * Adds a supplier for a named bean of the specified type to this store. 120 * 121 * <p> 122 * The supplier will be invoked lazily when the bean is first requested. 123 * 124 * @param <T> The bean type. 125 * @param beanType The bean type. 126 * @param supplier The bean supplier. Must not be <jk>null</jk>. 127 * @param name The bean name. Can be <jk>null</jk> for unnamed beans. 128 * @return This object for method chaining. 129 */ 130 <T> WritableBeanStore addSupplier(Class<T> beanType, Supplier<T> supplier, String name); 131 132 /** 133 * Adds a fallback supplier for an unnamed bean of the specified type to this store. 134 * 135 * <p> 136 * Default suppliers are consulted only after regular {@linkplain #addBean(Class,Object) entries} and the regular {@linkplain BasicBeanStore#BasicBeanStore(BeanStore) parent} 137 * chain have been searched. They serve as a "use this if nothing else has provided one" hook, 138 * useful for memoizer-backed framework defaults that should not shadow explicit user 139 * registrations or beans inherited from an overriding parent (e.g. a Spring application context). 140 * 141 * @param <T> The bean type. 142 * @param beanType The bean type. 143 * @param supplier The bean supplier. Must not be <jk>null</jk>. 144 * @return This object for method chaining. 145 */ 146 <T> WritableBeanStore addDefaultSupplier(Class<T> beanType, Supplier<T> supplier); 147 148 /** 149 * Adds a fallback supplier for a named bean of the specified type to this store. 150 * 151 * <p> 152 * Default suppliers are consulted only after regular {@linkplain #addBean(Class,Object,String) entries} and the regular 153 * parent chain have been searched. See {@link #addDefaultSupplier(Class,Supplier)}. 154 * 155 * @param <T> The bean type. 156 * @param beanType The bean type. 157 * @param supplier The bean supplier. Must not be <jk>null</jk>. 158 * @param name The bean name. Can be <jk>null</jk> for unnamed beans. 159 * @return This object for method chaining. 160 */ 161 <T> WritableBeanStore addDefaultSupplier(Class<T> beanType, Supplier<T> supplier, String name); 162 163 /** 164 * Removes all beans from this store. 165 * 166 * <p> 167 * This operation only affects this store and does not affect any parent stores 168 * that may be associated with this store. 169 * 170 * @return This object for method chaining. 171 */ 172 WritableBeanStore clear(); 173 174 /** 175 * Returns <jk>true</jk> if this store has a {@linkplain #addDefaultSupplier(Class,Supplier) default supplier} 176 * registered locally for the specified unnamed bean type. 177 * 178 * <p> 179 * This is intended for callers that need to distinguish "framework default present" from "any binding 180 * exists" — for example, REST initialization uses this signal to skip types that are managed by an 181 * internal memoizer. Parent and overriding-parent stores are <i>not</i> consulted. 182 * 183 * @param beanType The bean type to check. 184 * @return <jk>true</jk> if a default supplier for the unnamed bean type is registered on this store. 185 */ 186 boolean hasDefaultSupplier(Class<?> beanType); 187 188 /** 189 * Returns <jk>true</jk> if this store has a {@linkplain #addDefaultSupplier(Class,Supplier,String) default supplier} 190 * registered locally for the specified bean type and name. 191 * 192 * <p> 193 * See {@link #hasDefaultSupplier(Class)} for the rationale. Parent and overriding-parent stores are 194 * <i>not</i> consulted. 195 * 196 * @param beanType The bean type to check. 197 * @param name The bean name. Can be <jk>null</jk> for unnamed beans. 198 * @return <jk>true</jk> if a default supplier for the bean type and name is registered on this store. 199 */ 200 boolean hasDefaultSupplier(Class<?> beanType, String name); 201 202 /** 203 * Registers a default implementation class for the specified bean type. 204 * 205 * <p> 206 * Type bindings are consulted by callers (notably {@link BeanInstantiator} and the various REST 207 * memoizers) when resolving the impl class to instantiate for <c>beanType</c>. This is the 208 * type-binding analogue of {@link #addDefaultSupplier(Class,Supplier) addDefaultSupplier}: it 209 * provides a deferred-construction default that can be overridden by later resolution steps 210 * (e.g. an annotation override). 211 * 212 * @param <T> The bean type. 213 * @param beanType The bean type to bind. 214 * @param implType The implementation class to instantiate when this type is resolved. 215 * @return This object for method chaining. 216 */ 217 <T> WritableBeanStore addBeanType(Class<T> beanType, Class<? extends T> implType); 218 219 /** 220 * Registers a configuration class and its {@link Bean}-annotated members. 221 * 222 * @param configType The configuration type. 223 * @return This object. 224 */ 225 WritableBeanStore registerConfiguration(Class<?> configType); 226 227 /** 228 * Registers multiple configuration classes. 229 * 230 * @param configTypes The configuration types. Can be <jk>null</jk>, in which case no action is taken. 231 * @return This object. 232 */ 233 default WritableBeanStore registerConfigurations(Class<?>... configTypes) { 234 if (configTypes != null) 235 for (var c : configTypes) 236 registerConfiguration(c); 237 return this; 238 } 239 240 /** 241 * Pushes the supplied {@link BeanStore} onto this store's overlay stack. 242 * 243 * <p> 244 * The pushed frame becomes the top-priority lookup target for subsequent bean resolution — it sits above 245 * any pre-existing {@code overridingParent} setting, this store's local entries, the regular parent chain, and 246 * the default-supplier tier. Frames are popped in LIFO order via {@link #popOverlay(Snapshot)}. 247 * 248 * <p> 249 * This is the framework primitive behind <b>Mode OVERLAY</b> of the test-injection model: a long-lived SUT's 250 * bean store has a per-test overlay pushed at {@code @BeforeEach}, then popped at {@code @AfterEach}, so 251 * subsequent tests see the original beans again with no rebuild cost. 252 * 253 * <h5 class='section'>Composition with {@code overridingParent}:</h5> 254 * <p> 255 * When this store was constructed with an 256 * {@linkplain BasicBeanStore#BasicBeanStore(BeanStore, BeanStore) overriding parent} <i>and</i> has overlays 257 * pushed on top, the overlay stack wins (it is "more recent"). Both are still consulted before local entries 258 * and the regular parent. 259 * 260 * @param overlay The bean store to layer on top. Must not be <jk>null</jk>. 261 * @return A {@link Snapshot} that must be passed back to {@link #popOverlay(Snapshot)} to remove the frame. 262 * @throws NullPointerException If {@code overlay} is <jk>null</jk>. 263 * @since 10.0.0 264 */ 265 Snapshot pushOverlay(BeanStore overlay); 266 267 /** 268 * Removes the overlay frame identified by the supplied {@link Snapshot}. 269 * 270 * <p> 271 * Pops must be issued in <b>LIFO</b> order — the supplied snapshot must identify the current top-of-stack 272 * frame. Out-of-order pops, pops on an empty stack, and pops of a snapshot produced by a different store all 273 * throw {@link IllegalStateException} with a descriptive message. These are programming errors, surfaced loudly 274 * rather than silently degraded. 275 * 276 * @param snapshot The snapshot returned by a prior {@link #pushOverlay(BeanStore)} call. Must not be 277 * <jk>null</jk>. 278 * @throws NullPointerException If {@code snapshot} is <jk>null</jk>. 279 * @throws IllegalStateException If the snapshot was produced by a different store, the overlay stack is empty, 280 * or the snapshot does not identify the top-of-stack frame (LIFO violation). 281 * @since 10.0.0 282 */ 283 void popOverlay(Snapshot snapshot); 284 285 /** 286 * Closes this bean store, invoking pre-destroy callbacks. 287 * 288 * @throws BeanCreationException on shutdown failures. 289 */ 290 @Override 291 void close() throws BeanCreationException; 292} 293