001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.context.annotation;
018
019import java.util.Collections;
020import java.util.LinkedHashSet;
021import java.util.Map;
022import java.util.Set;
023
024import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
025import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
026import org.springframework.beans.factory.config.BeanDefinition;
027import org.springframework.beans.factory.config.BeanDefinitionHolder;
028import org.springframework.beans.factory.support.BeanDefinitionRegistry;
029import org.springframework.beans.factory.support.DefaultListableBeanFactory;
030import org.springframework.beans.factory.support.RootBeanDefinition;
031import org.springframework.context.event.DefaultEventListenerFactory;
032import org.springframework.context.event.EventListenerMethodProcessor;
033import org.springframework.context.support.GenericApplicationContext;
034import org.springframework.core.annotation.AnnotationAttributes;
035import org.springframework.core.annotation.AnnotationAwareOrderComparator;
036import org.springframework.core.type.AnnotatedTypeMetadata;
037import org.springframework.core.type.AnnotationMetadata;
038import org.springframework.lang.Nullable;
039import org.springframework.util.ClassUtils;
040
041/**
042 * Utility class that allows for convenient registration of common
043 * {@link org.springframework.beans.factory.config.BeanPostProcessor} and
044 * {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor}
045 * definitions for annotation-based configuration. Also registers a common
046 * {@link org.springframework.beans.factory.support.AutowireCandidateResolver}.
047 *
048 * @author Mark Fisher
049 * @author Juergen Hoeller
050 * @author Chris Beams
051 * @author Phillip Webb
052 * @author Stephane Nicoll
053 * @since 2.5
054 * @see ContextAnnotationAutowireCandidateResolver
055 * @see ConfigurationClassPostProcessor
056 * @see CommonAnnotationBeanPostProcessor
057 * @see org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
058 * @see org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor
059 */
060public abstract class AnnotationConfigUtils {
061
062        /**
063         * The bean name of the internally managed Configuration annotation processor.
064         */
065        public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
066                        "org.springframework.context.annotation.internalConfigurationAnnotationProcessor";
067
068        /**
069         * The bean name of the internally managed BeanNameGenerator for use when processing
070         * {@link Configuration} classes. Set by {@link AnnotationConfigApplicationContext}
071         * and {@code AnnotationConfigWebApplicationContext} during bootstrap in order to make
072         * any custom name generation strategy available to the underlying
073         * {@link ConfigurationClassPostProcessor}.
074         * @since 3.1.1
075         */
076        public static final String CONFIGURATION_BEAN_NAME_GENERATOR =
077                        "org.springframework.context.annotation.internalConfigurationBeanNameGenerator";
078
079        /**
080         * The bean name of the internally managed Autowired annotation processor.
081         */
082        public static final String AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME =
083                        "org.springframework.context.annotation.internalAutowiredAnnotationProcessor";
084
085        /**
086         * The bean name of the internally managed Required annotation processor.
087         * @deprecated as of 5.1, since no Required processor is registered by default anymore
088         */
089        @Deprecated
090        public static final String REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME =
091                        "org.springframework.context.annotation.internalRequiredAnnotationProcessor";
092
093        /**
094         * The bean name of the internally managed JSR-250 annotation processor.
095         */
096        public static final String COMMON_ANNOTATION_PROCESSOR_BEAN_NAME =
097                        "org.springframework.context.annotation.internalCommonAnnotationProcessor";
098
099        /**
100         * The bean name of the internally managed JPA annotation processor.
101         */
102        public static final String PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME =
103                        "org.springframework.context.annotation.internalPersistenceAnnotationProcessor";
104
105        private static final String PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME =
106                        "org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor";
107
108        /**
109         * The bean name of the internally managed @EventListener annotation processor.
110         */
111        public static final String EVENT_LISTENER_PROCESSOR_BEAN_NAME =
112                        "org.springframework.context.event.internalEventListenerProcessor";
113
114        /**
115         * The bean name of the internally managed EventListenerFactory.
116         */
117        public static final String EVENT_LISTENER_FACTORY_BEAN_NAME =
118                        "org.springframework.context.event.internalEventListenerFactory";
119
120        private static final boolean jsr250Present;
121
122        private static final boolean jpaPresent;
123
124        static {
125                ClassLoader classLoader = AnnotationConfigUtils.class.getClassLoader();
126                jsr250Present = ClassUtils.isPresent("javax.annotation.Resource", classLoader);
127                jpaPresent = ClassUtils.isPresent("javax.persistence.EntityManagerFactory", classLoader) &&
128                                ClassUtils.isPresent(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, classLoader);
129        }
130
131
132        /**
133         * Register all relevant annotation post processors in the given registry.
134         * @param registry the registry to operate on
135         */
136        public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
137                registerAnnotationConfigProcessors(registry, null);
138        }
139
140        /**
141         * Register all relevant annotation post processors in the given registry.
142         * @param registry the registry to operate on
143         * @param source the configuration source element (already extracted)
144         * that this registration was triggered from. May be {@code null}.
145         * @return a Set of BeanDefinitionHolders, containing all bean definitions
146         * that have actually been registered by this call
147         */
148        public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
149                        BeanDefinitionRegistry registry, @Nullable Object source) {
150
151                DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
152                if (beanFactory != null) {
153                        if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
154                                beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
155                        }
156                        if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
157                                beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
158                        }
159                }
160
161                Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
162
163                if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
164                        RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
165                        def.setSource(source);
166                        beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
167                }
168
169                if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
170                        RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
171                        def.setSource(source);
172                        beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
173                }
174
175                // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
176                if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
177                        RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
178                        def.setSource(source);
179                        beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
180                }
181
182                // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
183                if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
184                        RootBeanDefinition def = new RootBeanDefinition();
185                        try {
186                                def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
187                                                AnnotationConfigUtils.class.getClassLoader()));
188                        }
189                        catch (ClassNotFoundException ex) {
190                                throw new IllegalStateException(
191                                                "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
192                        }
193                        def.setSource(source);
194                        beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
195                }
196
197                if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
198                        RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
199                        def.setSource(source);
200                        beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
201                }
202
203                if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
204                        RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
205                        def.setSource(source);
206                        beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
207                }
208
209                return beanDefs;
210        }
211
212        private static BeanDefinitionHolder registerPostProcessor(
213                        BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
214
215                definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
216                registry.registerBeanDefinition(beanName, definition);
217                return new BeanDefinitionHolder(definition, beanName);
218        }
219
220        @Nullable
221        private static DefaultListableBeanFactory unwrapDefaultListableBeanFactory(BeanDefinitionRegistry registry) {
222                if (registry instanceof DefaultListableBeanFactory) {
223                        return (DefaultListableBeanFactory) registry;
224                }
225                else if (registry instanceof GenericApplicationContext) {
226                        return ((GenericApplicationContext) registry).getDefaultListableBeanFactory();
227                }
228                else {
229                        return null;
230                }
231        }
232
233        public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
234                processCommonDefinitionAnnotations(abd, abd.getMetadata());
235        }
236
237        static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
238                AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
239                if (lazy != null) {
240                        abd.setLazyInit(lazy.getBoolean("value"));
241                }
242                else if (abd.getMetadata() != metadata) {
243                        lazy = attributesFor(abd.getMetadata(), Lazy.class);
244                        if (lazy != null) {
245                                abd.setLazyInit(lazy.getBoolean("value"));
246                        }
247                }
248
249                if (metadata.isAnnotated(Primary.class.getName())) {
250                        abd.setPrimary(true);
251                }
252                AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
253                if (dependsOn != null) {
254                        abd.setDependsOn(dependsOn.getStringArray("value"));
255                }
256
257                AnnotationAttributes role = attributesFor(metadata, Role.class);
258                if (role != null) {
259                        abd.setRole(role.getNumber("value").intValue());
260                }
261                AnnotationAttributes description = attributesFor(metadata, Description.class);
262                if (description != null) {
263                        abd.setDescription(description.getString("value"));
264                }
265        }
266
267        static BeanDefinitionHolder applyScopedProxyMode(
268                        ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
269
270                ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
271                if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
272                        return definition;
273                }
274                boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
275                return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
276        }
277
278        @Nullable
279        static AnnotationAttributes attributesFor(AnnotatedTypeMetadata metadata, Class<?> annotationClass) {
280                return attributesFor(metadata, annotationClass.getName());
281        }
282
283        @Nullable
284        static AnnotationAttributes attributesFor(AnnotatedTypeMetadata metadata, String annotationClassName) {
285                return AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(annotationClassName, false));
286        }
287
288        static Set<AnnotationAttributes> attributesForRepeatable(AnnotationMetadata metadata,
289                        Class<?> containerClass, Class<?> annotationClass) {
290
291                return attributesForRepeatable(metadata, containerClass.getName(), annotationClass.getName());
292        }
293
294        @SuppressWarnings("unchecked")
295        static Set<AnnotationAttributes> attributesForRepeatable(
296                        AnnotationMetadata metadata, String containerClassName, String annotationClassName) {
297
298                Set<AnnotationAttributes> result = new LinkedHashSet<>();
299
300                // Direct annotation present?
301                addAttributesIfNotNull(result, metadata.getAnnotationAttributes(annotationClassName, false));
302
303                // Container annotation present?
304                Map<String, Object> container = metadata.getAnnotationAttributes(containerClassName, false);
305                if (container != null && container.containsKey("value")) {
306                        for (Map<String, Object> containedAttributes : (Map<String, Object>[]) container.get("value")) {
307                                addAttributesIfNotNull(result, containedAttributes);
308                        }
309                }
310
311                // Return merged result
312                return Collections.unmodifiableSet(result);
313        }
314
315        private static void addAttributesIfNotNull(
316                        Set<AnnotationAttributes> result, @Nullable Map<String, Object> attributes) {
317
318                if (attributes != null) {
319                        result.add(AnnotationAttributes.fromMap(attributes));
320                }
321        }
322
323}