• 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

88.02
today-context/src/main/java/infra/context/annotation/AnnotationConfigUtils.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.util.function.Consumer;
23

24
import infra.aop.framework.autoproxy.AutoProxyUtils;
25
import infra.beans.factory.annotation.AnnotatedBeanDefinition;
26
import infra.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
27
import infra.beans.factory.annotation.DisableDependencyInjection;
28
import infra.beans.factory.annotation.EnableDependencyInjection;
29
import infra.beans.factory.config.BeanDefinition;
30
import infra.beans.factory.config.BeanDefinitionHolder;
31
import infra.beans.factory.config.BeanFactoryPostProcessor;
32
import infra.beans.factory.config.BeanPostProcessor;
33
import infra.beans.factory.support.BeanDefinitionRegistry;
34
import infra.beans.factory.support.RootBeanDefinition;
35
import infra.beans.factory.support.StandardBeanFactory;
36
import infra.context.event.DefaultEventListenerFactory;
37
import infra.context.event.EventListenerMethodProcessor;
38
import infra.context.support.GenericApplicationContext;
39
import infra.core.annotation.AnnotationAwareOrderComparator;
40
import infra.core.annotation.MergedAnnotation;
41
import infra.core.annotation.MergedAnnotations;
42
import infra.core.type.AnnotatedTypeMetadata;
43
import infra.core.type.AnnotationMetadata;
44
import infra.util.ClassUtils;
45

46
/**
47
 * Utility class that allows for convenient registration of common
48
 * {@link BeanPostProcessor} and
49
 * {@link BeanFactoryPostProcessor}
50
 * definitions for annotation-based configuration.
51
 *
52
 * @author Mark Fisher
53
 * @author Juergen Hoeller
54
 * @author Chris Beams
55
 * @author Phillip Webb
56
 * @author Stephane Nicoll
57
 * @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
58
 * @see ConfigurationClassPostProcessor
59
 * @since 4.0
60
 */
61
public abstract class AnnotationConfigUtils {
×
62

63
  /**
64
   * The bean name of the internally managed Configuration annotation processor.
65
   */
66
  public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
67
          "infra.context.annotation.internalConfigurationAnnotationProcessor";
68

69
  /**
70
   * The bean name of the internally managed BeanNameGenerator for use when processing
71
   * {@link Configuration} classes. Set by {@link AnnotationConfigApplicationContext}
72
   * and {@code AnnotationConfigWebApplicationContext} during bootstrap in order to make
73
   * any custom name generation strategy available to the underlying
74
   * {@link ConfigurationClassPostProcessor}.
75
   */
76
  public static final String CONFIGURATION_BEAN_NAME_GENERATOR =
77
          "infra.context.annotation.internalConfigurationBeanNameGenerator";
78

79
  /**
80
   * The bean name of the internally managed Autowired annotation processor.
81
   */
82
  public static final String AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME =
83
          "infra.context.annotation.internalAutowiredAnnotationProcessor";
84

85
  /**
86
   * The bean name of the internally managed JPA annotation processor.
87
   */
88
  public static final String PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME =
89
          "infra.context.annotation.internalPersistenceAnnotationProcessor";
90

91
  private static final String PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME =
92
          "infra.orm.jpa.support.PersistenceAnnotationBeanPostProcessor";
93

94
  /**
95
   * The bean name of the internally managed @EventListener annotation processor.
96
   */
97
  public static final String EVENT_LISTENER_PROCESSOR_BEAN_NAME =
98
          "infra.context.event.internalEventListenerProcessor";
99

100
  /**
101
   * The bean name of the internally managed EventListenerFactory.
102
   */
103
  public static final String EVENT_LISTENER_FACTORY_BEAN_NAME =
104
          "infra.context.event.internalEventListenerFactory";
105

106
  /**
107
   * The bean name of the internally managed common annotation processor.
108
   */
109
  public static final String COMMON_ANNOTATION_PROCESSOR_BEAN_NAME =
110
          "infra.context.annotation.internalCommonAnnotationProcessor";
111

112
  private static final boolean jsr250Present = isPresent("javax.annotation.PostConstruct");
3✔
113
  private static final boolean jakartaAnnotationsPresent = isPresent("jakarta.annotation.PostConstruct");
3✔
114
  private static final boolean jpaPresent = isPresent("jakarta.persistence.EntityManagerFactory")
5✔
115
          && isPresent(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME);
4!
116

117
  private static boolean isPresent(String className) {
118
    ClassLoader classLoader = AnnotationConfigUtils.class.getClassLoader();
3✔
119
    return ClassUtils.isPresent(className, classLoader);
4✔
120
  }
121

122
  public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
123
    registerAnnotationConfigProcessors(registry, null);
3✔
124
  }
1✔
125

126
  /**
127
   * Register all relevant annotation post processors in the given registry.
128
   *
129
   * @param registry the registry to operate on
130
   */
131
  public static void registerAnnotationConfigProcessors(
132
          BeanDefinitionRegistry registry, @Nullable Consumer<BeanDefinitionHolder> consumer) {
133
    StandardBeanFactory beanFactory = unwrapStandardBeanFactory(registry);
3✔
134
    if (beanFactory != null) {
2!
135
      if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
4✔
136
        beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
3✔
137
      }
138

139
      if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
4✔
140
        beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
5✔
141
      }
142
    }
143

144
    if (!registry.containsBeanDefinition(AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
4✔
145
      RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
5✔
146
      registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME, consumer);
5✔
147
    }
148

149
    if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
4✔
150
      RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
5✔
151
      registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME, consumer);
5✔
152
    }
153

154
    // Check for Jakarta Annotations support, and if present add the CommonAnnotationBeanPostProcessor.
