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

TAKETODAY / today-infrastructure / 18943093076

30 Oct 2025 01:55PM UTC coverage: 83.399% (+0.01%) from 83.385%
18943093076

push

github

TAKETODAY
:bug: Fix potential CRaC hangup after restoring

60836 of 78019 branches covered (77.98%)

Branch coverage included in aggregate %.

143845 of 167405 relevant lines covered (85.93%)

3.66 hits per line

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

94.43
today-context/src/main/java/infra/context/annotation/ConfigurationClassBeanDefinitionReader.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.annotation;
19

20
import org.jspecify.annotations.Nullable;
21

22
import java.io.Serial;
23
import java.lang.reflect.Method;
24
import java.util.HashMap;
25
import java.util.Map;
26
import java.util.Set;
27

28
import infra.beans.factory.BeanDefinitionStoreException;
29
import infra.beans.factory.BeanRegistrar;
30
import infra.beans.factory.annotation.AnnotatedBeanDefinition;
31
import infra.beans.factory.annotation.AnnotatedGenericBeanDefinition;
32
import infra.beans.factory.annotation.DisableAllDependencyInjection;
33
import infra.beans.factory.annotation.DisableDependencyInjection;
34
import infra.beans.factory.annotation.EnableDependencyInjection;
35
import infra.beans.factory.config.BeanDefinition;
36
import infra.beans.factory.config.BeanDefinitionHolder;
37
import infra.beans.factory.support.AbstractBeanDefinition;
38
import infra.beans.factory.support.AbstractBeanDefinitionReader;
39
import infra.beans.factory.support.BeanDefinitionOverrideException;
40
import infra.beans.factory.support.BeanDefinitionReader;
41
import infra.beans.factory.support.BeanDefinitionRegistry;
42
import infra.beans.factory.support.BeanNameGenerator;
43
import infra.beans.factory.support.BeanRegistryAdapter;
44
import infra.beans.factory.support.RootBeanDefinition;
45
import infra.beans.factory.xml.XmlBeanDefinitionReader;
46
import infra.context.BootstrapContext;
47
import infra.core.annotation.MergedAnnotation;
48
import infra.core.annotation.MergedAnnotations;
49
import infra.core.type.AnnotationMetadata;
50
import infra.core.type.MethodMetadata;
51
import infra.core.type.StandardAnnotationMetadata;
52
import infra.core.type.StandardMethodMetadata;
53
import infra.lang.Assert;
54
import infra.logging.Logger;
55
import infra.logging.LoggerFactory;
56
import infra.stereotype.Component;
57
import infra.util.MultiValueMap;
58
import infra.util.ObjectUtils;
59
import infra.util.ReflectionUtils;
60
import infra.util.StringUtils;
61

62
/**
63
 * Reads a given fully-populated set of ConfigurationClass instances, registering bean
64
 * definitions with the given {@link BeanDefinitionRegistry} based on its contents.
65
 *
66
 * @author Chris Beams
67
 * @author Juergen Hoeller
68
 * @author Phillip Webb
69
 * @author Sam Brannen
70
 * @author Sebastien Deleuze
71
 * @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
72
 * @see ConfigurationClassParser
73
 * @since 4.0
74
 */
75
class ConfigurationClassBeanDefinitionReader {
76

77
  private static final Logger logger = LoggerFactory.getLogger(ConfigurationClassBeanDefinitionReader.class);
3✔
78

79
  private static final ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
5✔
80

81
  private final ImportRegistry importRegistry;
82

83
  private final BootstrapContext bootstrapContext;
84

85
  private final BeanNameGenerator importBeanNameGenerator;
86

87
  /**
88
   * Create a new {@link ConfigurationClassBeanDefinitionReader} instance
89
   * that will be used to populate the given {@link BeanDefinitionRegistry}.
90
   */
91
  ConfigurationClassBeanDefinitionReader(BootstrapContext bootstrapContext,
92
          BeanNameGenerator importBeanNameGenerator, ImportRegistry importRegistry) {
2✔
93

94
    this.bootstrapContext = bootstrapContext;
3✔
95
    this.importRegistry = importRegistry;
3✔
96
    this.importBeanNameGenerator = importBeanNameGenerator;
3✔
97
  }
1✔
98

99
  /**
100
   * Read {@code configurationModel}, registering bean definitions
101
   * with the registry based on its contents.
102
   */
103
  public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
104
    TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
5✔
105
    for (ConfigurationClass configClass : configurationModel) {
10✔
106
      loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
4✔
107
    }
1✔
108
  }
