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

TAKETODAY / today-infrastructure / 6100547694

06 Sep 2023 05:42PM UTC coverage: 77.72% (-0.02%) from 77.736%
6100547694

push

github

TAKETODAY
:bug:

61545 of 83980 branches covered (0.0%)

Branch coverage included in aggregate %.

153278 of 192427 relevant lines covered (79.66%)

3.37 hits per line

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

96.13
today-context/src/main/java/cn/taketoday/context/annotation/ConfigurationClassBeanDefinitionReader.java
1
/*
2
 * Copyright 2017 - 2023 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 [http://www.gnu.org/licenses/]
16
 */
17

18
package cn.taketoday.context.annotation;
19

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

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

59
/**
60
 * Reads a given fully-populated set of ConfigurationClass instances, registering bean
61
 * definitions with the given {@link BeanDefinitionRegistry} based on its contents.
62
 *
63
 * @author Chris Beams
64
 * @author Juergen Hoeller
65
 * @author Phillip Webb
66
 * @author Sam Brannen
67
 * @author Sebastien Deleuze
68
 * @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
69
 * @see ConfigurationClassParser
70
 * @since 4.0
71
 */
72
class ConfigurationClassBeanDefinitionReader {
73
  private static final Logger logger = LoggerFactory.getLogger(ConfigurationClassBeanDefinitionReader.class);
3✔
74
  private static final ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
5✔
75

76
  private final ImportRegistry importRegistry;
77
  private final BootstrapContext bootstrapContext;
78
  private final BeanNameGenerator importBeanNameGenerator;
79

80
  /**
81
   * Create a new {@link ConfigurationClassBeanDefinitionReader} instance
82
   * that will be used to populate the given {@link BeanDefinitionRegistry}.
83
   */
84
  ConfigurationClassBeanDefinitionReader(BootstrapContext bootstrapContext,
85
          BeanNameGenerator beanNameGenerator, ImportRegistry importRegistry) {
2✔
86

87
    this.bootstrapContext = bootstrapContext;
3✔
88
    this.importRegistry = importRegistry;
3✔
89
    this.importBeanNameGenerator = beanNameGenerator;
3✔
90
  }
1✔
91

92
  /**
93
   * Read {@code configurationModel}, registering bean definitions
94
   * with the registry based on its contents.
95
   */
96
  public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
97
    TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
5✔
98
    for (ConfigurationClass configClass : configurationModel) {
10✔
99
      loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
4✔
100
    }
1✔
101
  }
1✔
102

103
  /**
104
   * Read a particular {@link ConfigurationClass}, registering bean definitions
105
   * for the class itself and all of its {@link Component} methods.
106
   */
107
  private void loadBeanDefinitionsForConfigurationClass(
108
          ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
109

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

124
      for (ComponentMethod componentMethod : configClass.componentMethods) {
11✔
125
        loadBeanDefinitionsForComponentMethod(componentMethod, disableAllDependencyInjection);
4✔
126
      }
1✔
127

128
      loadBeanDefinitionsFromImportedResources(configClass.importedResources);
4✔
129
      loadBeanDefinitionsFromRegistrars(configClass.importBeanDefinitionRegistrars);
4✔
130
    }
131
  }
1✔
132

133
  /**
134
   * Register the {@link Configuration} class itself as a bean definition.
135
   */
136
  private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass, boolean disableAllDependencyInjection) {
137
    var configBeanDef = new AnnotatedGenericBeanDefinition(configClass.metadata);
6✔
138

139
    ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
4✔
140
    configBeanDef.setScope(scopeMetadata.getScopeName());
4✔
141
    String configBeanName = importBeanNameGenerator.generateBeanName(configBeanDef, bootstrapContext.getRegistry());
8✔
142
    AnnotationConfigUtils.applyAnnotationMetadata(configBeanDef, false);
3✔
143

144
    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
6✔
145
    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(
6✔
146
            scopeMetadata, definitionHolder, bootstrapContext.getRegistry());
1✔
147
    bootstrapContext.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
7✔
148
    configClass.setBeanName(configBeanName);
3✔
149

150
    boolean enableDependencyInjection = isEnableDependencyInjection(configClass.metadata.getAnnotations(), disableAllDependencyInjection);
7✔
151
    configBeanDef.setEnableDependencyInjection(enableDependencyInjection);
3✔
152

153
    if (logger.isTraceEnabled()) {
3!
154
      logger.trace("Registered bean definition for imported class '{}'", configBeanName);
×
155
    }
156
  }
