• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

TAKETODAY / today-infrastructure / 18154768944

01 Oct 2025 07:26AM UTC coverage: 81.882% (-0.005%) from 81.887%
18154768944

push

github

web-flow
Merge pull request #290 from TAKETODAY/dev/jspecify

jspecify

59788 of 78013 branches covered (76.64%)

Branch coverage included in aggregate %.

141239 of 167496 relevant lines covered (84.32%)

3.6 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.2
today-context/src/main/java/infra/context/BootstrapContext.java
1
/*
2
 * Copyright 2017 - 2025 the original author or authors.
3
 *
4
 * This program is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see [https://www.gnu.org/licenses/]
16
 */
17

18
package infra.context;
19

20
import org.jspecify.annotations.Nullable;
21

22
import java.io.IOException;
23
import java.lang.reflect.Constructor;
24
import java.lang.reflect.Parameter;
25

26
import infra.beans.BeanInstantiationException;
27
import infra.beans.BeanUtils;
28
import infra.beans.factory.Aware;
29
import infra.beans.factory.BeanClassLoaderAware;
30
import infra.beans.factory.BeanFactory;
31
import infra.beans.factory.BeanFactoryAware;
32
import infra.beans.factory.BeanFactoryUtils;
33
import infra.beans.factory.config.BeanDefinition;
34
import infra.beans.factory.config.BeanDefinitionCustomizer;
35
import infra.beans.factory.config.BeanDefinitionCustomizers;
36
import infra.beans.factory.config.ConfigurableBeanFactory;
37
import infra.beans.factory.config.ExpressionEvaluator;
38
import infra.beans.factory.parsing.FailFastProblemReporter;
39
import infra.beans.factory.parsing.Problem;
40
import infra.beans.factory.parsing.ProblemReporter;
41
import infra.beans.factory.support.BeanDefinitionRegistry;
42
import infra.beans.factory.support.BeanNameGenerator;
43
import infra.context.annotation.AnnotationBeanNameGenerator;
44
import infra.context.annotation.AnnotationScopeMetadataResolver;
45
import infra.context.annotation.ConditionEvaluator;
46
import infra.context.annotation.Configuration;
47
import infra.context.annotation.ConfigurationCondition.ConfigurationPhase;
48
import infra.context.annotation.ScopeMetadata;
49
import infra.context.annotation.ScopeMetadataResolver;
50
import infra.core.ConstructorNotFoundException;
51
import infra.core.env.Environment;
52
import infra.core.env.EnvironmentCapable;
53
import infra.core.env.StandardEnvironment;
54
import infra.core.io.DefaultPropertySourceFactory;
55
import infra.core.io.PathMatchingPatternResourceLoader;
56
import infra.core.io.PatternResourceLoader;
57
import infra.core.io.PropertySourceFactory;
58
import infra.core.io.Resource;
59
import infra.core.io.ResourceLoader;
60
import infra.core.type.AnnotatedTypeMetadata;
61
import infra.core.type.AnnotationMetadata;
62
import infra.core.type.classreading.CachingMetadataReaderFactory;
63
import infra.core.type.classreading.MetadataReader;
64
import infra.core.type.classreading.MetadataReaderFactory;
65
import infra.lang.Assert;
66
import infra.lang.ClassInstantiator;
67
import infra.stereotype.Component;
68
import infra.util.CollectionUtils;
69