1✔
109

110
  /**
111
   * Read a particular {@link ConfigurationClass}, registering bean definitions
112
   * for the class itself and all of its {@link Component} methods.
113
   */
114
  private void loadBeanDefinitionsForConfigurationClass(
115
          ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
116

117
    if (trackedConditionEvaluator.shouldSkip(configClass)) {
4✔
118
      String beanName = configClass.beanName;
3✔
119
      // TODO annotated with both @Component and @ConditionalOnMissingBean,condition matching error
120
      if (StringUtils.isNotEmpty(beanName) && bootstrapContext.containsBeanDefinition(beanName)) {
8!
121
        bootstrapContext.removeBeanDefinition(beanName);
4✔
122
      }
123
      importRegistry.removeImportingClass(configClass.metadata.getClassName());
6✔
124
    }
1✔
125
    else {
126
      boolean disableAllDependencyInjection = isDisableAllDependencyInjection(configClass);
4✔
127
      if (configClass.isImported()) {
3✔
128
        registerBeanDefinitionForImportedConfigurationClass(configClass, disableAllDependencyInjection);
4✔
129
      }
130

131
      for (ComponentMethod componentMethod : configClass.componentMethods) {
11✔
132
        loadBeanDefinitionsForComponentMethod(componentMethod, disableAllDependencyInjection);
4✔
133
      }
1✔
134

135
      loadBeanDefinitionsFromImportedResources(configClass.importedResources);
4✔
136
      loadBeanDefinitionsFromImportBeanDefinitionRegistrars(configClass.importBeanDefinitionRegistrars);
4✔
137
      loadBeanDefinitionsFromBeanRegistrars(configClass.beanRegistrars);
4✔
138
    }
139
  }
1✔
140

141
  /**
142
   * Register the {@link Configuration} class itself as a bean definition.
143
   */
144
  private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass, boolean disableAllDependencyInjection) {
145
    var configBeanDef = new AnnotatedGenericBeanDefinition(configClass.metadata);
6✔
146

147
    ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
4✔
148
    configBeanDef.setScope(scopeMetadata.getScopeName());
4✔
149
    // import bean name
150
    String configBeanName = importBeanNameGenerator.generateBeanName(configBeanDef, bootstrapContext.getRegistry());
8✔
151
    AnnotationConfigUtils.applyAnnotationMetadata(configBeanDef, false);
3✔
152

153
    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
6✔
154
    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, bootstrapContext.getRegistry());
7✔
155
    bootstrapContext.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
7✔
156
    configClass.setBeanName(configBeanName);
3✔
157

158
    boolean enableDependencyInjection = isEnableDependencyInjection(configClass.metadata.getAnnotations(), disableAllDependencyInjection);
7✔
159
    configBeanDef.setEnableDependencyInjection(enableDependencyInjection);
3✔
160

161
    if (logger.isTraceEnabled()) {
3!
162
      logger.trace("Registered bean definition for imported class '{}'", configBeanName);
×
163
    }
164
  }
1✔
165

166
  /**
167
   * Read the given {@link ComponentMethod}, registering bean definitions
168
   * with the BeanDefinitionRegistry based on its contents.
169
   */