1✔
157

158
  /**
159
   * Read the given {@link ComponentMethod}, registering bean definitions
160
   * with the BeanDefinitionRegistry based on its contents.
161
   */
162
  private void loadBeanDefinitionsForComponentMethod(ComponentMethod componentMethod, boolean disableAllDependencyInjection) {
163
    ConfigurationClass configClass = componentMethod.configurationClass;
3✔
164
    MethodMetadata methodMetadata = componentMethod.metadata;
3✔
165
    String methodName = methodMetadata.getMethodName();
3✔
166

167
    // Do we need to mark the bean as skipped by its condition?
168
    if (bootstrapContext.shouldSkip(methodMetadata, ConfigurationPhase.REGISTER_BEAN)) {
6✔
169
      configClass.skippedComponentMethods.add(methodName);
5✔
170
      return;
1✔
171
    }
172
    if (configClass.skippedComponentMethods.contains(methodName)) {
5✔
173
      return;
1✔
174
    }
175
    MergedAnnotations annotations = methodMetadata.getAnnotations();
3✔
176
    MergedAnnotation<Component> component = annotations.get(Component.class);
4✔
177
    Assert.state(component.isPresent(), "No @Component annotation attributes");
4✔
178

179
    // Consider name and any aliases
180
    ArrayList<String> names = CollectionUtils.newArrayList(component.getStringArray("name"));
5✔
181
    String beanName = !names.isEmpty() ? names.remove(0) : methodName;
10✔
182

183
    // Register aliases even when overridden
184
    for (String alias : names) {
10✔
185
      bootstrapContext.registerAlias(beanName, alias);
5✔
186
    }
1✔
187

188
    // Has this effectively been overridden before (e.g. via XML)?
189
    if (isOverriddenByExistingDefinition(componentMethod, beanName)) {
5✔
190
      if (beanName.equals(componentMethod.configurationClass.beanName)) {
6✔
191
        throw new BeanDefinitionStoreException(componentMethod.configurationClass.resource.toString(),
9✔
192
                beanName, "Bean name derived from @Component method '" + componentMethod.metadata.getMethodName() +
4✔
193
                "' clashes with bean name for containing configuration class; please make those names unique!");
194
      }
195
      return;
1✔
196
    }
197

198
    ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, methodMetadata, beanName);
7✔
199
    beanDef.setSource(configClass.resource);
4✔
200
    beanDef.setResource(configClass.resource);
4✔
201

202
    boolean enableDI = isEnableDependencyInjection(annotations, disableAllDependencyInjection);
5✔
203
    beanDef.setEnableDependencyInjection(enableDI);
3✔
204

205
    AnnotationMetadata configClassMetadata = configClass.metadata;
3✔
206
    if (methodMetadata.isStatic()) {
3✔
207
      // static @Component method
208
      if (configClassMetadata instanceof StandardAnnotationMetadata) {
3✔
209
        beanDef.setBeanClass(((StandardAnnotationMetadata) configClassMetadata).getIntrospectedClass());
6✔
210
      }
211
      else {
212
        beanDef.setBeanClassName(configClassMetadata.getClassName());
4✔
213
      }
214
      beanDef.setUniqueFactoryMethodName(methodName);
4✔
215
    }
216
    else {
217
      // instance @Component method
218
      beanDef.setFactoryBeanName(configClass.beanName);
4✔
219
      beanDef.setUniqueFactoryMethodName(methodName);
3✔
220
    }
221
    if (methodMetadata instanceof StandardMethodMetadata sam) {
6✔
222
      beanDef.setResolvedFactoryMethod(sam.getIntrospectedMethod());
4✔
223
    }
224

225
    beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
3✔
226
    AnnotationConfigUtils.applyAnnotationMetadata(beanDef, false);
3✔
227