70
/**
71
 * Startup(Refresh) Context
72
 *
73
 * <p>
74
 * BootstrapContext is can instantiate the class may implement any of the following
75
 * {@link Aware Aware} interfaces
76
 * <ul>
77
 * <li>{@link EnvironmentAware}</li>
78
 * <li>{@link BeanFactoryAware}</li>
79
 * <li>{@link BeanClassLoaderAware}</li>
80
 * <li>{@link ResourceLoaderAware}</li>
81
 * <li>{@link BootstrapContextAware}</li>
82
 * <li>{@link ApplicationContextAware}</li>
83
 * </ul>
84
 * and it's {@link Constructor#getParameters()} can be following types
85
 * <ul>
86
 * <li>{@link Environment}</li>
87
 * <li>{@link BeanFactory}</li>
88
 * <li>{@link ClassLoader}</li>
89
 * <li>{@link ResourceLoader}</li>
90
 * <li>{@link BootstrapContext}</li>
91
 * <li>{@link ApplicationContext}</li>
92
 * <li>{@link BeanDefinitionRegistry}</li>
93
 * <li>{@link ExpressionEvaluator}</li>
94
 * </ul>
95
 * <p>
96
 *  This bootstrap context is containing many components that for context(IoC) startup
97
 *
98
 * @author TODAY 2021/10/19 22:22
99
 * @since 4.0
100
 */
101
public class BootstrapContext extends BeanDefinitionCustomizers implements ClassInstantiator, EnvironmentCapable {
102

103
  public static final String BEAN_NAME = "infra.context.internalBootstrapContext";
104

105
  private final BeanDefinitionRegistry registry;
106

107
  private final ConfigurableBeanFactory beanFactory;
108

109
  @Nullable
110
  private final ApplicationContext applicationContext;
111

112
  @Nullable
113
  ConditionEvaluator conditionEvaluator;
114

115
  @Nullable
116
  private MetadataReaderFactory metadataReaderFactory;
117

118
  @Nullable
119
  private PatternResourceLoader resourceLoader;
120

121
  @Nullable
122
  private ScopeMetadataResolver scopeMetadataResolver;
123

124
  @Nullable
125
  private PropertySourceFactory propertySourceFactory;
126

127
  /* Using short class names as default bean names by default. */
128
  private BeanNameGenerator beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
3✔
129

130
  private ProblemReporter problemReporter = new FailFastProblemReporter();
5✔
131

132
  @Nullable
133
  private Environment environment;
134

135
  @Nullable
136
  ExpressionEvaluator expressionEvaluator;
137

138
  public BootstrapContext(ApplicationContext context) {
139
    this(context.unwrapFactory(ConfigurableBeanFactory.class), context);
7✔
140
  }
1✔
141

142
  public BootstrapContext(ConfigurableBeanFactory beanFactory, @Nullable ApplicationContext context) {
2✔
143
    Assert.notNull(beanFactory, "beanFactory is required");
3✔
144
    this.registry = beanFactory.unwrap(BeanDefinitionRegistry.class);
6✔
145
    this.beanFactory = beanFactory;
3✔
146
    this.resourceLoader = context;
3✔
147
    this.applicationContext = context;
3✔
148
  }
1✔
149

150
  public BootstrapContext(@Nullable Environment environment, ConfigurableBeanFactory beanFactory) {
151
    this(beanFactory, null);
4✔
152
    setEnvironment(environment);
3✔
153
  }
1✔
154

155
  public BeanDefinitionRegistry getRegistry() {
156
    return registry;
3✔
157
  }
158

159
  @Nullable
160
  public ApplicationContext getApplicationContext() {
161
    return applicationContext;
3✔
162
  }
163

164
  @Override
165
  public Environment getEnvironment() {
166
    Environment environment = this.environment;
3✔
167
    if (environment == null) {
2✔
168
      if (applicationContext != null) {
3✔
169
        environment = applicationContext.getEnvironment();
4✔
170
      }
171
      if (environment == null) {
2✔
172
        environment = new StandardEnvironment();
4✔
173
      }
174
      this.environment = environment;
3✔
175
    }
176
    return environment;
2✔
177
  }
178

179
  /**
180
   * Set environment when applicationContext is {@code null}
181
   *
182
   * @param environment Environment
183
   */
184
  public void setEnvironment(@Nullable Environment environment) {
185
    this.environment = environment;
3✔
186
  }
1✔
187

188
  public ConfigurableBeanFactory getBeanFactory() {
189
    return beanFactory;
3✔
190
  }
191

192
  /**
193
   * unwrap bean-factory to {@code requiredType}
194
   *
195
   * @throws IllegalArgumentException not a requiredType
196
   */
197
  public <T> T unwrapFactory(Class<T> requiredType) {
198
    if (applicationContext != null) {
3!
199
      return applicationContext.unwrapFactory(requiredType);
5✔
200
    }
201
    return beanFactory.unwrap(requiredType);
×
202
  }
203

204
  /**
205
   * unwrap this ApplicationContext to {@code requiredType}
206
   *
207
   * @throws IllegalArgumentException not a requiredType
208
   */
209
  public <T> T unwrapContext(Class<T> requiredType) {
210
    Assert.state(applicationContext != null, "No ApplicationContext available");
4!
211
    return applicationContext.unwrap(requiredType);
×
212
  }
213

214
  /**
215
   * Generate a bean name for the given bean definition.
216
   * <p>
217
   * use internal registry
218
   * </p>
219
   *
220
   * @param definition the bean definition to generate a name for
221
   * @return the generated bean name
222
   */
223
  public String generateBeanName(BeanDefinition definition) {
224
    return beanNameGenerator.generateBeanName(definition, registry);
7✔
225
  }
226

227
  public ConditionEvaluator getConditionEvaluator() {
228
    if (conditionEvaluator == null) {
3✔
229
      if (applicationContext != null) {
3✔
230
        this.conditionEvaluator = new ConditionEvaluator(applicationContext, registry);
10✔
231
      }
232
      else {
233
        this.conditionEvaluator = new ConditionEvaluator(getEnvironment(), null, registry);
10✔
234
      }
235
    }
236
    return conditionEvaluator;
3✔
237
  }
238

239
  public void registerBeanDefinition(String beanName, BeanDefinition definition) {
240
    if (definition.getScope() == null) {
3✔
241
      definition.setScope(resolveScopeName(definition));
5✔
242
    }
243

244
    if (CollectionUtils.isNotEmpty(customizers)) {
4✔
245
      for (BeanDefinitionCustomizer definitionCustomizer : customizers) {
11✔
246
        definitionCustomizer.customize(definition);
3✔
247
      }
1✔
248
    }
249
    registry.registerBeanDefinition(beanName, definition);
5✔
250
  }
1✔
251

252
  public void registerAlias(String beanName, String alias) {
253
    registry.registerAlias(beanName, alias);
5✔
254
  }
1✔
255

256
  public boolean containsBeanDefinition(String beanName) {
257
    return registry.containsBeanDefinition(beanName);
5✔
258
  }
259

260
  public void removeBeanDefinition(String beanName) {
261
    registry.removeBeanDefinition(beanName);
4✔
262
  }
1✔
263

264
  public BeanDefinition getBeanDefinition(String beanName) {
265
    return registry.getBeanDefinition(beanName);
5✔
266
  }
267

268
  public boolean passCondition(AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
269
    return getConditionEvaluator().passCondition(metadata, phase);
6✔
270
  }
271

272
  public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
273
    return getConditionEvaluator().shouldSkip(metadata, phase);
6✔
274
  }
