/******************************************************************************* * Copyright (c) 2009, 2015 Spring IDE Developers * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Spring IDE Developers - initial API and implementation *******************************************************************************/ package org.springframework.ide.eclipse.beans.core.autowire.internal.provider; import java.lang.reflect.Constructor; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Resource; import javax.inject.Provider; import org.eclipse.core.resources.IMarker; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.JavaModelException; import org.springframework.beans.BeanWrapperImpl; import org.springframework.beans.BeansException; import org.springframework.beans.PropertyValue; import org.springframework.beans.TypeConverter; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.DependencyDescriptor; import org.springframework.beans.factory.config.TypedStringValue; import org.springframework.beans.factory.support.AutowireCandidateResolver; import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.core.ParameterNameDiscoverer; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.ide.eclipse.beans.core.BeansCorePlugin; import org.springframework.ide.eclipse.beans.core.autowire.IAutowireDependencyResolver; import org.springframework.ide.eclipse.beans.core.autowire.IFactoryBeanTypeResolver; import org.springframework.ide.eclipse.beans.core.autowire.internal.provider.InjectionMetadata.InjectedElement; import org.springframework.ide.eclipse.beans.core.internal.model.BeansModelUtils; import org.springframework.ide.eclipse.beans.core.internal.model.validation.rules.ValidationRuleUtils; import org.springframework.ide.eclipse.beans.core.model.IBean; import org.springframework.ide.eclipse.beans.core.model.IBeanAlias; import org.springframework.ide.eclipse.beans.core.model.IBeanReference; import org.springframework.ide.eclipse.beans.core.model.IBeansConfig; import org.springframework.ide.eclipse.beans.core.model.IBeansConfigSet; import org.springframework.ide.eclipse.beans.core.model.IBeansModelElement; import org.springframework.ide.eclipse.beans.core.model.IBeansProject; import org.springframework.ide.eclipse.core.java.ClassUtils; import org.springframework.ide.eclipse.core.java.IProjectClassLoaderSupport; import org.springframework.ide.eclipse.core.java.JdtUtils; import org.springframework.ide.eclipse.core.model.validation.ValidationProblem; import org.springframework.ide.eclipse.core.model.validation.ValidationProblemAttribute; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** * {@link IAutowireDependencyResolver} capable of processing Spring's {@link Autowired}, {@link EJB}, {@link Resource}annotations. * <p> * This class is the entry point into autowiring resolution within Spring IDE. * @author Christian Dupuis * @author Terry Denney * @author Martin Lippert * @since 2.2.7 */ public class AutowireDependencyProvider implements IAutowireDependencyResolver { public static final String TOO_MANY_MATCHING_BEANS = "TOO_MANY_MATCHING_BEANS"; public static final String REQUIRED_NO_MATCH = "REQUIRED_NO_MATCH"; public static final String AUTOWIRE_PROBLEM_TYPE = "AUTOWIRE_PROBLEM"; public static final String MATCHING_BEAN_NAME = "MATCHING_BEAN_NAME"; public static final String BEAN_TYPE = "BEAN_TYPE"; private Set<IBean> beans; private IBeansModelElement context; private IBeansModelElement element; private IBeansProject project; private IProjectClassLoaderSupport classLoaderSupport; private Map<IBean, List<InjectionMetadata>> injectionMetadata = new ConcurrentHashMap<IBean, List<InjectionMetadata>>(); private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer(); private IInjectionMetadataProviderProblemReporter problemReporter = new AutowireProblemReporter(); private List<ValidationProblem> problems = new ArrayList<ValidationProblem>(); private Map<Class<?>, String> resolvableDependencies = new HashMap<Class<?>, String>(); private Class<?> factoryBeanClass; private Class<?> objectFactoryClass; private Class<?> providerClass; public AutowireDependencyProvider(IBeansModelElement element, IBeansModelElement context) { this.context = (context == null ? element : context); this.element = element; this.beans = BeansModelUtils.getBeans(context); this.project = BeansModelUtils.getParentOfClass(context, IBeansProject.class); } public List<ValidationProblem> getValidationProblems() { return this.problems; } public Map<IBean, Set<IBeanReference>> resolveAutowiredDependencies() { final Map<IBean, Set<IBeanReference>> autowiredBeanReferences = new HashMap<IBean, Set<IBeanReference>>(); createProjectClassLoaderSupport(); try { this.classLoaderSupport.executeCallback(new IProjectClassLoaderSupport.IProjectClassLoaderAwareCallback() { public void doWithActiveProjectClassLoader() throws Throwable { // pre-load used classes preloadClasses(); // fill in the resolvableDependencies fillResolvableDependencies(); Set<IBean> elementBeans = BeansModelUtils.getBeans(element); for (IInjectionMetadataProvider provider : createInjectionMetadataProviders()) { for (final IBean bean : elementBeans) { List<InjectionMetadata> beanInjectionMetadata = null; if (injectionMetadata.containsKey(bean)) { beanInjectionMetadata = injectionMetadata.get(bean); } else { beanInjectionMetadata = new ArrayList<InjectionMetadata>(); injectionMetadata.put(bean, beanInjectionMetadata); } String className = BeansModelUtils.getBeanClass(bean, context); try { if (className != null && !bean.isFactory()) { Class<?> targetClass = ClassUtils.loadClass(className); beanInjectionMetadata.add(provider.findAutowiringMetadata(targetClass)); } } catch (Throwable e) { } } } for (Map.Entry<IBean, List<InjectionMetadata>> entry : injectionMetadata.entrySet()) { Set<IBeanReference> autowiredReferences = new HashSet<IBeanReference>(); for (InjectionMetadata metadata : entry.getValue()) { resolveDependencies(entry.getKey(), autowiredReferences, metadata.getInjectedFields()); resolveDependencies(entry.getKey(), autowiredReferences, metadata.getInjectedMethods()); resolveConstructorDependencies(entry.getKey(), autowiredReferences, metadata .getInjectedConstructors()); } if (autowiredReferences.size() > 0) { autowiredBeanReferences.put(entry.getKey(), autowiredReferences); } } } private void fillResolvableDependencies() { addResolvableClass(BeanFactory.class.getName()); addResolvableClass("org.springframework.core.io.ResourceLoader"); addResolvableClass("org.springframework.context.ApplicationEventPublisher"); addResolvableClass("org.springframework.context.ApplicationContext"); addResolvableClass("org.springframework.core.env.Environment", "environment"); addResolvableClass("javax.servlet.ServletConfig"); addResolvableClass("javax.servlet.ServletRequest", "requestObjectFactory"); addResolvableClass("javax.servlet.http.HttpSession", "sessionObjectFactory"); addResolvableClass("javax.portlet.PortletRequest", "requestObjectFactory"); addResolvableClass("javax.portlet.PortletSession", "sessionObjectFactory"); addResolvableClass("javax.portlet.PortletSession", "sessionObjectFactory"); } private void addResolvableClass(String className, String beanName) { try { Class<?> clazz = ClassUtils.loadClass(className); resolvableDependencies.put(clazz, beanName); } catch (ClassNotFoundException e) { } } private void addResolvableClass(String className) { addResolvableClass(className, StringUtils.uncapitalize(org.springframework.util.ClassUtils .getShortName(className))); } private void resolveConstructorDependencies(IBean bean, Set<IBeanReference> autowiredReferences, Set<InjectedElement> injectedConstructors) { InjectedElement[] constructors = sortConstructors(injectedConstructors); // Special handling for explicit defined values if (constructors.length > 0) { for (InjectionMetadata.InjectedElement injectionElement : constructors) { try { autowiredReferences.addAll(injectionElement.getBeanReferences(bean, context, AutowireDependencyProvider.this)); } catch (Throwable e) { // TODO CD log somewhere } } } } private InjectedElement[] sortConstructors(Set<InjectedElement> injectedConstructors) { InjectedElement[] constructors = (InjectedElement[]) injectedConstructors .toArray(new InjectedElement[injectedConstructors.size()]); Arrays.sort(constructors, new Comparator<InjectedElement>() { public int compare(InjectedElement o1, InjectedElement o2) { Constructor<?> c1 = (Constructor<?>) o1.getMember(); Constructor<?> c2 = (Constructor<?>) o2.getMember(); boolean p1 = Modifier.isPublic(c1.getModifiers()); boolean p2 = Modifier.isPublic(c2.getModifiers()); if (p1 != p2) { return (p1 ? -1 : 1); } int c1pl = c1.getParameterTypes().length; int c2pl = c2.getParameterTypes().length; return (new Integer(c1pl)).compareTo(c2pl) * -1; } }); return constructors; } private void resolveDependencies(IBean bean, Set<IBeanReference> autowiredReferences, Set<InjectionMetadata.InjectedElement> injectionElements) { if (injectionElements.size() > 0) { for (InjectionMetadata.InjectedElement injectionElement : injectionElements) { try { autowiredReferences.addAll(injectionElement.getBeanReferences(bean, context, AutowireDependencyProvider.this)); } catch (Throwable e) { // TODO CD log somewhere } } } } }); } catch (ClassNotFoundException e) { // Ignore here as this can easily happen if project class path is not complete } catch (NoClassDefFoundError e) { // Ignore here as this can easily happen if project class path is not complete } catch (Throwable e) { BeansCorePlugin.log(e); } return autowiredBeanReferences; } public void preloadClasses() { try { factoryBeanClass = ClassUtils.loadClass(FactoryBean.class.getName()); } catch (Throwable e) { // Ignore here as this can easily happen if project class path is not complete } try { objectFactoryClass = ClassUtils.loadClass(ObjectFactory.class.getName()); } catch (Throwable e) { // Ignore here as this can easily happen if project class path is not complete } try { providerClass = ClassUtils.loadClass(Provider.class.getName()); } catch (Throwable e) { // Ignore here as this can easily happen if project class path is not complete } } public boolean containsBean(String beanName) { return getBean(beanName) != null; } public String[] getAliases(String beanName) { Set<String> aliases = new HashSet<String>(); if (context instanceof IBeansConfig) { for (IBeanAlias alias : ((IBeansConfig) context).getAliases()) { if (beanName.equals(alias.getBeanName())) { aliases.add(alias.getElementName()); } } } else if (context instanceof IBeansConfigSet) { for (IBeanAlias alias : ((IBeansConfigSet) context).getAliases()) { if (beanName.equals(alias.getBeanName())) { aliases.add(alias.getElementName()); } } } return (String[]) aliases.toArray(new String[aliases.size()]); } public IBean getBean(String candidateName) { for (IBean bean : beans) { if (bean.getElementName().equals(candidateName)) { return bean; } else { for (String alias : getAliases(bean.getElementName())) { if (alias.equals(candidateName)) { return bean; } } } } return null; } public String[] getBeansForType(String requiredTypeName) { try { Class<?> requiredType = ClassUtils.loadClass(requiredTypeName); return getBeansForType(requiredType); } catch (ClassNotFoundException e) { // Ignore here as this can easily happen if project class path is not complete } catch (NoClassDefFoundError e) { // Ignore here as this can easily happen if project class path is not complete } catch (Throwable e) { BeansCorePlugin.log(e); } return new String[0]; } public String[] getBeansForType(Class<?> requiredType) { Set<String> matchingBeans = new HashSet<String>(); for (IBean bean : beans) { String beanClassName = ValidationRuleUtils.getBeanClassName(bean, context); if (beanClassName != null) { try { Class<?> beanClass = ClassUtils.loadClass(beanClassName); if (requiredType.isAssignableFrom(beanClass)) { matchingBeans.add(bean.getElementName()); } else if (factoryBeanClass != null && factoryBeanClass.isAssignableFrom(beanClass)) { if (isFactoryForType(beanClass, requiredType)) { matchingBeans.add(bean.getElementName()); } else if (isExtensibleFactoryForType(bean, beanClass, requiredType)) { matchingBeans.add(bean.getElementName()); } } } catch (ClassNotFoundException e) { // Ignore here as this can easily happen if project class path is not complete } catch (NoClassDefFoundError e) { // Ignore here as this can easily happen if project class path is not complete } catch (Throwable e) { BeansCorePlugin.log(e); } } } return (String[]) matchingBeans.toArray(new String[matchingBeans.size()]); } private boolean isFactoryForType(Class<?> beanClass, Class<?> requiredType) { try { Method factoryMethod = beanClass.getMethod("getObject", new Class[] {}); if (factoryMethod != null && requiredType.isAssignableFrom(factoryMethod.getReturnType())) { return true; } } catch (NoClassDefFoundError e) { // Ignore here as this can easily happen if project class path is not complete } catch (Throwable e) { BeansCorePlugin.log(e); } return false; } private boolean isExtensibleFactoryForType(IBean bean, Class<?> beanClass, Class<?> requiredType) { IFactoryBeanTypeResolver[] resolvers = FactoryBeanTypeResolverExtensions.getFactoryBeanTypeResolvers(); for (IFactoryBeanTypeResolver factoryTypeResolver : resolvers) { Class<?> beanType = factoryTypeResolver.resolveBeanTypeFromFactory(bean, beanClass); if (beanType != null && requiredType.isAssignableFrom(beanType)) { return true; } } return false; } public boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor) throws NoSuchBeanDefinitionException { // Consider FactoryBeans as autowiring candidates. boolean isFactoryBean = (descriptor != null && descriptor.getDependencyType() != null && factoryBeanClass != null && factoryBeanClass.isAssignableFrom(descriptor.getDependencyType())); if (isFactoryBean) { beanName = BeanFactoryUtils.transformedBeanName(beanName); } if (containsBean(beanName)) { return isAutowireCandidate(beanName, BeansModelUtils.getMergedBeanDefinition(getBean(beanName), context), descriptor); } else { return true; } } private Set<IInjectionMetadataProvider> createInjectionMetadataProviders() { Set<IInjectionMetadataProvider> providers = new HashSet<IInjectionMetadataProvider>(); String[] autowiredAnnotationBeanPostProcessorNames = getBeansForType(AutowiredAnnotationBeanPostProcessor.class.getName()); for (String autowiredAnnotationBeanPostProcessorName : autowiredAnnotationBeanPostProcessorNames) { AutowiredAnnotationInjectionMetadataProvider provider = new AutowiredAnnotationInjectionMetadataProvider( this.classLoaderSupport.getProjectClassLoader()); IBean bean = getBean(autowiredAnnotationBeanPostProcessorName); BeanDefinition beanDef = BeansModelUtils.getMergedBeanDefinition(bean, context); if (beanDef.getPropertyValues().size() > 0) { BeanWrapperImpl wrapper = new BeanWrapperImpl(true); wrapper.setConversionService(new DefaultConversionService()); wrapper.setWrappedInstance(provider); for (PropertyValue pv : beanDef.getPropertyValues().getPropertyValueList()) { if (wrapper.isWritableProperty(pv.getName())) { // TODO other values types required as well? if (pv.getValue() instanceof TypedStringValue) { wrapper.setPropertyValue(pv.getName(), (((TypedStringValue) pv.getValue())).getValue()); } } } } provider.setProblemReporter(problemReporter); providers.add(provider); } String[] commonAnnotationBeanPostProcessorNames = getBeansForType(CommonAnnotationBeanPostProcessor.class.getName()); for (String commonAnnotationBeanPostProcessorName : commonAnnotationBeanPostProcessorNames) { CommonAnnnotationInjectionMetadataProvider provider = new CommonAnnnotationInjectionMetadataProvider(); IBean bean = getBean(commonAnnotationBeanPostProcessorName); BeanDefinition beanDef = BeansModelUtils.getMergedBeanDefinition(bean, context); if (beanDef.getPropertyValues().size() > 0) { BeanWrapperImpl wrapper = new BeanWrapperImpl(true); wrapper.setConversionService(new DefaultConversionService()); wrapper.setWrappedInstance(provider); for (PropertyValue pv : beanDef.getPropertyValues().getPropertyValueList()) { if (wrapper.isWritableProperty(pv.getName())) { // TODO other values types required as well? if (pv.getValue() instanceof TypedStringValue) { wrapper.setPropertyValue(pv.getName(), (((TypedStringValue) pv.getValue())).getValue()); } } } } provider.setProblemReporter(problemReporter); providers.add(provider); } return providers; } private AutowireCandidateResolver getAutowireCandidateResolver() { QualifierAnnotationAutowireCandidateResolver resolver = new QualifierAnnotationAutowireCandidateResolver( this.classLoaderSupport.getProjectClassLoader()); resolver.setProblemReporter(problemReporter); return resolver; } protected void createProjectClassLoaderSupport() { if (this.classLoaderSupport == null) { this.classLoaderSupport = JdtUtils.getProjectClassLoaderSupport(project.getProject(), null); } } public void setProjectClassLoaderSupport(IProjectClassLoaderSupport classLoaderSupport) { this.classLoaderSupport = classLoaderSupport; } protected String determinePrimaryCandidate(Map<String, IBean> candidateBeans, DependencyDescriptor descriptor) { String primaryBeanName = null; String fallbackBeanName = null; for (Map.Entry<String, IBean> entry : candidateBeans.entrySet()) { String candidateBeanName = entry.getKey(); Object beanInstance = entry.getValue(); if (isPrimary(candidateBeanName, beanInstance)) { if (primaryBeanName != null) { boolean candidateLocal = containsBean(candidateBeanName); boolean primaryLocal = containsBean(primaryBeanName); if (candidateLocal == primaryLocal) { problemReporter.error("More than one 'primary' bean found among candiates [" + candidateBeans.keySet() + "]", descriptor); throw new AutowireResolutionException(); } else if (candidateLocal && !primaryLocal) { primaryBeanName = candidateBeanName; } } else { primaryBeanName = candidateBeanName; } } if (primaryBeanName == null && (matchesBeanName(candidateBeanName, descriptor.getDependencyName()))) { fallbackBeanName = candidateBeanName; } } return (primaryBeanName != null ? primaryBeanName : fallbackBeanName); } protected void doResolveDependency(DependencyDescriptor descriptor, Class<?> type, String beanName, Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException { if (type.isArray()) { Class<?> componentType = type.getComponentType(); Map<String, IBean> matchingBeans = findAutowireCandidates(beanName, componentType, descriptor); if (matchingBeans.isEmpty()) { if (descriptor.isRequired()) { problemReporter.error("No matching beans found for 'required' dependency array", descriptor); throw new AutowireResolutionException(); } } if (autowiredBeanNames != null) { autowiredBeanNames.addAll(matchingBeans.keySet()); } } else if (Collection.class.isAssignableFrom(type) && type.isInterface()) { Class<?> elementType = descriptor.getCollectionType(); if (elementType == null) { if (descriptor.isRequired()) { problemReporter.error( "No element type declared for 'required' collection [" + type.getName() + "]", descriptor); throw new AutowireResolutionException(); } } Map<String, IBean> matchingBeans = findAutowireCandidates(beanName, elementType, descriptor); if (matchingBeans.isEmpty()) { if (descriptor.isRequired()) { problemReporter.error("No matching beans found for 'required' dependency collection", descriptor); throw new AutowireResolutionException(); } } if (autowiredBeanNames != null) { autowiredBeanNames.addAll(matchingBeans.keySet()); } } else if (Map.class.isAssignableFrom(type) && type.isInterface()) { Class<?> keyType = descriptor.getMapKeyType(); if (keyType == null || !String.class.isAssignableFrom(keyType)) { if (descriptor.isRequired()) { problemReporter.error("Key type [" + keyType + "] of map [" + type.getName() + "] must be assignable to [java.lang.String]", descriptor); throw new AutowireResolutionException(); } } Class<?> valueType = descriptor.getMapValueType(); if (valueType == null) { if (descriptor.isRequired()) { problemReporter.error("No value type declared for 'required' map [" + type.getName() + "]", descriptor); throw new AutowireResolutionException(); } } Map<String, IBean> matchingBeans = findAutowireCandidates(beanName, valueType, descriptor); if (matchingBeans.isEmpty()) { if (descriptor.isRequired()) { problemReporter.error("No matching beans found for 'required' dependency map for value type [" + valueType.getName() + "]", descriptor); throw new AutowireResolutionException(); } } if (autowiredBeanNames != null) { autowiredBeanNames.addAll(matchingBeans.keySet()); } } else { Map<String, IBean> matchingBeans = findAutowireCandidates(beanName, type, descriptor); if (matchingBeans.isEmpty()) { if (descriptor.isRequired()) { problemReporter.error("Unsatisfied 'required' dependency of type [" + type + "]. Expected at least 1 matching bean", descriptor, new ValidationProblemAttribute(AUTOWIRE_PROBLEM_TYPE, REQUIRED_NO_MATCH)); throw new AutowireResolutionException(); } return; } if (matchingBeans.size() > 1) { String primaryBeanName = determinePrimaryCandidate(matchingBeans, descriptor); if (primaryBeanName == null) { Set<String> matchingBeanNames = matchingBeans.keySet(); ValidationProblemAttribute[] attributes = new ValidationProblemAttribute[matchingBeanNames.size() + 2]; attributes[0] = new ValidationProblemAttribute(AUTOWIRE_PROBLEM_TYPE, TOO_MANY_MATCHING_BEANS); attributes[1] = new ValidationProblemAttribute(BEAN_TYPE, type.getName()); int counter = 2; for(String matchingBeanName: matchingBeanNames) { attributes[counter] = new ValidationProblemAttribute(MATCHING_BEAN_NAME + counter, matchingBeanName); counter++; } problemReporter.error("Expected single matching bean but found " + matchingBeans.size() + ": " + matchingBeanNames, descriptor, attributes); throw new AutowireResolutionException(); } if (autowiredBeanNames != null) { autowiredBeanNames.add(primaryBeanName); return; } } // We have exactly one match. Map.Entry<String, IBean> entry = matchingBeans.entrySet().iterator().next(); if (autowiredBeanNames != null) { autowiredBeanNames.add(entry.getKey()); } } } protected Map<String, IBean> findAutowireCandidates(String beanName, Class<?> requiredType, DependencyDescriptor descriptor) { String[] candidateNames = getBeansForType(requiredType); Map<String, IBean> result = new LinkedHashMap<String, IBean>(candidateNames.length); for (Class<?> autowiringType : this.resolvableDependencies.keySet()) { if (autowiringType.isAssignableFrom(requiredType)) { String autowiringValue = this.resolvableDependencies.get(autowiringType); result.put(autowiringValue, null); break; } } for (String candidateName : candidateNames) { if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, descriptor)) { result.put(candidateName, getBean(candidateName)); } } return result; } protected boolean isAutowireCandidate(String beanName, BeanDefinition mbd, DependencyDescriptor descriptor) { return getAutowireCandidateResolver().isAutowireCandidate( new BeanDefinitionHolder(mbd, beanName, getAliases(beanName)), descriptor); } protected boolean isPrimary(String beanName, Object beanInstance) { if (containsBean(beanName)) { return BeansModelUtils.getMergedBeanDefinition(getBean(beanName), context).isPrimary(); } return false; } protected boolean matchesBeanName(String beanName, String candidateName) { return (candidateName != null && (candidateName.equals(beanName) || ObjectUtils.containsElement( getAliases(beanName), candidateName))); } public void resolveDependency(DependencyDescriptor descriptor, Class<?> type, String beanName, Set<String> autowiredBeanNames, TypeConverter typeConverter) { descriptor.initParameterNameDiscovery(this.parameterNameDiscoverer); if (descriptor.getDependencyType().equals(objectFactoryClass) || descriptor.getDependencyType().equals(providerClass)) { descriptor.increaseNestingLevel(); type = descriptor.getDependencyType(); } try { doResolveDependency(descriptor, type, beanName, autowiredBeanNames, typeConverter); } catch (AutowireResolutionException e) { // we can ignore this as problems have been reported using the problem reporter } } @SuppressWarnings("serial") private static class AutowireResolutionException extends RuntimeException { } private class AutowireProblemReporter implements IInjectionMetadataProviderProblemReporter { public void error(String message, Member member, ValidationProblemAttribute... attributes) { try { IJavaElement source = AutowireUtils.getJavaElement(project.getProject(), member, -1); if (source != null && source.getUnderlyingResource() != null) { ValidationProblemAttribute[] newAttributes = new ValidationProblemAttribute[attributes.length + 1]; for(int i=0; i<attributes.length; i++) { newAttributes[i] = attributes[i]; } newAttributes[attributes.length] = new ValidationProblemAttribute("JAVA_HANDLE", source.getHandleIdentifier()); // By convention autowire problems will only get reported as warnings (for now?) problems.add(new ValidationProblem(IMarker.SEVERITY_WARNING, message, source .getUnderlyingResource(), JdtUtils.getLineNumber(source), newAttributes)); } } catch (JavaModelException e) { } } public void error(String message, DependencyDescriptor descriptor, ValidationProblemAttribute... attributes) { if (descriptor.getField() != null) { error(message, descriptor.getField(), attributes); } else if (descriptor.getMethodParameter() != null && descriptor.getMethodParameter().getMethod() != null) { error(message, descriptor.getMethodParameter().getMethod(), attributes); } else if (descriptor.getMethodParameter() != null && descriptor.getMethodParameter().getConstructor() != null) { error(message, descriptor.getMethodParameter().getConstructor(), attributes); } } } }