228
    if (!component.getBoolean("autowireCandidate")) {
4✔
229
      beanDef.setAutowireCandidate(false);
3✔
230
    }
231

232
    String[] initMethodName = component.getStringArray("initMethods");
4✔
233
    if (ObjectUtils.isNotEmpty(initMethodName)) {
3✔
234
      beanDef.setInitMethodNames(initMethodName);
3✔
235
    }
236

237
    String destroyMethodName = component.getString("destroyMethod");
4✔
238
    beanDef.setDestroyMethodName(destroyMethodName);
3✔
239

240
    // Consider scoping
241
    ScopedProxyMode proxyMode = ScopedProxyMode.NO;
2✔
242
    MergedAnnotation<Scope> scope = annotations.get(Scope.class);
4✔
243
    if (scope.isPresent()) {
3✔
244
      beanDef.setScope(scope.getString("value"));
5✔
245
      proxyMode = scope.getEnum("proxyMode", ScopedProxyMode.class);
6✔
246
      if (proxyMode == ScopedProxyMode.DEFAULT) {
3✔
247
        proxyMode = ScopedProxyMode.NO;
2✔
248
      }
249
    }
250

251
    // Replace the original bean definition with the target one, if necessary
252
    BeanDefinition beanDefToRegister;
253
    if (proxyMode != ScopedProxyMode.NO) {
3✔
254
      BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
9✔
255
              new BeanDefinitionHolder(beanDef, beanName), bootstrapContext.getRegistry(), proxyMode == ScopedProxyMode.TARGET_CLASS);
7✔
256
      beanDefToRegister = new ConfigurationClassBeanDefinition(
3✔
257
              (RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, methodMetadata, beanName);
7✔
258
    }
1✔
259
    else {
260
      beanDefToRegister = beanDef;
2✔
261
    }
262

263
    // Replace the original bean definition with the target one, if necessary
264
    if (logger.isTraceEnabled()) {
3!
265
      logger.trace("Registering bean definition for @Component method {}.{}()",
×
266
              configClassMetadata.getClassName(), beanName);
×
267
    }
268

269
    bootstrapContext.registerBeanDefinition(beanName, beanDefToRegister);
5✔
270
  }
1✔
271

272
  /**
273
   * disable all member class DI
274
   *
275
   * @param configClass current config class
276
   */
277
  private boolean isDisableAllDependencyInjection(ConfigurationClass configClass) {
278
    if (!configClass.metadata.isAnnotated(DisableAllDependencyInjection.class)) {
5✔
279
      try {
280
        String enclosingClassName = configClass.metadata.getEnclosingClassName();
4✔
281
        while (enclosingClassName != null) {
2✔
282
          AnnotationMetadata enclosingMetadata = bootstrapContext.getAnnotationMetadata(enclosingClassName);
5✔
283
          if (enclosingMetadata.isAnnotated(DisableAllDependencyInjection.class)) {
4✔
284
            return true;
2✔
285
          }
286
          enclosingClassName = enclosingMetadata.getEnclosingClassName();
3✔
287
        }
1✔
288
      }
289
      catch (Exception e) {
1✔
290
        logger.error("Failed to read class file via ASM for determining DI status order", e);
4✔
291
      }
1✔
292
      return false;
2✔
293
    }
294
    return true;
2✔
295
  }
296

297
  private boolean isEnableDependencyInjection(MergedAnnotations annotations, boolean disableAllDependencyInjection) {
298
    return annotations.isPresent(EnableDependencyInjection.class)
9✔
299
            || !(disableAllDependencyInjection || annotations.isPresent(DisableDependencyInjection.class));
5✔
300
  }
301