275

276
  //---------------------------------------------------------------------
277
  // Instantiator
278
  //---------------------------------------------------------------------
279

280
  /**
281
   * Convenience method to instantiate a class using the given class.
282
   * <p>
283
   * Note that this method tries to set the constructor accessible if given a
284
   * non-accessible (that is, non-public) constructor,
285
   * with optional parameters and default values.
286
   *
287
   * <p>
288
   * This method instantiate the class may implement any of the following
289
   * {@link Aware Aware} interfaces
290
   * <ul>
291
   * <li>{@link EnvironmentAware}</li>
292
   * <li>{@link BeanFactoryAware}</li>
293
   * <li>{@link BeanClassLoaderAware}</li>
294
   * <li>{@link ResourceLoaderAware}</li>
295
   * <li>{@link BootstrapContextAware}</li>
296
   * <li>{@link ApplicationContextAware}</li>
297
   * </ul>
298
   * And it's {@link Constructor#getParameters()} can be following types
299
   * <ul>
300
   * <li>{@link Environment}</li>
301
   * <li>{@link BeanFactory}</li>
302
   * <li>{@link ClassLoader}</li>
303
   * <li>{@link ResourceLoader}</li>
304
   * <li>{@link BootstrapContext}</li>
305
   * <li>{@link ApplicationContext}</li>
306
   * <li>{@link BeanDefinitionRegistry}</li>
307
   * <li>{@link ExpressionEvaluator}</li>
308
   * <li>{@link MetadataReaderFactory}</li>
309
   * </ul>
310
   *
311
   * @see BeanInstantiationException If the bean cannot be instantiated
312
   * @see ConstructorNotFoundException If there is no suitable constructor
313
   */