170
  private void loadBeanDefinitionsForComponentMethod(ComponentMethod componentMethod, boolean disableAllDependencyInjection) {
171
    ConfigurationClass configClass = componentMethod.configurationClass;
3✔
172
    MethodMetadata metadata = componentMethod.metadata;
3✔
173
    String methodName = metadata.getMethodName();
3✔
174

175
    // Do we need to mark the bean as skipped by its condition?
176
    if (bootstrapContext.shouldSkip(metadata, ConfigurationCondition.ConfigurationPhase.REGISTER_BEAN)) {
6✔
177
      configClass.skippedComponentMethods.add(methodName);
5✔
178
      return;
1✔
179
    }
180
    if (configClass.skippedComponentMethods.contains(methodName)) {
5!
181
      return;
×
182
    }
183
    MergedAnnotations annotations = metadata.getAnnotations();
3✔
184
    MergedAnnotation<Component> component = annotations.get(Component.class);
4✔
185
    Assert.state(component.isPresent(), "No @Component annotation attributes");
4✔
186

187
    // Consider name and any aliases.
188
    String[] explicitNames = component.getStringArray("name");
4✔
189
    String beanName = (explicitNames.length > 0 && StringUtils.hasText(explicitNames[0])) ? explicitNames[0] : null;
14!
190
    String localBeanName = defaultBeanName(beanName, methodName);
4✔
191
    beanName = this.importBeanNameGenerator instanceof ConfigurationBeanNameGenerator cbng ?
9✔
192
            cbng.deriveBeanName(metadata, beanName) : defaultBeanName(beanName, methodName);
9✔
193
    if (explicitNames.length > 0) {
3✔
194
      // Register aliases even when overridden below.
195
      for (int i = 1; i < explicitNames.length; i++) {
8✔
196
        bootstrapContext.registerAlias(beanName, explicitNames[i]);
7✔
197
      }
198
    }
199

200
    var beanDef = new ConfigurationClassBeanDefinition(configClass, metadata, localBeanName);
7✔
201
    beanDef.setSource(configClass.resource);
4✔
202
    beanDef.setResource(configClass.resource);
4✔
203

204
    // Has this effectively been overridden before (e.g. via XML)?
205
    if (isOverriddenByExistingDefinition(componentMethod, beanName, beanDef)) {
6✔
206
      if (beanName.equals(componentMethod.configurationClass.beanName)) {
6✔
207
        throw new BeanDefinitionStoreException(componentMethod.configurationClass.resource.toString(),
14✔
208
                beanName, ("Bean name derived from @Component method '%s' clashes with bean name for containing configuration class; " +
209
                "please make those names unique!").formatted(componentMethod.metadata.getMethodName()));
5✔
210
      }
211
      return;
1✔
212
    }
213

214
    boolean enableDI = isEnableDependencyInjection(annotations, disableAllDependencyInjection);
5✔
215
    beanDef.setEnableDependencyInjection(enableDI);
3✔
216

217
    AnnotationMetadata configClassMetadata = configClass.metadata;
3✔
218
    if (metadata.isStatic()) {
3✔
219
      // static @Component method
220
      if (configClassMetadata instanceof StandardAnnotationMetadata) {
3✔
221
        beanDef.setBeanClass(((StandardAnnotationMetadata) configClassMetadata).getIntrospectedClass());
6✔
222
      }
223
      else {
224
        beanDef.setBeanClassName(configClassMetadata.getClassName());
4✔
225
      }
226
      beanDef.setUniqueFactoryMethodName(methodName);
4✔
227
    }
228
    else {
229
      // instance @Component method
230
      beanDef.setFactoryBeanName(configClass.beanName);
4✔
231
      beanDef.setUniqueFactoryMethodName(methodName);
3✔
232
    }
233

234
    if (metadata instanceof StandardMethodMetadata smm && configClass.metadata instanceof StandardAnnotationMetadata sam) {
15!
235
      Method method = ReflectionUtils.getMostSpecificMethod(smm.getIntrospectedMethod(), sam.getIntrospectedClass());
6✔
236
      if (method == smm.getIntrospectedMethod()) {
4✔
237
        beanDef.setResolvedFactoryMethod(method);
3✔
238
      }
239
    }
240

241
    beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
3✔
242
    AnnotationConfigUtils.applyAnnotationMetadata(beanDef, false);
3✔
243

244
    if (!component.getBoolean("autowireCandidate")) {
4✔
245
      beanDef.setAutowireCandidate(false);
3✔
246
    }
247

248
    if (!component.getBoolean("defaultCandidate")) {
4✔
249
      beanDef.setDefaultCandidate(false);
3✔
250
    }
251

252
    var instantiation = component.getEnum("bootstrap", Component.Bootstrap.class);
6✔
253
    if (instantiation == Component.Bootstrap.BACKGROUND) {
3✔
254
      beanDef.setBackgroundInit(true);
3✔
255
    }
256

257
    String[] initMethodName = component.getStringArray("initMethods");
4✔
258
    if (ObjectUtils.isNotEmpty(initMethodName)) {
3✔
259
      beanDef.setInitMethodNames(initMethodName);
3✔
260
    }
261

262
    String destroyMethodName = component.getString("destroyMethod");
4✔
263
    beanDef.setDestroyMethodName(destroyMethodName);
3✔
264

265
    // Consider scoping
266
    ScopedProxyMode proxyMode = ScopedProxyMode.NO;
2✔
267
    MergedAnnotation<Scope> scope = annotations.get(Scope.class);
4✔
268
    if (scope.isPresent()) {
3✔
269
      beanDef.setScope(scope.getString("value"));
5✔
270
      proxyMode = scope.getEnum("proxyMode", ScopedProxyMode.class);
6✔
271
      if (proxyMode == ScopedProxyMode.DEFAULT) {
3✔
272
        proxyMode = ScopedProxyMode.NO;
2✔
273
      }
274
    }
275

276
    // Replace the original bean definition with the target one, if necessary
277
    BeanDefinition beanDefToRegister;
278
    if (proxyMode != ScopedProxyMode.NO) {
3✔
279
      BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(new BeanDefinitionHolder(beanDef, beanName),
9✔
280
              bootstrapContext.getRegistry(), proxyMode == ScopedProxyMode.TARGET_CLASS);
7✔
281
      beanDefToRegister = new ConfigurationClassBeanDefinition(
3✔
282
              (RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata, localBeanName);
7✔
283
    }
1✔
284
    else {
285
      beanDefToRegister = beanDef;
2✔
286
    }
287

288
    // Replace the original bean definition with the target one, if necessary
289
    if (logger.isTraceEnabled()) {
3!
290
      logger.trace("Registering bean definition for @Component method {}.{}()",
×
291
              configClassMetadata.getClassName(), beanName);
×
292
    }
293

294
    bootstrapContext.registerBeanDefinition(beanName, beanDefToRegister);
5✔
295
  }
1✔
296

297
  private static String defaultBeanName(@Nullable String beanName, String methodName) {
298
    return beanName != null ? beanName : methodName;
6✔
299
  }
300

301
  /**
302
   * disable all member class DI
303
   *
304
   * @param configClass current config class
305
   */
306
  private boolean isDisableAllDependencyInjection(ConfigurationClass configClass) {
307
    if (!configClass.metadata.isAnnotated(DisableAllDependencyInjection.class)) {
5✔
308
      try {
309
        String enclosingClassName = configClass.metadata.getEnclosingClassName();
4✔
310
        while (enclosingClassName != null) {
2✔
311
          AnnotationMetadata enclosingMetadata = bootstrapContext.getAnnotationMetadata(enclosingClassName);
5✔
312
          if (enclosingMetadata.isAnnotated(DisableAllDependencyInjection.class)) {
4✔
313
            return true;
2✔
314
          }
315
          enclosingClassName = enclosingMetadata.getEnclosingClassName();
3✔
316
        }
1✔
317
      }
318
      catch (Exception e) {
1✔
319
        logger.error("Failed to read class file via ASM for determining DI status order", e);
4✔
320
      }
1✔
321
      return false;
2✔
322
    }
323
    return true;
2✔
324
  }
325

326
  private boolean isEnableDependencyInjection(MergedAnnotations annotations, boolean disableAllDependencyInjection) {
327
    return annotations.isPresent(EnableDependencyInjection.class)
9✔
328
            || !(disableAllDependencyInjection || annotations.isPresent(DisableDependencyInjection.class));
5✔
329
  }
330

331
  @SuppressWarnings("NullAway")
332
  private boolean isOverriddenByExistingDefinition(ComponentMethod componentMethod, String beanName, ConfigurationClassBeanDefinition newBeanDef) {
333
    if (!bootstrapContext.containsBeanDefinition(beanName)) {
5✔
334
      return false;
2✔
335
    }
336
    BeanDefinition existingBeanDef = bootstrapContext.getBeanDefinition(beanName);
5✔
337
    ConfigurationClass configClass = componentMethod.configurationClass;
3✔
338

339
    // If the bean method is an overloaded case on the same configuration class,
340
    // preserve the existing bean definition and mark it as overloaded.
341
    if (existingBeanDef instanceof ConfigurationClassBeanDefinition ccbd) {
6✔
342
      if (!ccbd.getMetadata().getClassName().equals(configClass.metadata.getClassName())) {
8✔
343
        return false;
2✔
344
      }
345
      if (ccbd.getFactoryMethodMetadata().getMethodName().equals(componentMethod.metadata.getMethodName())) {
8✔
346
        ccbd.setNonUniqueFactoryMethodName(ccbd.getFactoryMethodMetadata().getMethodName());
5✔
347
        return true;
2✔
348
      }
349
      Map<String, Object> attributes = configClass.metadata.getAnnotationAttributes(Configuration.class);
5✔
350
      if ((attributes != null && (Boolean) attributes.get("enforceUniqueMethods"))
10!
351
              || !bootstrapContext.getRegistry().isBeanDefinitionOverridable(beanName)) {
4✔
352
        throw new BeanDefinitionOverrideException(beanName, newBeanDef, existingBeanDef,
10✔
353
                "@Bean method override with same bean name but different method name: " + existingBeanDef);
354
      }
355
      return true;
2✔
356
    }
357

358
    // A bean definition resulting from a component scan can be silently overridden
359
    // by an @Component method, even when general overriding is disabled
360
    // as long as the bean class is the same.
361
    if (existingBeanDef instanceof ScannedGenericBeanDefinition scannedBeanDef) {
6✔
362
      if (componentMethod.metadata.getReturnTypeName().equals(scannedBeanDef.getBeanClassName())) {
7!
363
        bootstrapContext.removeBeanDefinition(beanName);
4✔
364
      }
365
      return false;
2✔
366
    }
367

368
    // Has the existing bean definition bean marked as a framework-generated bean?
369
    // -> allow the current bean method to override it, since it is application-level
370
    if (existingBeanDef.getRole() > BeanDefinition.ROLE_APPLICATION) {
3✔
371
      return false;
2✔
372
    }
373

374
    // At this point, it's a top-level override (probably XML), just having been parsed
375
    // before configuration class processing kicks in...
376
    if (!bootstrapContext.getRegistry().isBeanDefinitionOverridable(beanName)) {
6✔
377
      throw new BeanDefinitionOverrideException(beanName, newBeanDef,
10✔
378
              existingBeanDef, "@Component definition illegally overridden by existing bean definition: " + existingBeanDef);
379
    }
380
    if (logger.isDebugEnabled()) {
3!
381
      logger.debug("Skipping bean definition for {}: a definition for bean '{}' " +
×
382
              "already exists. This top-level bean definition is considered as an override.", componentMethod, beanName);
383
    }
384
    return true;
2✔
385
  }
386

387
  private void loadBeanDefinitionsFromImportedResources(Map<String, Class<? extends BeanDefinitionReader>> importedResources) {
388
    HashMap<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>();
4✔
389

390
    for (Map.Entry<String, Class<? extends BeanDefinitionReader>> entry : importedResources.entrySet()) {
11✔
391
      String resource = entry.getKey();
4✔
392
      Class<? extends BeanDefinitionReader> readerClass = entry.getValue();
4✔
393
      // Default reader selection necessary?
394
      if (BeanDefinitionReader.class == readerClass) {
3!
395
        // Primarily ".xml" files but for any other extension as well
396
        readerClass = XmlBeanDefinitionReader.class;
2✔
397
      }
398

399
      BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
5✔
400
      if (reader == null) {
2✔
401
        try {
402
          // Instantiate the specified BeanDefinitionReader
403
          reader = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(bootstrapContext.getRegistry());
19✔
404
          // Delegate the current ResourceLoader to it if possible
405
          if (reader instanceof AbstractBeanDefinitionReader abdr) {
6!
406
            abdr.setEnvironment(bootstrapContext.getEnvironment());
5✔
407
            abdr.setResourceLoader(bootstrapContext.getResourceLoader());
5✔
408
          }
409
          readerInstanceCache.put(readerClass, reader);
5✔
410
        }
411
        catch (Throwable ex) {
×
412
          throw new IllegalStateException("Could not instantiate BeanDefinitionReader class [%s]"
×
413
                  .formatted(readerClass.getName()), ex);
×
414
        }
1✔
415
      }
416

417
      reader.loadBeanDefinitions(resource);
4✔
418
    }
1✔
419

420
  }
1✔
421

422
  private void loadBeanDefinitionsFromImportBeanDefinitionRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
423
    for (var entry : registrars.entrySet()) {
11✔
424
      entry.getKey().registerBeanDefinitions(entry.getValue(), bootstrapContext, importBeanNameGenerator);
11✔
425
    }
1✔
426
  }