302
  protected boolean isOverriddenByExistingDefinition(ComponentMethod componentMethod, String beanName) {
303
    if (!bootstrapContext.containsBeanDefinition(beanName)) {
5✔
304
      return false;
2✔
305
    }
306
    BeanDefinition existingBeanDef = bootstrapContext.getBeanDefinition(beanName);
5✔
307

308
    // Is the existing bean definition one that was created from a configuration class?
309
    // -> allow the current bean method to override, since both are at second-pass level.
310
    // However, if the bean method is an overloaded case on the same configuration class,
311
    // preserve the existing bean definition.
312
    if (existingBeanDef instanceof ConfigurationClassBeanDefinition ccbd) {
6✔
313
      if (ccbd.getMetadata().getClassName().equals(
8✔
314
              componentMethod.configurationClass.metadata.getClassName())) {
1✔
315
        if (ccbd.getFactoryMethodMetadata().getMethodName().equals(ccbd.getFactoryMethodName())) {
7!
316
          ccbd.setNonUniqueFactoryMethodName(ccbd.getFactoryMethodMetadata().getMethodName());
5✔
317
        }
318
        return true;
2✔
319
      }
320
      else {
321
        return false;
2✔
322
      }
323
    }
324

325
    // A bean definition resulting from a component scan can be silently overridden
326
    // by an @Component method, even when general overriding is disabled
327
    // as long as the bean class is the same.
328
    if (existingBeanDef instanceof ScannedGenericBeanDefinition scannedBeanDef) {
6✔
329
      if (componentMethod.metadata.getReturnTypeName().equals(scannedBeanDef.getBeanClassName())) {
7✔
330
        bootstrapContext.removeBeanDefinition(beanName);
4✔
331
      }
332
      return false;
2✔
333
    }
334

335
    // Has the existing bean definition bean marked as a framework-generated bean?
336
    // -> allow the current bean method to override it, since it is application-level
337
    if (existingBeanDef.getRole() > BeanDefinition.ROLE_APPLICATION) {
3✔
338
      return false;
2✔
339
    }
340

341
    // At this point, it's a top-level override (probably XML), just having been parsed
342
    // before configuration class processing kicks in...
343
    if (!bootstrapContext.getRegistry().isBeanDefinitionOverridable(beanName)) {
6✔
344
      throw new BeanDefinitionStoreException(componentMethod.configurationClass.resource.toString(),
11✔
345
              beanName, "@Component definition illegally overridden by existing bean definition: " + existingBeanDef);
346
    }
347
    if (logger.isDebugEnabled()) {
3✔
348
      logger.debug("Skipping bean definition for {}: a definition for bean '{}' " +
5✔
349
                      "already exists. This top-level bean definition is considered as an override.",
350
              componentMethod, beanName);
351
    }
352
    return true;
2✔
353
  }
354

355
  private void loadBeanDefinitionsFromImportedResources(
356
          Map<String, Class<? extends BeanDefinitionReader>> importedResources) {
357

358
    HashMap<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>();
4✔
359

360
    for (Map.Entry<String, Class<? extends BeanDefinitionReader>> entry : importedResources.entrySet()) {
11✔
361
      String resource = entry.getKey();
4✔
362
      Class<? extends BeanDefinitionReader> readerClass = entry.getValue();
4✔
363
      // Default reader selection necessary?
364
      if (BeanDefinitionReader.class == readerClass) {
3!
365
        // Primarily ".xml" files but for any other extension as well
366
        readerClass = XmlBeanDefinitionReader.class;
2✔
367
      }
368

369
      BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
5✔
370
      if (reader == null) {
2✔
371
        try {
372
          // Instantiate the specified BeanDefinitionReader
373
          reader = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(bootstrapContext.getRegistry());
19✔
374
          // Delegate the current ResourceLoader to it if possible
375
          if (reader instanceof AbstractBeanDefinitionReader abdr) {
6!
376
            abdr.setEnvironment(bootstrapContext.getEnvironment());
5✔
377
            abdr.setResourceLoader(bootstrapContext.getResourceLoader());
5✔
378
          }
379
          readerInstanceCache.put(readerClass, reader);
5✔
380
        }
381
        catch (Throwable ex) {
×
382
          throw new IllegalStateException(
×
383
                  "Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]");
×
384
        }
1✔
385
      }
386

387
      reader.loadBeanDefinitions(resource);
4✔
388
    }
1✔
389

390
  }
1✔
391

392
  private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
393
    for (Map.Entry<ImportBeanDefinitionRegistrar, AnnotationMetadata> entry : registrars.entrySet()) {
11✔
394
      entry.getKey().registerBeanDefinitions(entry.getValue(), bootstrapContext);
9✔
395
    }
1✔
396
  }
1✔
397

