001/*
002 * Copyright 2002-2020 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.beans.factory.support;
018
019import java.lang.reflect.Method;
020import java.util.Properties;
021
022import org.springframework.beans.factory.BeanFactory;
023import org.springframework.beans.factory.BeanFactoryAware;
024import org.springframework.beans.factory.FactoryBean;
025import org.springframework.beans.factory.config.BeanDefinition;
026import org.springframework.beans.factory.config.BeanDefinitionHolder;
027import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
028import org.springframework.beans.factory.config.DependencyDescriptor;
029import org.springframework.core.ResolvableType;
030import org.springframework.lang.Nullable;
031import org.springframework.util.ClassUtils;
032
033/**
034 * Basic {@link AutowireCandidateResolver} that performs a full generic type
035 * match with the candidate's type if the dependency is declared as a generic type
036 * (e.g. Repository<Customer>).
037 *
038 * <p>This is the base class for
039 * {@link org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver},
040 * providing an implementation all non-annotation-based resolution steps at this level.
041 *
042 * @author Juergen Hoeller
043 * @since 4.0
044 */
045public class GenericTypeAwareAutowireCandidateResolver extends SimpleAutowireCandidateResolver
046                implements BeanFactoryAware, Cloneable {
047
048        @Nullable
049        private BeanFactory beanFactory;
050
051
052        @Override
053        public void setBeanFactory(BeanFactory beanFactory) {
054                this.beanFactory = beanFactory;
055        }
056
057        @Nullable
058        protected final BeanFactory getBeanFactory() {
059                return this.beanFactory;
060        }
061
062
063        @Override
064        public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
065                if (!super.isAutowireCandidate(bdHolder, descriptor)) {
066                        // If explicitly false, do not proceed with any other checks...
067                        return false;
068                }
069                return checkGenericTypeMatch(bdHolder, descriptor);
070        }
071
072        /**
073         * Match the given dependency type with its generic type information against the given
074         * candidate bean definition.
075         */
076        protected boolean checkGenericTypeMatch(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
077                ResolvableType dependencyType = descriptor.getResolvableType();
078                if (dependencyType.getType() instanceof Class) {
079                        // No generic type -> we know it's a Class type-match, so no need to check again.
080                        return true;
081                }
082
083                ResolvableType targetType = null;
084                boolean cacheType = false;
085                RootBeanDefinition rbd = null;
086                if (bdHolder.getBeanDefinition() instanceof RootBeanDefinition) {
087                        rbd = (RootBeanDefinition) bdHolder.getBeanDefinition();
088                }
089                if (rbd != null) {
090                        targetType = rbd.targetType;
091                        if (targetType == null) {
092                                cacheType = true;
093                                // First, check factory method return type, if applicable
094                                targetType = getReturnTypeForFactoryMethod(rbd, descriptor);
095                                if (targetType == null) {
096                                        RootBeanDefinition dbd = getResolvedDecoratedDefinition(rbd);
097                                        if (dbd != null) {
098                                                targetType = dbd.targetType;
099                                                if (targetType == null) {
100                                                        targetType = getReturnTypeForFactoryMethod(dbd, descriptor);
101                                                }
102                                        }
103                                }
104                        }
105                }
106
107                if (targetType == null) {
108                        // Regular case: straight bean instance, with BeanFactory available.
109                        if (this.beanFactory != null) {
110                                Class<?> beanType = this.beanFactory.getType(bdHolder.getBeanName());
111                                if (beanType != null) {
112                                        targetType = ResolvableType.forClass(ClassUtils.getUserClass(beanType));
113                                }
114                        }
115                        // Fallback: no BeanFactory set, or no type resolvable through it
116                        // -> best-effort match against the target class if applicable.
117                        if (targetType == null && rbd != null && rbd.hasBeanClass() && rbd.getFactoryMethodName() == null) {
118                                Class<?> beanClass = rbd.getBeanClass();
119                                if (!FactoryBean.class.isAssignableFrom(beanClass)) {
120                                        targetType = ResolvableType.forClass(ClassUtils.getUserClass(beanClass));
121                                }
122                        }
123                }
124
125                if (targetType == null) {
126                        return true;
127                }
128                if (cacheType) {
129                        rbd.targetType = targetType;
130                }
131                if (descriptor.fallbackMatchAllowed() &&
132                                (targetType.hasUnresolvableGenerics() || targetType.resolve() == Properties.class)) {
133                        // Fallback matches allow unresolvable generics, e.g. plain HashMap to Map<String,String>;
134                        // and pragmatically also java.util.Properties to any Map (since despite formally being a
135                        // Map<Object,Object>, java.util.Properties is usually perceived as a Map<String,String>).
136                        return true;
137                }
138                // Full check for complex generic type match...
139                return dependencyType.isAssignableFrom(targetType);
140        }
141
142        @Nullable
143        protected RootBeanDefinition getResolvedDecoratedDefinition(RootBeanDefinition rbd) {
144                BeanDefinitionHolder decDef = rbd.getDecoratedDefinition();
145                if (decDef != null && this.beanFactory instanceof ConfigurableListableBeanFactory) {
146                        ConfigurableListableBeanFactory clbf = (ConfigurableListableBeanFactory) this.beanFactory;
147                        if (clbf.containsBeanDefinition(decDef.getBeanName())) {
148                                BeanDefinition dbd = clbf.getMergedBeanDefinition(decDef.getBeanName());
149                                if (dbd instanceof RootBeanDefinition) {
150                                        return (RootBeanDefinition) dbd;
151                                }
152                        }
153                }
154                return null;
155        }
156
157        @Nullable
158        protected ResolvableType getReturnTypeForFactoryMethod(RootBeanDefinition rbd, DependencyDescriptor descriptor) {
159                // Should typically be set for any kind of factory method, since the BeanFactory
160                // pre-resolves them before reaching out to the AutowireCandidateResolver...
161                ResolvableType returnType = rbd.factoryMethodReturnType;
162                if (returnType == null) {
163                        Method factoryMethod = rbd.getResolvedFactoryMethod();
164                        if (factoryMethod != null) {
165                                returnType = ResolvableType.forMethodReturnType(factoryMethod);
166                        }
167                }
168                if (returnType != null) {
169                        Class<?> resolvedClass = returnType.resolve();
170                        if (resolvedClass != null && descriptor.getDependencyType().isAssignableFrom(resolvedClass)) {
171                                // Only use factory method metadata if the return type is actually expressive enough
172                                // for our dependency. Otherwise, the returned instance type may have matched instead
173                                // in case of a singleton instance having been registered with the container already.
174                                return returnType;
175                        }
176                }
177                return null;
178        }
179
180
181        /**
182         * This implementation clones all instance fields through standard
183         * {@link Cloneable} support, allowing for subsequent reconfiguration
184         * of the cloned instance through a fresh {@link #setBeanFactory} call.
185         * @see #clone()
186         */
187        @Override
188        public AutowireCandidateResolver cloneIfNecessary() {
189                try {
190                        return (AutowireCandidateResolver) clone();
191                }
192                catch (CloneNotSupportedException ex) {
193                        throw new IllegalStateException(ex);
194                }
195        }
196
197}