1✔
427

428
  private void loadBeanDefinitionsFromBeanRegistrars(MultiValueMap<String, BeanRegistrar> registrars) {
429
    for (var registrarList : registrars.values()) {
11✔
430
      for (BeanRegistrar registrar : registrarList) {
10✔
431
        registrar.register(new BeanRegistryAdapter(bootstrapContext.getRegistry(),
9✔
432
                bootstrapContext.getBeanFactory(), bootstrapContext.getEnvironment(), registrar.getClass()), bootstrapContext.getEnvironment());
10✔
433
      }
1✔
434
    }
1✔
435
  }
1✔
436

437
  /**
438
   * Evaluate {@code @Conditional} annotations, tracking results and taking into
439
   * account 'imported by'.
440
   */
441
  private final class TrackedConditionEvaluator {
5✔
442

443
    private final HashMap<ConfigurationClass, Boolean> skipped = new HashMap<>();
6✔
444

445
    public boolean shouldSkip(ConfigurationClass configClass) {
446
      Boolean skip = this.skipped.get(configClass);
6✔
447
      if (skip == null) {
2✔
448
        if (configClass.isImported()) {
3✔
449
          boolean allSkipped = true;
2✔
450
          for (ConfigurationClass importedBy : configClass.importedBy) {
11✔
451
            if (!shouldSkip(importedBy)) {
4✔
452
              allSkipped = false;
2✔
453
              break;
1✔
454
            }
455
          }
1✔
456
          if (allSkipped) {
2✔
457
            // The config classes that imported this one were all skipped, therefore we are skipped...
458
            skip = true;
3✔
459
          }
460
        }
461
        if (skip == null) {
2✔
462
          skip = bootstrapContext.shouldSkip(configClass.metadata, ConfigurationCondition.ConfigurationPhase.REGISTER_BEAN);
9✔
463
        }
464
        this.skipped.put(configClass, skip);
6✔
465
      }
466
      return skip;
3✔
467
    }
468
  }