155
    if ((jakartaAnnotationsPresent || jsr250Present)
6!
156
            && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
2✔
157
      RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
5✔
158
      registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME, consumer);
5✔
159
    }
160

161
    // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
162
    if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
2!
163
      RootBeanDefinition def = new RootBeanDefinition();
×
164
      try {
165
        def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
×
166
                AnnotationConfigUtils.class.getClassLoader()));
×
167
      }
168
      catch (ClassNotFoundException ex) {
×
169
        throw new IllegalStateException(
×
170
                "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
171
      }
×
172
      registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME, consumer);
×
173
    }
174

175
    if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
4✔
176
      RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
5✔
177
      registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME, consumer);
5✔
178
    }
179

180
    if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
4✔
181
      RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
5✔
182
      registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME, consumer);
5✔
183
    }
184
  }
1✔
185

186
  private static void registerPostProcessor(BeanDefinitionRegistry registry,
187
          RootBeanDefinition definition, String beanName, @Nullable Consumer<BeanDefinitionHolder> consumer) {
188

189
    definition.setEnableDependencyInjection(false);
3✔
190
    definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
3✔
191
    registry.registerBeanDefinition(beanName, definition);
4✔
192

193
    if (consumer != null) {
2✔
194
      consumer.accept(new BeanDefinitionHolder(definition, beanName));
7✔
195
    }
196
  }
1✔
197

198
  @Nullable
199
  private static StandardBeanFactory unwrapStandardBeanFactory(BeanDefinitionRegistry registry) {
200
    if (registry instanceof StandardBeanFactory) {
3✔
201
      return (StandardBeanFactory) registry;
3✔
202
    }
203
    else if (registry instanceof GenericApplicationContext) {
3!
204
      return ((GenericApplicationContext) registry).getBeanFactory();
4✔
205
    }
206
    else {
207
      return null;
×
208
    }
209
  }
210

211
  public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
212
    applyAnnotationMetadata(abd, true);
3✔
213
  }
1✔
214

215
  static BeanDefinitionHolder applyScopedProxyMode(
216
          ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
217

218
    ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
3✔
219
    if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
4✔
220
      return definition;
2✔
221
    }
222
    boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
4✔
223
    return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
5✔
224
  }
225

226
  public static void applyAnnotationMetadata(AnnotatedBeanDefinition definition, boolean detectDIStatus) {
227
    AnnotatedTypeMetadata metadata = definition.getFactoryMethodMetadata();
3✔
228
    if (metadata == null) {
2✔
229
      metadata = definition.getMetadata();
3✔
230
    }
231
    MergedAnnotations annotations = metadata.getAnnotations();
3✔
232
    applyAnnotationMetadata(annotations, definition, detectDIStatus);
4✔
233
  }
1✔
234

235
  public static void applyAnnotationMetadata(MergedAnnotations annotations, BeanDefinition definition, boolean detectDIStatus) {
236
    if (annotations.isPresent(Primary.class)) {
4✔
237
      definition.setPrimary(true);
3✔
238
    }
239

240
    if (annotations.isPresent(Fallback.class)) {
4✔
241
      definition.setFallback(true);
3✔
242
    }
243

244
    MergedAnnotation<Lazy> lazyMergedAnnotation = annotations.get(Lazy.class);
4✔
245
    if (lazyMergedAnnotation.isPresent()) {
3✔
246
      definition.setLazyInit(lazyMergedAnnotation.getBooleanValue());
5✔
247
    }
248
    else if (definition instanceof AnnotatedBeanDefinition annotated) {
6!
249
      AnnotationMetadata metadata = annotated.getMetadata();
3✔
250
      lazyMergedAnnotation = metadata.getAnnotation(Lazy.class);
4✔
251

252
      if (lazyMergedAnnotation.isPresent()) {
3✔
253
        definition.setLazyInit(lazyMergedAnnotation.getBooleanValue());
4✔
254
      }
255
    }
256

257
    MergedAnnotation<Role> roleMergedAnnotation = annotations.get(Role.class);
4✔
258
    if (roleMergedAnnotation.isPresent()) {
3✔
259
      definition.setRole(roleMergedAnnotation.getIntValue());
4✔
260
    }
261

262
    MergedAnnotation<DependsOn> dependsOn = annotations.get(DependsOn.class);
4✔
263
    if (dependsOn.isPresent()) {
3✔
264
      definition.setDependsOn(dependsOn.getStringValueArray());
4✔
265
    }
266

267
    MergedAnnotation<Description> description = annotations.get(Description.class);
4✔
268
    if (description.isPresent()) {
3✔
269
      definition.setDescription(description.getStringValue());
4✔
270
    }
271

272
    if (detectDIStatus) {
2✔
273
      if (annotations.isPresent(EnableDependencyInjection.class)) {
4!
274
        definition.setEnableDependencyInjection(true);
×
275
      }
276
      else if (annotations.isPresent(DisableDependencyInjection.class)) {
4✔
277
        definition.setEnableDependencyInjection(false);
3✔
278
      }
279
    }
280

281
    MergedAnnotation<Proxyable> proxyable = annotations.get(Proxyable.class);
4✔
282
    if (proxyable.isPresent()) {
3✔
283
      ProxyType mode = proxyable.getEnum("value", ProxyType.class);
6✔
284
      if (mode == ProxyType.TARGET_CLASS) {
3✔
285
        definition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
5✔
286
      }
287
      else {
288
        Class<?>[] ifcs = proxyable.getClassArray("interfaces");
4✔
289
        if (ifcs.length > 0 || mode == ProxyType.INTERFACES) {
6!
290
          definition.setAttribute(AutoProxyUtils.EXPOSED_INTERFACES_ATTRIBUTE, ifcs);
4✔
291
        }
292
      }
293
    }
294

295
  }
1✔
296

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