314
  @Override
315
  @SuppressWarnings("NullAway")
316
  public <T> T instantiate(Class<T> clazz) {
317
    Assert.notNull(clazz, "Class is required");
3✔
318
    if (clazz.isInterface()) {
3✔
319
      throw new BeanInstantiationException(clazz, "Specified class is an interface");
6✔
320
    }
321
    Constructor<T> constructor = BeanUtils.obtainConstructor(clazz);
3✔
322

323
    try {
324
      int i = 0;
2✔
325
      Parameter[] parameters = constructor.getParameters();
3✔
326
      @Nullable Object[] args = new Object[parameters.length];
4✔
327
      for (Parameter parameter : parameters) {
16✔
328
        Object arg = findProvided(parameter);
4✔
329
        args[i++] = arg;
5✔
330
      }
331

332
      T instance = BeanUtils.newInstance(constructor, args);
4✔
333
      invokeAwareMethods(instance);
3✔
334
      return instance;
2✔
335
    }
336
    catch (IllegalStateException ex) {
1✔
337
      throw new BeanInstantiationException(clazz, "No suitable constructor found", ex);
7✔
338
    }
339
  }
340

341
  /**
342
   * Instantiate a class using an appropriate constructor and return the new
343
   * instance as the specified assignable type. The returned instance will
344
   * have {@link BeanClassLoaderAware}, {@link BeanFactoryAware},
345
   * {@link EnvironmentAware}, and {@link ResourceLoaderAware} contracts
346
   * invoked if they are implemented by the given object.
347
   */
348
  @SuppressWarnings("unchecked")
349
  public <T> T instantiate(Class<?> clazz, Class<T> assignableTo) {
350
    Assert.notNull(clazz, "Class is required");
3✔
351
    Assert.isAssignable(assignableTo, clazz);
3✔
352
    return (T) instantiate(clazz);
4✔
353
  }
354

355
  @Nullable
356
  private Object findProvided(Parameter parameter) {
357
    Class<?> parameterType = parameter.getType();
3✔
358
    if (Environment.class.isAssignableFrom(parameterType)
6✔
359
            && parameterType.isInstance(getEnvironment())) {
3!
360
      return getEnvironment();
3✔
361
    }
362
    if (ResourceLoader.class.isAssignableFrom(parameterType)
6✔
363
            && parameterType.isInstance(getResourceLoader())) {
3!
364
      return getResourceLoader();
3✔
365
    }
366
    if (parameterType.isInstance(beanFactory)) {
5✔
367
      return beanFactory;
3✔
368
    }
369
    if (parameterType == ClassLoader.class) {
3✔
370
      return getClassLoader();
3✔
371
    }
372
    if (parameterType == BeanDefinitionRegistry.class) {
3✔
373
      return registry;
3✔
374
    }
375
    if (parameterType == BootstrapContext.class) {
3✔
376
      return this;
2✔
377
    }
378
    if (parameterType.isInstance(applicationContext)) {
5!
379
      return applicationContext;
×
380
    }
381
    if (parameterType == ExpressionEvaluator.class) {
3!
382
      return getExpressionEvaluator();
×
383
    }
384
    if (parameterType == MetadataReaderFactory.class) {
3✔
385
      return getMetadataReaderFactory();
3✔
386
    }
387

388
    throw new IllegalStateException("Illegal method parameter type: " + parameterType.getName());
7✔
389
  }