469

470
  /**
471
   * {@link RootBeanDefinition} marker subclass used to signify that a bean definition
472
   * was created from a configuration class as opposed to any other configuration source.
473
   * Used in bean overriding cases where it's necessary to determine whether the bean
474
   * definition was created externally.
475
   */
476
  private static final class ConfigurationClassBeanDefinition extends RootBeanDefinition
477
          implements AnnotatedBeanDefinition {
478

479
    @Serial
480
    private static final long serialVersionUID = 1L;
481

482
    private final AnnotationMetadata annotationMetadata;
483

484
    private final MethodMetadata factoryMethodMetadata;
485

486
    private final String localBeanName;
487

488
    public ConfigurationClassBeanDefinition(ConfigurationClass configClass,
489
            MethodMetadata beanMethodMetadata, String localBeanName) {
2✔
490

491
      this.annotationMetadata = configClass.metadata;
4✔
492
      this.factoryMethodMetadata = beanMethodMetadata;
3✔
493
      this.localBeanName = localBeanName;
3✔
494
      setResource(configClass.resource);
4✔
495
      setLenientConstructorResolution(false);
3✔
496
    }
1✔
497

498
    public ConfigurationClassBeanDefinition(RootBeanDefinition original,
499
            ConfigurationClass configClass, MethodMetadata beanMethodMetadata, String localBeanName) {
500
      super(original);
3✔
501
      this.annotationMetadata = configClass.metadata;
4✔
502
      this.factoryMethodMetadata = beanMethodMetadata;
3✔
503
      this.localBeanName = localBeanName;
3✔
504
    }
1✔
505

506
    private ConfigurationClassBeanDefinition(ConfigurationClassBeanDefinition original) {
507
      super(original);
3✔
508
      this.annotationMetadata = original.annotationMetadata;
4✔
509
      this.factoryMethodMetadata = original.factoryMethodMetadata;
4✔
510
      this.localBeanName = original.localBeanName;
4✔
511
    }
1✔
512

513
    @Override
514
    public AnnotationMetadata getMetadata() {
515
      return this.annotationMetadata;
3✔
516
    }
517

518
    @Override
519
    public MethodMetadata getFactoryMethodMetadata() {
520
      return this.factoryMethodMetadata;
3✔
521
    }
522

523
    @Override
524
    public boolean isFactoryMethod(Method candidate) {
525
      return super.isFactoryMethod(candidate)
6✔
526
              && BeanAnnotationHelper.isBeanAnnotated(candidate)
3✔
527
              && BeanAnnotationHelper.determineBeanNameFor(candidate).equals(localBeanName);
8✔
528
    }
529

530
    @Override
531
    public ConfigurationClassBeanDefinition cloneBeanDefinition() {
532
      return new ConfigurationClassBeanDefinition(this);
5✔
533
    }
534
  }
535

536
}
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