Save This Page
Home » spring-framework-2.5.6-with-dependencies » org.springframework » beans » factory » annotation » [javadoc | source]
    1   /*
    2    * Copyright 2002-2008 the original author or authors.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
   10    * Unless required by applicable law or agreed to in writing, software
   11    * distributed under the License is distributed on an "AS IS" BASIS,
   12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13    * See the License for the specific language governing permissions and
   14    * limitations under the License.
   15    */
   16   
   17   package org.springframework.beans.factory.annotation;
   18   
   19   import java.beans.PropertyDescriptor;
   20   import java.lang.reflect.Field;
   21   import java.lang.reflect.InvocationTargetException;
   22   import java.lang.reflect.Member;
   23   import java.lang.reflect.Method;
   24   import java.util.Arrays;
   25   import java.util.Iterator;
   26   import java.util.LinkedHashSet;
   27   import java.util.Set;
   28   
   29   import org.apache.commons.logging.Log;
   30   import org.apache.commons.logging.LogFactory;
   31   
   32   import org.springframework.beans.MutablePropertyValues;
   33   import org.springframework.beans.PropertyValues;
   34   import org.springframework.beans.factory.support.RootBeanDefinition;
   35   import org.springframework.util.ReflectionUtils;
   36   
   37   /**
   38    * Internal class for managing injection metadata.
   39    * Not intended for direct use in applications.
   40    *
   41    * <p>Used by {@link AutowiredAnnotationBeanPostProcessor},
   42    * {@link org.springframework.context.annotation.CommonAnnotationBeanPostProcessor} and
   43    * {@link org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor}.
   44    *
   45    * @author Juergen Hoeller
   46    * @since 2.5
   47    */
   48   public class InjectionMetadata {
   49   
   50   	private final Log logger = LogFactory.getLog(InjectionMetadata.class);
   51   
   52   	private String targetClassName;
   53   
   54   	private final Set<InjectedElement> injectedFields = new LinkedHashSet<InjectedElement>();
   55   
   56   	private final Set<InjectedElement> injectedMethods = new LinkedHashSet<InjectedElement>();
   57   
   58   
   59   	public InjectionMetadata() {
   60   	}
   61   
   62   	public InjectionMetadata(Class targetClass) {
   63   		this.targetClassName = targetClass.getName();
   64   	}
   65   
   66   
   67   	public void addInjectedField(InjectedElement element) {
   68   		if (logger.isDebugEnabled()) {
   69   			logger.debug("Found injected field on class [" + this.targetClassName + "]: " + element);
   70   		}
   71   		this.injectedFields.add(element);
   72   	}
   73   
   74   	public void addInjectedMethod(InjectedElement element) {
   75   		if (logger.isDebugEnabled()) {
   76   			logger.debug("Found injected method on class [" + this.targetClassName + "]: " + element);
   77   		}
   78   		this.injectedMethods.add(element);
   79   	}
   80   
   81   	public void checkConfigMembers(RootBeanDefinition beanDefinition) {
   82   		doRegisterConfigMembers(beanDefinition, this.injectedFields);
   83   		doRegisterConfigMembers(beanDefinition, this.injectedMethods);
   84   	}
   85   
   86   	private void doRegisterConfigMembers(RootBeanDefinition beanDefinition, Set<InjectedElement> members) {
   87   		for (Iterator<InjectedElement> it = members.iterator(); it.hasNext();) {
   88   			Member member = it.next().getMember();
   89   			if (!beanDefinition.isExternallyManagedConfigMember(member)) {
   90   				beanDefinition.registerExternallyManagedConfigMember(member);
   91   			}
   92   			else {
   93   				it.remove();
   94   			}
   95   		}
   96   	}
   97   
   98   	public void injectFields(Object target, String beanName) throws Throwable {
   99   		if (!this.injectedFields.isEmpty()) {
  100   			boolean debug = logger.isDebugEnabled();
  101   			for (InjectedElement element : this.injectedFields) {
  102   				if (debug) {
  103   					logger.debug("Processing injected field of bean '" + beanName + "': " + element);
  104   				}
  105   				element.inject(target, beanName, null);
  106   			}
  107   		}
  108   	}
  109   
  110   	public void injectMethods(Object target, String beanName, PropertyValues pvs) throws Throwable {
  111   		if (!this.injectedMethods.isEmpty()) {
  112   			boolean debug = logger.isDebugEnabled();
  113   			for (InjectedElement element : this.injectedMethods) {
  114   				if (debug) {
  115   					logger.debug("Processing injected method of bean '" + beanName + "': " + element);
  116   				}
  117   				element.inject(target, beanName, pvs);
  118   			}
  119   		}
  120   	}
  121   
  122   
  123   	public static abstract class InjectedElement {
  124   
  125   		protected final Member member;
  126   
  127   		protected final boolean isField;
  128   
  129   		protected final PropertyDescriptor pd;
  130   
  131   		protected volatile Boolean skip;
  132   
  133   		protected InjectedElement(Member member, PropertyDescriptor pd) {
  134   			this.member = member;
  135   			this.isField = (member instanceof Field);
  136   			this.pd = pd;
  137   		}
  138   
  139   		public final Member getMember() {
  140   			return this.member;
  141   		}
  142   
  143   		protected final Class getResourceType() {
  144   			if (this.isField) {
  145   				return ((Field) this.member).getType();
  146   			}
  147   			else if (this.pd != null) {
  148   				return this.pd.getPropertyType();
  149   			}
  150   			else {
  151   				return ((Method) this.member).getParameterTypes()[0];
  152   			}
  153   		}
  154   
  155   		protected final void checkResourceType(Class resourceType) {
  156   			if (this.isField) {
  157   				Class fieldType = ((Field) this.member).getType();
  158   				if (!(resourceType.isAssignableFrom(fieldType) || fieldType.isAssignableFrom(resourceType))) {
  159   					throw new IllegalStateException("Specified field type [" + fieldType +
  160   							"] is incompatible with resource type [" + resourceType.getName() + "]");
  161   				}
  162   			}
  163   			else {
  164   				Class paramType =
  165   						(this.pd != null ? this.pd.getPropertyType() : ((Method) this.member).getParameterTypes()[0]);
  166   				if (!(resourceType.isAssignableFrom(paramType) || paramType.isAssignableFrom(resourceType))) {
  167   					throw new IllegalStateException("Specified parameter type [" + paramType +
  168   							"] is incompatible with resource type [" + resourceType.getName() + "]");
  169   				}
  170   			}
  171   		}
  172   
  173   		/**
  174   		 * Either this or {@link #getResourceToInject} needs to be overridden.
  175   		 */
  176   		protected void inject(Object target, String requestingBeanName, PropertyValues pvs) throws Throwable {
  177   			if (this.isField) {
  178   				Field field = (Field) this.member;
  179   				ReflectionUtils.makeAccessible(field);
  180   				field.set(target, getResourceToInject(target, requestingBeanName));
  181   			}
  182   			else {
  183   				if (this.skip == null) {
  184   					this.skip = Boolean.valueOf(checkPropertySkipping(pvs));
  185   				}
  186   				if (this.skip.booleanValue()) {
  187   					return;
  188   				}
  189   				try {
  190   					Method method = (Method) this.member;
  191   					ReflectionUtils.makeAccessible(method);
  192   					method.invoke(target, getResourceToInject(target, requestingBeanName));
  193   				}
  194   				catch (InvocationTargetException ex) {
  195   					throw ex.getTargetException();
  196   				}
  197   			}
  198   		}
  199   
  200   		/**
  201   		 * Checks whether this injector's property needs to be skipped due to
  202   		 * an explicit property value having been specified. Also marks the
  203   		 * affected property as processed for other processors to ignore it.
  204   		 */
  205   		protected boolean checkPropertySkipping(PropertyValues pvs) {
  206   			if (this.pd != null && pvs != null) {
  207   				if (pvs.contains(this.pd.getName())) {
  208   					// Explicit value provided as part of the bean definition.
  209   					return true;
  210   				}
  211   				else if (pvs instanceof MutablePropertyValues) {
  212   					((MutablePropertyValues) pvs).registerProcessedProperty(this.pd.getName());
  213   				}
  214   			}
  215   			return false;
  216   		}
  217   
  218   		/**
  219   		 * Either this or {@link #inject} needs to be overridden.
  220   		 */
  221   		protected Object getResourceToInject(Object target, String requestingBeanName) {
  222   			return null;
  223   		}
  224   
  225   		public boolean equals(Object other) {
  226   			if (this == other) {
  227   				return true;
  228   			}
  229   			if (!(other instanceof InjectedElement)) {
  230   				return false;
  231   			}
  232   			InjectedElement otherElement = (InjectedElement) other;
  233   			if (this.isField) {
  234   				return this.member.equals(otherElement.member);
  235   			}
  236   			else {
  237   				return (otherElement.member instanceof Method &&
  238   						this.member.getName().equals(otherElement.member.getName()) &&
  239   						Arrays.equals(((Method) this.member).getParameterTypes(),
  240   								((Method) otherElement.member).getParameterTypes()));
  241   			}
  242   		}
  243   
  244   		public int hashCode() {
  245   			return this.member.getClass().hashCode() * 29 + this.member.getName().hashCode();
  246   		}
  247   
  248   		public String toString() {
  249   			return getClass().getSimpleName() + " for " + this.member;
  250   		}
  251   	}
  252   
  253   }

Save This Page
Home » spring-framework-2.5.6-with-dependencies » org.springframework » beans » factory » annotation » [javadoc | source]