390

391
  @SuppressWarnings("NullAway")
392
  private void invokeAwareMethods(Object bean) {
393
    if (bean instanceof Aware) {
3✔
394
      if (bean instanceof BeanClassLoaderAware aware) {
6✔
395
        aware.setBeanClassLoader(getClassLoader());
4✔
396
      }
397
      if (bean instanceof BeanFactoryAware aware) {
6✔
398
        aware.setBeanFactory(beanFactory);
4✔
399
      }
400
      if (bean instanceof EnvironmentAware aware) {
6✔
401
        aware.setEnvironment(getEnvironment());
4✔
402
      }
403
      if (bean instanceof ResourceLoaderAware aware) {
6✔
404
        aware.setResourceLoader(getResourceLoader());
4✔
405
      }
406

407
      if (bean instanceof BootstrapContextAware aware) {
6✔
408
        aware.setBootstrapContext(this);
3✔
409
      }
410

411
      if (bean instanceof ApplicationContextAware aware && applicationContext != null) {
3!
412
        aware.setApplicationContext(applicationContext);
×
413
      }
414
    }
415
  }
1✔
416
  //---------------------------------------------------------------------
417
  // MetadataReaderFactory
418
  //---------------------------------------------------------------------
419

420
  /**
421
   * Set the {@link ResourceLoader} to use for resource locations.
422
   * This will typically be a {@link PatternResourceLoader} implementation.
423
   * <p>Default is a {@code PathMatchingPatternResourceLoader}, also capable of
424
   * resource pattern resolving through the {@code PatternResourceLoader} interface.
425
   *
426
   * @see PatternResourceLoader
427
   * @see PathMatchingPatternResourceLoader
428
   */
429
  public void setResourceLoader(@Nullable ResourceLoader resourceLoader) {
430
    this.resourceLoader = PatternResourceLoader.fromResourceLoader(resourceLoader);
4✔
431
    this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
6✔
432
  }
1✔
433

434
  public PatternResourceLoader getResourceLoader() {
435
    if (this.resourceLoader == null) {
3✔
436
      if (applicationContext != null) {
3!
437
        this.resourceLoader = applicationContext;
×
438
      }
439
      else {
440
        this.resourceLoader = new PathMatchingPatternResourceLoader();
5✔
441
      }
442
      // try to bind ResourceLoader to MetadataReaderFactory
443
      if (this.metadataReaderFactory == null) {
3!
444
        this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
7✔
445
      }
446
    }
447
    return this.resourceLoader;
3✔
448
  }
449

450
  public Resource getResource(String location) {
451
    return getResourceLoader().getResource(location);
5✔
452
  }
453

454
  /**
455
   * Set the {@link MetadataReaderFactory} to use.
456
   * <p>Default is a {@link CachingMetadataReaderFactory} for the specified
457
   * {@linkplain #setResourceLoader resource loader}.
458
   * <p>Call this setter method <i>after</i> {@link #setResourceLoader} in order
459
   * for the given MetadataReaderFactory to override the default factory.
460
   */
461
  public void setMetadataReaderFactory(@Nullable MetadataReaderFactory metadataReaderFactory) {
462
    this.metadataReaderFactory = metadataReaderFactory;
3✔
463
  }
1✔
464

465
  /**
466
   * Return the MetadataReaderFactory used by this component provider.
467
   */
468
  @SuppressWarnings("NullAway")
469
  public final MetadataReaderFactory getMetadataReaderFactory() {
470
    if (this.metadataReaderFactory == null) {
3✔
471
      // try to bind ResourceLoader to MetadataReaderFactory
472
      if (this.resourceLoader == null) {
3✔
473
        getResourceLoader();
4✔
474
      }
475
      else {
476
        ResourceLoader resourceLoader;
477
        if (this.resourceLoader instanceof PathMatchingPatternResourceLoader loader) {
6!
478
          resourceLoader = loader.getRootLoader();
×
479
        }
480
        else {
481
          resourceLoader = this.resourceLoader;
3✔
482
        }
483
        this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
6✔
484
      }
485
    }
486
    return this.metadataReaderFactory;
3✔
487
  }
