View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau.cp;
18  
19  import static java.util.stream.Collectors.*;
20  import static java.util.stream.Collectors.toList;
21  import static org.apache.juneau.commons.reflect.ReflectionUtils.*;
22  import static org.apache.juneau.commons.utils.CollectionUtils.*;
23  import static org.apache.juneau.commons.utils.ThrowableUtils.*;
24  import static org.apache.juneau.commons.utils.Utils.*;
25  
26  import java.util.*;
27  import java.util.concurrent.*;
28  
29  import java.util.function.*;
30  import java.util.stream.*;
31  
32  import org.apache.juneau.commons.collections.*;
33  import org.apache.juneau.commons.concurrent.*;
34  import org.apache.juneau.commons.reflect.*;
35  
36  /**
37   * Java bean store.
38   *
39   * <p>
40   * A simple storage database for beans keyed by type and name.
41   * Used to retrieve and instantiate beans using an injection-like API.
42   * It's similar in concept to the injection framework of Spring but greatly simplified in function and not intended to implement a full-fledged injection framework.
43   *
44   * <p>
45   * Beans can be stored with or without names.  Named beans are typically resolved using
46   * the <ja>@Name</ja> or <ja>@Qualified</ja> annotations on constructor or method parameters.
47   *
48   * <p>
49   * Beans are added through the following methods:
50   * <ul class='javatreec'>
51   * 	<li class='jm'>{@link #add(Class,Object) add(Class,Object)}
52   * 	<li class='jm'>{@link #add(Class,Object,String) add(Class,Object,String)}
53   * 	<li class='jm'>{@link #addBean(Class,Object) addBean(Class,Object)}
54   * 	<li class='jm'>{@link #addBean(Class,Object,String) addBean(Class,Object,String)}
55   * 	<li class='jm'>{@link #addSupplier(Class,Supplier) addSupplier(Class,Supplier)}
56   * 	<li class='jm'>{@link #addSupplier(Class,Supplier,String) addSupplier(Class,Supplier,String)}
57   * </ul>
58   *
59   * <p>
60   * Beans are retrieved through the following methods:
61   * <ul class='javatreec'>
62   * 	<li class='jm'>{@link #getBean(Class) getBean(Class)}
63   * 	<li class='jm'>{@link #getBean(Class,String) getBean(Class,String)}
64   * 	<li class='jm'>{@link #stream(Class) stream(Class)}
65   * </ul>
66   *
67   * <p>
68   * Beans are created through the following methods:
69   * <ul class='javatreec'>
70   * 	<li class='jm'>{@link #createBean(Class) createBean(Class)}
71   * 	<li class='jm'>{@link #createMethodFinder(Class) createMethodFinder(Class)}
72   * 	<li class='jm'>{@link #createMethodFinder(Class,Class) createMethodFinder(Class,Class)}
73   * 	<li class='jm'>{@link #createMethodFinder(Class,Object) createMethodFinder(Class,Object)}
74   * </ul>
75   *
76   * <h5 class='section'>Notes:</h5><ul>
77   * 	<li class='note'>Bean stores can be nested using {@link Builder#parent(BeanStore)}.
78   * 	<li class='note'>Bean stores can be made read-only using {@link Builder#readOnly()}.
79   * 	<li class='note'>Bean stores can be made thread-safe using {@link Builder#threadSafe()}.
80   * </ul>
81   *
82   */
83  public class BeanStore {
84  	/**
85  	 * Builder class.
86  	 */
87  	public static class Builder {
88  
89  		BeanStore parent;
90  		boolean readOnly, threadSafe;
91  		Object outer;
92  		Class<? extends BeanStore> type;
93  		BeanStore impl;
94  
95  		/**
96  		 * Constructor.
97  		 */
98  		protected Builder() {}
99  
100 		/**
101 		 * Instantiates this bean store.
102 		 *
103 		 * @return A new bean store.
104 		 */
105 		public BeanStore build() {
106 			if (nn(impl))
107 				return impl;
108 			if (type == null || type == BeanStore.class)
109 				return new BeanStore(this);
110 
111 			var c = info(type);
112 
113 			// @formatter:off
114 			var result = c.getDeclaredMethod(
115 				x -> x.isPublic()
116 				&& x.getParameterCount() == 0
117 				&& x.isStatic()
118 				&& x.hasName("getInstance")
119 			).map(m -> m.<BeanStore>invoke(null));
120 			// @formatter:on
121 			if (result.isPresent())
122 				return result.get();
123 
124 			result = c.getPublicConstructor(x -> x.canAccept(this)).map(ci -> ci.<BeanStore>newInstance(this));
125 			if (result.isPresent())
126 				return result.get();
127 
128 			result = c.getDeclaredConstructor(x -> x.isProtected() && x.canAccept(this)).map(ci -> ci.accessible().<BeanStore>newInstance(this));
129 			if (result.isPresent())
130 				return result.get();
131 
132 			throw rex("Could not find a way to instantiate class {0}", cn(type));
133 		}
134 
135 		/**
136 		 * Overrides the bean to return from the {@link #build()} method.
137 		 *
138 		 * @param value The bean to return from the {@link #build()} method.
139 		 * @return This object.
140 		 */
141 		public Builder impl(BeanStore value) {
142 			impl = value;
143 			return this;
144 		}
145 
146 		/**
147 		 * Specifies the outer bean context.
148 		 *
149 		 * <p>
150 		 * The outer context bean to use when calling constructors on inner classes.
151 		 *
152 		 * @param value The outer bean context.  Can be <jk>null</jk>.
153 		 * @return  This object.
154 		 */
155 		public Builder outer(Object value) {
156 			outer = value;
157 			return this;
158 		}
159 
160 		/**
161 		 * Specifies the parent bean store.
162 		 *
163 		 * <p>
164 		 * Bean searches are performed recursively up this parent chain.
165 		 *
166 		 * @param value The setting value.
167 		 * @return  This object.
168 		 */
169 		public Builder parent(BeanStore value) {
170 			parent = value;
171 			return this;
172 		}
173 
174 		/**
175 		 * Specifies that the bean store is read-only.
176 		 *
177 		 * <p>
178 		 * This means methods such as {@link BeanStore#addBean(Class, Object)} cannot be used.
179 		 *
180 		 * @return  This object.
181 		 */
182 		public Builder readOnly() {
183 			readOnly = true;
184 			return this;
185 		}
186 
187 		/**
188 		 * Specifies that the bean store being created should be thread-safe.
189 		 *
190 		 * @return  This object.
191 		 */
192 		public Builder threadSafe() {
193 			threadSafe = true;
194 			return this;
195 		}
196 
197 		/**
198 		 * Overrides the bean store type.
199 		 *
200 		 * <p>
201 		 * The specified type must have one of the following:
202 		 * <ul>
203 		 * 	<li>A static <c>getInstance()</c> method.
204 		 * 	<li>A public constructor that takes in this builder.
205 		 * 	<li>A protected constructor that takes in this builder.
206 		 * </ul>
207 		 *
208 		 * @param value The bean store type.
209 		 * @return This object.
210 		 */
211 		public Builder type(Class<? extends BeanStore> value) {
212 			type = value;
213 			return this;
214 		}
215 	}
216 
217 	/**
218 	 * Non-existent bean store.
219 	 */
220 	public static final class Void extends BeanStore {}
221 
222 	/**
223 	 * Static read-only reusable instance.
224 	 */
225 	public static final BeanStore INSTANCE = create().readOnly().build();
226 
227 	/**
228 	 * Static creator.
229 	 *
230 	 * @return A new {@link Builder} object.
231 	 */
232 	public static Builder create() {
233 		return new Builder();
234 	}
235 
236 	/**
237 	 * Static creator.
238 	 *
239 	 * @param parent Parent bean store.  Can be <jk>null</jk> if this is the root resource.
240 	 * @return A new {@link BeanStore} object.
241 	 */
242 	public static BeanStore of(BeanStore parent) {
243 		return create().parent(parent).build();
244 	}
245 
246 	/**
247 	 * Static creator.
248 	 *
249 	 * @param parent Parent bean store.  Can be <jk>null</jk> if this is the root resource.
250 	 * @param outer The outer bean used when instantiating inner classes.  Can be <jk>null</jk>.
251 	 * @return A new {@link BeanStore} object.
252 	 */
253 	public static BeanStore of(BeanStore parent, Object outer) {
254 		return create().parent(parent).outer(outer).build();
255 	}
256 
257 	private final Deque<BeanStoreEntry<?>> entries;
258 	private final Map<Class<?>,BeanStoreEntry<?>> unnamedEntries;
259 
260 	final Optional<BeanStore> parent;
261 	final Optional<Object> outer;
262 	final boolean readOnly, threadSafe;
263 	final SimpleReadWriteLock lock;
264 
265 	/**
266 	 * Constructor.
267 	 *
268 	 * @param builder The builder containing the settings for this bean.
269 	 */
270 	protected BeanStore(Builder builder) {
271 		parent = opt(builder.parent);
272 		outer = opt(builder.outer);
273 		readOnly = builder.readOnly;
274 		threadSafe = builder.threadSafe;
275 		lock = threadSafe ? new SimpleReadWriteLock() : SimpleReadWriteLock.NO_OP;
276 		entries = threadSafe ? new ConcurrentLinkedDeque<>() : new LinkedList<>();
277 		unnamedEntries = threadSafe ? new ConcurrentHashMap<>() : map();
278 	}
279 
280 	BeanStore() {
281 		this(create());
282 	}
283 
284 	/**
285 	 * Same as {@link #addBean(Class,Object)} but returns the bean instead of this object for fluent calls.
286 	 *
287 	 * @param <T> The class to associate this bean with.
288 	 * @param beanType The class to associate this bean with.
289 	 * @param bean The bean.  Can be <jk>null</jk>.
290 	 * @return The bean.
291 	 */
292 	public <T> T add(Class<T> beanType, T bean) {
293 		add(beanType, bean, null);
294 		return bean;
295 	}
296 
297 	/**
298 	 * Same as {@link #addBean(Class,Object,String)} but returns the bean instead of this object for fluent calls.
299 	 *
300 	 * @param <T> The class to associate this bean with.
301 	 * @param beanType The class to associate this bean with.
302 	 * @param bean The bean.  Can be <jk>null</jk>.
303 	 * @param name The bean name if this is a named bean.  Can be <jk>null</jk>.
304 	 * @return The bean.
305 	 */
306 	public <T> T add(Class<T> beanType, T bean, String name) {
307 		addBean(beanType, bean, name);
308 		return bean;
309 	}
310 
311 	/**
312 	 * Adds an unnamed bean of the specified type to this factory.
313 	 *
314 	 * @param <T> The class to associate this bean with.
315 	 * @param beanType The class to associate this bean with.
316 	 * @param bean The bean.  Can be <jk>null</jk>.
317 	 * @return This object.
318 	 */
319 	public <T> BeanStore addBean(Class<T> beanType, T bean) {
320 		return addBean(beanType, bean, null);
321 	}
322 
323 	/**
324 	 * Adds a named bean of the specified type to this factory.
325 	 *
326 	 * @param <T> The class to associate this bean with.
327 	 * @param beanType The class to associate this bean with.
328 	 * @param bean The bean.  Can be <jk>null</jk>.
329 	 * @param name The bean name if this is a named bean.  Can be <jk>null</jk>.
330 	 * @return This object.
331 	 */
332 	public <T> BeanStore addBean(Class<T> beanType, T bean, String name) {
333 		return addSupplier(beanType, () -> bean, name);
334 	}
335 
336 	/**
337 	 * Adds a supplier for an unnamed bean of the specified type to this factory.
338 	 *
339 	 * @param <T> The class to associate this bean with.
340 	 * @param beanType The class to associate this bean with.
341 	 * @param bean The bean supplier.
342 	 * @return This object.
343 	 */
344 	public <T> BeanStore addSupplier(Class<T> beanType, Supplier<T> bean) {
345 		return addSupplier(beanType, bean, null);
346 	}
347 
348 	/**
349 	 * Adds a supplier for a named bean of the specified type to this factory.
350 	 *
351 	 * @param <T> The class to associate this bean with.
352 	 * @param beanType The class to associate this bean with.
353 	 * @param bean The bean supplier.
354 	 * @param name The bean name if this is a named bean.  Can be <jk>null</jk>.
355 	 * @return This object.
356 	 */
357 	public <T> BeanStore addSupplier(Class<T> beanType, Supplier<T> bean, String name) {
358 		assertCanWrite();
359 		var e = createEntry(beanType, bean, name);
360 		try (var x = lock.write()) {
361 			entries.addFirst(e);
362 			if (e(name))
363 				unnamedEntries.put(beanType, e);
364 		}
365 		return this;
366 	}
367 
368 	/**
369 	 * Clears out all bean in this bean store.
370 	 *
371 	 * <p>
372 	 * Does not affect the parent bean store.
373 	 *
374 	 * @return This object.
375 	 */
376 	public BeanStore clear() {
377 		assertCanWrite();
378 		try (var x = lock.write()) {
379 			unnamedEntries.clear();
380 			entries.clear();
381 		}
382 		return this;
383 	}
384 
385 	/**
386 	 * Instantiates a bean creator.
387 	 *
388 	 * <h5 class='section'>See Also:</h5><ul>
389 	 * 	<li class='jc'>{@link BeanCreator} for usage.
390 	 * </ul>
391 	 *
392 	 * @param <T> The bean type to create.
393 	 * @param beanType The bean type to create.
394 	 * @return A new bean creator.
395 	 */
396 	public <T> BeanCreator<T> createBean(Class<T> beanType) {
397 		return new BeanCreator<>(beanType, this);
398 	}
399 
400 	/**
401 	 * Create a method finder for finding bean creation methods.
402 	 *
403 	 * <p>
404 	 * Same as {@link #createMethodFinder(Class,Object)} but uses {@link Builder#outer(Object)} as the resource bean.
405 	 *
406 	 * <h5 class='section'>See Also:</h5><ul>
407 	 * 	<li class='jc'>{@link BeanCreateMethodFinder} for usage.
408 	 * </ul>
409 	 *
410 	 * @param <T> The bean type to create.
411 	 * @param beanType The bean type to create.
412 	 * @return The method finder.  Never <jk>null</jk>.
413 	 */
414 	public <T> BeanCreateMethodFinder<T> createMethodFinder(Class<T> beanType) {
415 		return new BeanCreateMethodFinder<>(beanType, outer.orElseThrow(() -> new IllegalArgumentException("Method cannot be used without outer bean definition.")), this);
416 	}
417 
418 	/**
419 	 * Create a method finder for finding bean creation methods.
420 	 *
421 	 * <p>
422 	 * Same as {@link #createMethodFinder(Class,Class)} but looks for only static methods on the specified resource class
423 	 * and not also instance methods within the context of a bean.
424 	 *
425 	 * <h5 class='section'>See Also:</h5><ul>
426 	 * 	<li class='jc'>{@link BeanCreateMethodFinder} for usage.
427 	 * </ul>
428 	 *
429 	 * @param <T> The bean type to create.
430 	 * @param beanType The bean type to create.
431 	 * @param resourceClass The class containing the bean creator method.
432 	 * @return The method finder.  Never <jk>null</jk>.
433 	 */
434 	public <T> BeanCreateMethodFinder<T> createMethodFinder(Class<T> beanType, Class<?> resourceClass) {
435 		return new BeanCreateMethodFinder<>(beanType, resourceClass, this);
436 	}
437 
438 	/**
439 	 * Create a method finder for finding bean creation methods.
440 	 *
441 	 * <h5 class='section'>See Also:</h5><ul>
442 	 * 	<li class='jc'>{@link BeanCreateMethodFinder} for usage.
443 	 * </ul>
444 	 *
445 	 * @param <T> The bean type to create.
446 	 * @param beanType The bean type to create.
447 	 * @param resource The class containing the bean creator method.
448 	 * @return The method finder.  Never <jk>null</jk>.
449 	 */
450 	public <T> BeanCreateMethodFinder<T> createMethodFinder(Class<T> beanType, Object resource) {
451 		return new BeanCreateMethodFinder<>(beanType, resource, this);
452 	}
453 
454 	/**
455 	 * Returns the unnamed bean of the specified type.
456 	 *
457 	 * @param <T> The type of bean to return.
458 	 * @param beanType The type of bean to return.
459 	 * @return The bean.
460 	 */
461 	@SuppressWarnings("unchecked")
462 	public <T> Optional<T> getBean(Class<T> beanType) {
463 		try (var x = lock.read()) {
464 			var e = (BeanStoreEntry<T>)unnamedEntries.get(beanType);
465 			if (nn(e))
466 				return opt(e.get());
467 			if (parent.isPresent())
468 				return parent.get().getBean(beanType);
469 			return opte();
470 		}
471 	}
472 
473 	/**
474 	 * Returns the named bean of the specified type.
475 	 *
476 	 * @param <T> The type of bean to return.
477 	 * @param beanType The type of bean to return.
478 	 * @param name The bean name.  Can be <jk>null</jk>.
479 	 * @return The bean.
480 	 */
481 	@SuppressWarnings("unchecked")
482 	public <T> Optional<T> getBean(Class<T> beanType, String name) {
483 		try (var x = lock.read()) {
484 			var e = (BeanStoreEntry<T>)entries.stream().filter(x2 -> x2.matches(beanType, name)).findFirst().orElse(null);
485 			if (nn(e))
486 				return opt(e.get());
487 			if (parent.isPresent())
488 				return parent.get().getBean(beanType, name);
489 			return opte();
490 		}
491 	}
492 
493 	/**
494 	 * Given an executable, returns a list of types that are missing from this factory.
495 	 *
496 	 * @param executable The constructor or method to get the params for.
497 	 * @return A comma-delimited list of types that are missing from this factory, or <jk>null</jk> if none are missing.
498 	 */
499 	public String getMissingParams(ExecutableInfo executable) {
500 		var params = executable.getParameters();
501 		List<String> l = list();
502 		loop: for (int i = 0; i < params.size(); i++) {
503 			var pi = params.get(i);
504 			var pt = pi.getParameterType();
505 			if (i == 0 && outer.isPresent() && pt.isInstance(outer.get()))
506 				continue loop;
507 			if (pt.is(Optional.class) || pt.is(BeanStore.class))
508 				continue loop;
509 			var beanName = pi.getResolvedQualifier();  // Use @Named for bean injection
510 			var ptc = pt.inner();
511 			if (beanName == null && ! hasBean(ptc))
512 				l.add(pt.getNameSimple());
513 			if (nn(beanName) && ! hasBean(ptc, beanName))
514 				l.add(pt.getNameSimple() + '@' + beanName);
515 		}
516 		return l.isEmpty() ? null : l.stream().sorted().collect(joining(","));
517 	}
518 
519 	/**
520 	 * Returns the corresponding beans in this factory for the specified param types.
521 	 *
522 	 * @param executable The constructor or method to get the params for.
523 	 * @return The corresponding beans in this factory for the specified param types.
524 	 */
525 	public Object[] getParams(ExecutableInfo executable) {
526 		var o = new Object[executable.getParameterCount()];
527 		for (var i = 0; i < executable.getParameterCount(); i++) {
528 			var pi = executable.getParameter(i);
529 			var pt = pi.getParameterType();
530 			if (i == 0 && outer.isPresent() && pt.isInstance(outer.get())) {
531 				o[i] = outer.get();
532 			} else if (pt.is(BeanStore.class)) {
533 				o[i] = this;
534 			} else {
535 				var beanQualifier = pi.getResolvedQualifier();
536 				var ptc = pt.unwrap(Optional.class).inner();
537 				var o2 = beanQualifier == null ? getBean(ptc) : getBean(ptc, beanQualifier);
538 				o[i] = pt.is(Optional.class) ? o2 : o2.orElse(null);
539 			}
540 		}
541 		return o;
542 	}
543 
544 	/**
545 	 * Given the list of param types, returns <jk>true</jk> if this factory has all the parameters for the specified executable.
546 	 *
547 	 * @param executable The constructor or method to get the params for.
548 	 * @return A comma-delimited list of types that are missing from this factory.
549 	 */
550 	public boolean hasAllParams(ExecutableInfo executable) {
551 		loop: for (int i = 0; i < executable.getParameterCount(); i++) {
552 			var pi = executable.getParameter(i);
553 			var pt = pi.getParameterType();
554 			if (i == 0 && outer.isPresent() && pt.isInstance(outer.get()))
555 				continue loop;
556 			if (pt.is(Optional.class) || pt.is(BeanStore.class))
557 				continue loop;
558 			var beanQualifier = pi.getResolvedQualifier();
559 			var ptc = pt.inner();
560 			if ((beanQualifier == null && ! hasBean(ptc)) || (nn(beanQualifier) && ! hasBean(ptc, beanQualifier)))
561 				return false;
562 		}
563 		return true;
564 	}
565 
566 	/**
567 	 * Returns <jk>true</jk> if this store contains the specified unnamed bean type.
568 	 *
569 	 * @param beanType The bean type to check.
570 	 * @return <jk>true</jk> if this store contains the specified unnamed bean type.
571 	 */
572 	public boolean hasBean(Class<?> beanType) {
573 		return unnamedEntries.containsKey(beanType) || parent.map(x -> x.hasBean(beanType)).orElse(false);
574 	}
575 
576 	/**
577 	 * Returns <jk>true</jk> if this store contains the specified named bean type.
578 	 *
579 	 * @param beanType The bean type to check.
580 	 * @param name The bean name.
581 	 * @return <jk>true</jk> if this store contains the specified named bean type.
582 	 */
583 	public boolean hasBean(Class<?> beanType, String name) {
584 		return entries.stream().anyMatch(x -> x.matches(beanType, name)) || parent.map(x -> x.hasBean(beanType, name)).orElse(false);
585 	}
586 
587 	/**
588 	 * Removes an unnamed bean from this store.
589 	 *
590 	 * @param beanType The bean type being removed.
591 	 * @return This object.
592 	 */
593 	public BeanStore removeBean(Class<?> beanType) {
594 		return removeBean(beanType, null);
595 	}
596 
597 	/**
598 	 * Removes a named bean from this store.
599 	 *
600 	 * @param beanType The bean type being removed.
601 	 * @param name The bean name to remove.
602 	 * @return This object.
603 	 */
604 	public BeanStore removeBean(Class<?> beanType, String name) {
605 		assertCanWrite();
606 		try (var x = lock.write()) {
607 			if (name == null)
608 				unnamedEntries.remove(beanType);
609 			entries.removeIf(y -> y.matches(beanType, name));
610 		}
611 		return this;
612 	}
613 
614 	/**
615 	 * Returns all the beans in this store of the specified type.
616 	 *
617 	 * <p>
618 	 * Returns both named and unnamed beans.
619 	 *
620 	 * <p>
621 	 * The results from the parent bean store are appended to the list of beans from this beans store.
622 	 *
623 	 * @param <T> The bean type to return.
624 	 * @param beanType The bean type to return.
625 	 * @return The bean entries.  Never <jk>null</jk>.
626 	 */
627 	public <T> Stream<BeanStoreEntry<T>> stream(Class<T> beanType) {
628 		@SuppressWarnings("unchecked")
629 		var s = entries.stream().filter(x -> x.matches(beanType)).map(x -> (BeanStoreEntry<T>)x);
630 		if (parent.isPresent())
631 			s = Stream.concat(s, parent.get().stream(beanType));
632 		return s;
633 	}
634 
635 	protected FluentMap<String,Object> properties() {
636 		// @formatter:off
637 		return filteredBeanPropertyMap()
638 			.a("entries", entries.stream().map(BeanStoreEntry::properties).collect(toList()))
639 			.a("identity", id(this))
640 			.a("outer", id(outer.orElse(null)))
641 			.a("parent", parent.map(BeanStore::properties).orElse(null))
642 			.ai(readOnly, "readOnly", readOnly)
643 			.ai(threadSafe, "threadSafe", threadSafe);
644 		// @formatter:on
645 	}
646 
647 	@Override /* Overridden from Object */
648 	public String toString() {
649 		return r(properties());
650 	}
651 
652 	private void assertCanWrite() {
653 		if (readOnly)
654 			throw new IllegalStateException("Method cannot be used because BeanStore is read-only.");
655 	}
656 
657 	/**
658 	 * Creates an entry in this store for the specified bean.
659 	 *
660 	 * <p>
661 	 * Subclasses can override this method to create their own entry subtypes.
662 	 *
663 	 * @param <T> The class type to associate with the bean.
664 	 * @param type The class type to associate with the bean.
665 	 * @param bean The bean supplier.
666 	 * @param name Optional name to associate with the bean.  Can be <jk>null</jk>.
667 	 * @return A new bean store entry.
668 	 */
669 	protected <T> BeanStoreEntry<T> createEntry(Class<T> type, Supplier<T> bean, String name) {
670 		return BeanStoreEntry.create(type, bean, name);
671 	}
672 }