/******************************************************************************* * Copyright (c) 2009 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.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; import org.springframework.beans.PropertyValues; import org.springframework.beans.SimpleTypeConverter; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.DependencyDescriptor; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.ide.eclipse.beans.core.autowire.AutowireBeanReference; import org.springframework.ide.eclipse.beans.core.autowire.IAutowireDependencyResolver; import org.springframework.ide.eclipse.beans.core.internal.model.BeansModelUtils; import org.springframework.ide.eclipse.beans.core.model.IBean; import org.springframework.ide.eclipse.beans.core.model.IBeanReference; import org.springframework.ide.eclipse.beans.core.model.IBeansModelElement; /** * Internal class for managing injection meta data. * @author Christian Dupuis * @since 2.2.7 */ public class InjectionMetadata { private final Set<InjectedElement> injectedFields = new LinkedHashSet<InjectedElement>(); private final Set<InjectedElement> injectedMethods = new LinkedHashSet<InjectedElement>(); private final Set<InjectedElement> injectedConstructors = new LinkedHashSet<InjectedElement>(); public void addInjectedField(InjectedElement element) { this.injectedFields.add(element); } public void addInjectedMethod(InjectedElement element) { this.injectedMethods.add(element); } public void addInjectedConstructor(InjectedElement element) { this.injectedConstructors.add(element); } public Set<InjectedElement> getInjectedFields() { return injectedFields; } public Set<InjectedElement> getInjectedMethods() { return injectedMethods; } public Set<InjectedElement> getInjectedConstructors() { return injectedConstructors; } public static abstract class InjectedElement { protected final Member member; protected final boolean isField; protected final PropertyDescriptor pd; protected volatile Boolean skip; protected InjectedElement(Member member, PropertyDescriptor pd) { this.member = member; this.isField = (member instanceof Field); this.pd = pd; } public final Member getMember() { return this.member; } protected final Class<?> getResourceType() { if (this.isField) { return ((Field) this.member).getType(); } else if (this.pd != null) { return this.pd.getPropertyType(); } else { return ((Method) this.member).getParameterTypes()[0]; } } protected final void checkResourceType(Class<?> resourceType) { if (this.isField) { Class<?> fieldType = ((Field) this.member).getType(); if (!(resourceType.isAssignableFrom(fieldType) || fieldType.isAssignableFrom(resourceType))) { throw new IllegalStateException("Specified field type [" + fieldType + "] is incompatible with resource type [" + resourceType.getName() + "]"); } } else { Class<?> paramType = (this.pd != null ? this.pd.getPropertyType() : ((Method) this.member) .getParameterTypes()[0]); if (!(resourceType.isAssignableFrom(paramType) || paramType.isAssignableFrom(resourceType))) { throw new IllegalStateException("Specified parameter type [" + paramType + "] is incompatible with resource type [" + resourceType.getName() + "]"); } } } protected abstract DependencyDescriptor[] getDependencyDescriptor(IAutowireDependencyResolver resolver); public Set<IBeanReference> getBeanReferences(IBean bean, IBeansModelElement context, IAutowireDependencyResolver resolver) { Set<IBeanReference> autowiredReferences = new HashSet<IBeanReference>(); BeanDefinition db = BeansModelUtils.getMergedBeanDefinition(bean, context); if (!shouldSkip(db)) { for (DependencyDescriptor dependencyDescriptor : getDependencyDescriptor(resolver)) { Set<String> autowiredBeanNames = new HashSet<String>(); resolver.resolveDependency(dependencyDescriptor, dependencyDescriptor.getDependencyType(), bean .getElementName(), autowiredBeanNames, new SimpleTypeConverter()); for (String autowiredBeanName : autowiredBeanNames) { AutowireBeanReference ref = new AutowireBeanReference(bean, new RuntimeBeanReference( autowiredBeanName)); if (dependencyDescriptor.getField() != null) { ref.setSource(dependencyDescriptor.getField()); } else if (dependencyDescriptor.getMethodParameter() != null && dependencyDescriptor.getMethodParameter().getMethod() != null) { ref.setSource(dependencyDescriptor.getMethodParameter().getMethod(), dependencyDescriptor .getMethodParameter().getParameterIndex()); } else if (dependencyDescriptor.getMethodParameter() != null && dependencyDescriptor.getMethodParameter().getConstructor() != null) { ref.setSource(dependencyDescriptor.getMethodParameter().getConstructor(), dependencyDescriptor.getMethodParameter().getParameterIndex()); } autowiredReferences.add(ref); } } } return autowiredReferences; } public boolean shouldSkip(BeanDefinition bd) { return false; } /** * Checks whether this injector's property needs to be skipped due to an explicit property value having been * specified. Also marks the affected property as processed for other processors to ignore it. */ protected boolean checkPropertySkipping(PropertyValues pvs) { if (this.pd != null && pvs != null) { if (pvs.contains(this.pd.getName())) { // Explicit value provided as part of the bean definition. return true; } // else if (pvs instanceof MutablePropertyValues) { // ((MutablePropertyValues) pvs).registerProcessedProperty(this.pd.getName()); // } } return false; } @Override public boolean equals(Object other) { if (this == other) { return true; } if (!(other instanceof InjectedElement)) { return false; } InjectedElement otherElement = (InjectedElement) other; return this.member.equals(otherElement.member); } @Override public int hashCode() { return this.member.getClass().hashCode() * 29 + this.member.getName().hashCode(); } @Override public String toString() { return getClass().getSimpleName() + " for " + this.member; } } }