488

489
  public AnnotationMetadata getAnnotationMetadata(String className) throws IOException {
490
    return getMetadataReader(className).getAnnotationMetadata();
5✔
491
  }
492

493
  public MetadataReader getMetadataReader(String className) throws IOException {
494
    MetadataReaderFactory metadataFactory = getMetadataReaderFactory();
3✔
495
    return metadataFactory.getMetadataReader(className);
4✔
496
  }
497

498
  /**
499
   * Clear the local metadata cache, if any, removing all cached class metadata.
500
   */
501
  public void clearCache() {
502
    if (metadataReaderFactory instanceof CachingMetadataReaderFactory cmef) {
9✔
503
      // Clear cache in externally provided MetadataReaderFactory; this is a no-op
504
      // for a shared cache since it'll be cleared by the ApplicationContext.
505
      cmef.clearCache();
2✔
506
    }
507
    if (conditionEvaluator != null) {
3✔
508
      conditionEvaluator.clearCache();
3✔
509
    }
510
  }
1✔
511

512
  //---------------------------------------------------------------------
513
  // ExpressionEvaluator
514
  //---------------------------------------------------------------------
515

516
  /**
517
   * evaluate expression
518
   */
519
  @Nullable
520
  public String evaluateExpression(String expression) {
521
    return evaluateExpression(expression, String.class);
6✔
522
  }
523

524
  /**
525
   * evaluate expression
526
   */
527
  @Nullable
528
  public <T> T evaluateExpression(String expression, Class<T> requiredType) {
529
    return getExpressionEvaluator().evaluate(expression, requiredType);
6✔
530
  }
531

532
  /**
533
   * Get ExpressionEvaluator
534
   */
535
  public ExpressionEvaluator getExpressionEvaluator() {
536
    ExpressionEvaluator expressionEvaluator = this.expressionEvaluator;
3✔
537
    if (expressionEvaluator == null) {
2✔
538
      if (applicationContext != null) {
3✔
539
        expressionEvaluator = applicationContext.getExpressionEvaluator();
5✔
540
      }
541
      else {
542
        expressionEvaluator = ExpressionEvaluator.from(getBeanFactory());
4✔
543
      }
544
      this.expressionEvaluator = expressionEvaluator;
3✔
545
    }
546
    return expressionEvaluator;
2✔
547
  }
548

549
  // ScopeMetadataResolver
550

551
  public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
552
    Assert.notNull(scopeMetadataResolver, "ScopeMetadataResolver is required");
3✔
553
    this.scopeMetadataResolver = scopeMetadataResolver;
3✔
554
  }
1✔
555

556
  public ScopeMetadataResolver getScopeMetadataResolver() {
557
    if (scopeMetadataResolver == null) {
3✔
558
      scopeMetadataResolver = new AnnotationScopeMetadataResolver();
5✔
559
    }
560
    return scopeMetadataResolver;
3✔
561
  }
562

563
  /**
564
   * Get the name of the scope.
565
   *
566
   * @see #resolveScopeMetadata(BeanDefinition)
567
   */
568
  public String resolveScopeName(BeanDefinition definition) {
569
    return resolveScopeMetadata(definition).getScopeName();
5✔
570
  }
571

572
  /**
573
   * Resolve the {@link ScopeMetadata} appropriate to the supplied
574
   * bean {@code definition}.
575
   * <p>Implementations can of course use any strategy they like to
576
   * determine the scope metadata, but some implementations that
577
   * immediately to mind might be to use source level annotations
578
   * present on {@link BeanDefinition#getBeanClassName() the class} of the
579
   * supplied {@code definition}, or to use metadata present in the
580
   * {@link BeanDefinition#getAttributeNames()} of the supplied {@code definition}.
581
   *
582
   * @param definition the target bean definition
583
   * @return the relevant scope metadata; never {@code null}
584
   */