398
  /**
399
   * Evaluate {@code @Conditional} annotations, tracking results and taking into
400
   * account 'imported by'.
401
   */
402
  private class TrackedConditionEvaluator {
5✔
403

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

406
    public boolean shouldSkip(ConfigurationClass configClass) {
407
      Boolean skip = this.skipped.get(configClass);
6✔
408
      if (skip == null) {
2✔
409
        if (configClass.isImported()) {
3✔
410
          boolean allSkipped = true;
2✔
411
          for (ConfigurationClass importedBy : configClass.importedBy) {
11✔
412
            if (!shouldSkip(importedBy)) {
4✔
413
              allSkipped = false;
2✔
414
              break;
1✔
415
            }
416
          }
1✔
417
          if (allSkipped) {
2✔
418
            // The config classes that imported this one were all skipped, therefore we are skipped...
419
            skip = true;
3✔
420
          }
421
        }
422
        if (skip == null) {
2✔
423
          skip = bootstrapContext.shouldSkip(configClass.metadata, ConfigurationPhase.REGISTER_BEAN);
9✔
424
        }
425
        this.skipped.put(configClass, skip);
6✔
426
      }
427
      return skip;
3✔
428
    }
429
  }
430

431
  /**
432
   * {@link RootBeanDefinition} marker subclass used to signify that a bean definition
433
   * was created from a configuration class as opposed to any other configuration source.
434
   * Used in bean overriding cases where it's necessary to determine whether the bean
435
   * definition was created externally.
436
   */
437
  private static class ConfigurationClassBeanDefinition extends RootBeanDefinition
438
          implements AnnotatedBeanDefinition {
439

440
    @Serial
441
    private static final long serialVersionUID = 1L;
442

443
    private final AnnotationMetadata annotationMetadata;
444

445
    private final MethodMetadata factoryMethodMetadata;
446

447
    private final String derivedBeanName;
448

449
    public ConfigurationClassBeanDefinition(
450
            ConfigurationClass configClass, MethodMetadata beanMethodMetadata, String derivedBeanName) {
2✔
451

452
      this.annotationMetadata = configClass.metadata;
4✔
453
      this.factoryMethodMetadata = beanMethodMetadata;
3✔
454
      this.derivedBeanName = derivedBeanName;
3✔
455
      setResource(configClass.resource);
4✔
456
      setLenientConstructorResolution(false);
3✔
457
    }
1✔
458

459
    public ConfigurationClassBeanDefinition(RootBeanDefinition original,
460
            ConfigurationClass configClass, MethodMetadata beanMethodMetadata, String derivedBeanName) {
461
      super(original);
3✔
462
      this.annotationMetadata = configClass.metadata;
4✔
463
      this.factoryMethodMetadata = beanMethodMetadata;
3✔
464
      this.derivedBeanName = derivedBeanName;
3✔
465
    }
1✔
466

467
    private ConfigurationClassBeanDefinition(ConfigurationClassBeanDefinition original) {
468
      super(original);
3✔
469
      this.annotationMetadata = original.annotationMetadata;
4✔
470
      this.factoryMethodMetadata = original.factoryMethodMetadata;
4✔
471
      this.derivedBeanName = original.derivedBeanName;
4✔
472
    }
1✔
473

474
    @Override
475
    public AnnotationMetadata getMetadata() {
476
      return this.annotationMetadata;
3✔
477
    }
478

479
    @Override
480
    @NonNull
481
    public MethodMetadata getFactoryMethodMetadata() {
482
      return this.factoryMethodMetadata;
3✔
483
    }
484

485
    @Override
486
    public boolean isFactoryMethod(Method candidate) {
487
      return super.isFactoryMethod(candidate)
6✔
488
              && BeanAnnotationHelper.isBeanAnnotated(candidate)
3✔
489
              && BeanAnnotationHelper.determineBeanNameFor(candidate).equals(derivedBeanName);
8✔
490
    }
491

492
    @Override
493
    public ConfigurationClassBeanDefinition cloneBeanDefinition() {
494
      return new ConfigurationClassBeanDefinition(this);
5✔
495
    }
496
  }
497

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

© 2025 Coveralls, Inc