585
  public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
586
    return getScopeMetadataResolver().resolveScopeMetadata(definition);
5✔
587
  }
588

589
  /**
590
   * setting default PropertySourceFactory
591
   *
592
   * @param propertySourceFactory PropertySourceFactory
593
   */
594
  public void setPropertySourceFactory(@Nullable PropertySourceFactory propertySourceFactory) {
595
    this.propertySourceFactory = propertySourceFactory;
×
596
  }
×
597

598
  public PropertySourceFactory getPropertySourceFactory() {
599
    if (propertySourceFactory == null) {
3✔
600
      propertySourceFactory = new DefaultPropertySourceFactory();
5✔
601
    }
602
    return propertySourceFactory;
3✔
603
  }
604

605
  /**
606
   * Set the {@code BeanNameGenerator} to use for detected bean classes.
607
   * <p>The default is a {@link AnnotationBeanNameGenerator}.
608
   */
609
  public void setBeanNameGenerator(@Nullable BeanNameGenerator beanNameGenerator) {
610
    this.beanNameGenerator = beanNameGenerator != null ? beanNameGenerator : AnnotationBeanNameGenerator.INSTANCE;
6!
611
  }
1✔
612

613
  public BeanNameGenerator getBeanNameGenerator() {
614
    return beanNameGenerator;
3✔
615
  }
616

617
  /**
618
   * Set the {@link ProblemReporter} to use.
619
   * <p>Used to register any problems detected with {@link Configuration} or {@link Component}
620
   * declarations. For instance, a @Component method marked as {@code final} is illegal
621
   * and would be reported as a problem. Defaults to {@link FailFastProblemReporter}.
622
   */
623
  public void setProblemReporter(@Nullable ProblemReporter problemReporter) {
624
    this.problemReporter = problemReporter != null ? problemReporter : new FailFastProblemReporter();
6!
625
  }
1✔
626

627
  public ProblemReporter getProblemReporter() {
628
    return problemReporter;
3✔
629
  }
630

631
  public void reportError(Problem problem) {
632
    problemReporter.error(problem);
4✔
633
  }
1✔
634

635
  @Nullable
636
  public ClassLoader getClassLoader() {
637
    ClassLoader classLoader = beanFactory.getBeanClassLoader();
4✔
638
    if (classLoader == null) {
2✔
639
      classLoader = getResourceLoader().getClassLoader();
4✔
640
    }
641
    return classLoader;
2✔
642
  }
643

644
  // static
645

646
  // this method mainly for internal use
647
  public static BootstrapContext obtain(BeanFactory beanFactory) {
648
    Assert.notNull(beanFactory, "beanFactory is required");
3✔
649
    BootstrapContext context = findContext(beanFactory);
3✔
650
    if (context == null) {
2!
651
      synchronized(beanFactory) {
4✔
652
        context = findContext(beanFactory);
3✔
653
        if (context == null) {
2!
654
          ConfigurableBeanFactory factory = beanFactory.unwrap(ConfigurableBeanFactory.class);
5✔
655
          context = new BootstrapContext(factory, deduceContext(beanFactory));
7✔
656
          factory.registerSingleton(BEAN_NAME, context);
4✔
657
        }
658
      }
3✔
659
    }
660
    return context;
2✔
661
  }
662

663
  @Nullable
664
  static ApplicationContext deduceContext(BeanFactory beanFactory) {
665
    if (beanFactory instanceof ApplicationContext context) {
6✔
666
      return context;
2✔
667
    }
668
    return null;
2✔
669
  }
670

671
  @Nullable
672
  private static BootstrapContext findContext(BeanFactory beanFactory) {
673
    return BeanFactoryUtils.findLocal(beanFactory, BEAN_NAME, BootstrapContext.class);
6✔
674
  }
675

676
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc