Save This Page
Home » spring-framework-2.5.6-with-dependencies » org.springframework » aop » support » [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.aop.support;
   18   
   19   import java.lang.reflect.InvocationTargetException;
   20   import java.lang.reflect.Method;
   21   import java.lang.reflect.Proxy;
   22   import java.util.HashSet;
   23   import java.util.Iterator;
   24   import java.util.LinkedList;
   25   import java.util.List;
   26   import java.util.Set;
   27   
   28   import org.springframework.aop.Advisor;
   29   import org.springframework.aop.AopInvocationException;
   30   import org.springframework.aop.IntroductionAdvisor;
   31   import org.springframework.aop.IntroductionAwareMethodMatcher;
   32   import org.springframework.aop.MethodMatcher;
   33   import org.springframework.aop.Pointcut;
   34   import org.springframework.aop.PointcutAdvisor;
   35   import org.springframework.aop.SpringProxy;
   36   import org.springframework.aop.TargetClassAware;
   37   import org.springframework.core.BridgeMethodResolver;
   38   import org.springframework.core.JdkVersion;
   39   import org.springframework.util.Assert;
   40   import org.springframework.util.ClassUtils;
   41   import org.springframework.util.ReflectionUtils;
   42   
   43   /**
   44    * Utility methods for AOP support code.
   45    * Mainly for internal use within Spring's AOP support.
   46    *
   47    * <p>See {@link org.springframework.aop.framework.AopProxyUtils} for a
   48    * collection of framework-specific AOP utility methods which depend
   49    * on internals of Spring's AOP framework implementation.
   50    *
   51    * @author Rod Johnson
   52    * @author Juergen Hoeller
   53    * @author Rob Harrop
   54    * @see org.springframework.aop.framework.AopProxyUtils
   55    */
   56   public abstract class AopUtils {
   57   
   58   	/**
   59   	 * Check whether the given object is a JDK dynamic proxy or a CGLIB proxy.
   60   	 * @param object the object to check
   61   	 * @see #isJdkDynamicProxy
   62   	 * @see #isCglibProxy
   63   	 */
   64   	public static boolean isAopProxy(Object object) {
   65   		return (object instanceof SpringProxy &&
   66   				(Proxy.isProxyClass(object.getClass()) || isCglibProxyClass(object.getClass())));
   67   	}
   68   
   69   	/**
   70   	 * Check whether the given object is a JDK dynamic proxy.
   71   	 * @param object the object to check
   72   	 * @see java.lang.reflect.Proxy#isProxyClass
   73   	 */
   74   	public static boolean isJdkDynamicProxy(Object object) {
   75   		return (object instanceof SpringProxy && Proxy.isProxyClass(object.getClass()));
   76   	}
   77   
   78   	/**
   79   	 * Check whether the given object is a CGLIB proxy.
   80   	 * @param object the object to check
   81   	 */
   82   	public static boolean isCglibProxy(Object object) {
   83   		return (object instanceof SpringProxy && isCglibProxyClass(object.getClass()));
   84   	}
   85   
   86   	/**
   87   	 * Check whether the specified class is a CGLIB-generated class.
   88   	 * @param clazz the class to check
   89   	 */
   90   	public static boolean isCglibProxyClass(Class clazz) {
   91   		return (clazz != null && clazz.getName().indexOf(ClassUtils.CGLIB_CLASS_SEPARATOR) != -1);
   92   	}
   93   
   94   	/**
   95   	 * Determine the target class of the given bean instance,
   96   	 * which might be an AOP proxy.
   97   	 * <p>Returns the target class for an AOP proxy and the plain class else.
   98   	 * @param candidate the instance to check (might be an AOP proxy)
   99   	 * @return the target class (or the plain class of the given object as fallback)
  100   	 * @see org.springframework.aop.TargetClassAware#getTargetClass()
  101   	 */
  102   	public static Class getTargetClass(Object candidate) {
  103   		Assert.notNull(candidate, "Candidate object must not be null");
  104   		if (candidate instanceof TargetClassAware) {
  105   			return ((TargetClassAware) candidate).getTargetClass();
  106   		}
  107   		if (isCglibProxyClass(candidate.getClass())) {
  108   			return candidate.getClass().getSuperclass();
  109   		}
  110   		return candidate.getClass();
  111   	}
  112   
  113   	/**
  114   	 * Determine whether the given method is an "equals" method.
  115   	 * @see java.lang.Object#equals
  116   	 */
  117   	public static boolean isEqualsMethod(Method method) {
  118   		return ReflectionUtils.isEqualsMethod(method);
  119   	}
  120   
  121   	/**
  122   	 * Determine whether the given method is a "hashCode" method.
  123   	 * @see java.lang.Object#hashCode
  124   	 */
  125   	public static boolean isHashCodeMethod(Method method) {
  126   		return ReflectionUtils.isHashCodeMethod(method);
  127   	}
  128   
  129   	/**
  130   	 * Determine whether the given method is a "toString" method.
  131   	 * @see java.lang.Object#toString()
  132   	 */
  133   	public static boolean isToStringMethod(Method method) {
  134   		return ReflectionUtils.isToStringMethod(method);
  135   	}
  136   
  137   	/**
  138   	 * Determine whether the given method is a "finalize" method.
  139   	 * @see java.lang.Object#finalize()
  140   	 */
  141   	public static boolean isFinalizeMethod(Method method) {
  142   		return (method != null && method.getName().equals("finalize") &&
  143   				method.getParameterTypes().length == 0);
  144   	}
  145   
  146   	/**
  147   	 * Given a method, which may come from an interface, and a target class used
  148   	 * in the current AOP invocation, find the corresponding target method if there
  149   	 * is one. E.g. the method may be <code>IFoo.bar()</code> and the target class
  150   	 * may be <code>DefaultFoo</code>. In this case, the method may be
  151   	 * <code>DefaultFoo.bar()</code>. This enables attributes on that method to be found.
  152   	 * <p><b>NOTE:</b> In contrast to {@link org.springframework.util.ClassUtils#getMostSpecificMethod},
  153   	 * this method resolves Java 5 bridge methods in order to retrieve attributes
  154   	 * from the <i>original</i> method definition.
  155   	 * @param method the method to be invoked, which may come from an interface
  156   	 * @param targetClass the target class for the current invocation.
  157   	 * May be <code>null</code> or may not even implement the method.
  158   	 * @return the specific target method, or the original method if the
  159   	 * <code>targetClass</code> doesn't implement it or is <code>null</code>
  160   	 * @see org.springframework.util.ClassUtils#getMostSpecificMethod
  161   	 */
  162   	public static Method getMostSpecificMethod(Method method, Class targetClass) {
  163   		Method resolvedMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
  164   		// If we are dealing with method with generic parameters, find the original method.
  165   		if (JdkVersion.isAtLeastJava15()) {
  166   			resolvedMethod = BridgeMethodResolver.findBridgedMethod(resolvedMethod);
  167   		}
  168   		return resolvedMethod;
  169   	}
  170   
  171   
  172   	/**
  173   	 * Can the given pointcut apply at all on the given class?
  174   	 * <p>This is an important test as it can be used to optimize
  175   	 * out a pointcut for a class.
  176   	 * @param pc the static or dynamic pointcut to check
  177   	 * @param targetClass the class to test
  178   	 * @return whether the pointcut can apply on any method
  179   	 */
  180   	public static boolean canApply(Pointcut pc, Class targetClass) {
  181   		return canApply(pc, targetClass, false);
  182   	}
  183   
  184   	/**
  185   	 * Can the given pointcut apply at all on the given class?
  186   	 * <p>This is an important test as it can be used to optimize
  187   	 * out a pointcut for a class.
  188   	 * @param pc the static or dynamic pointcut to check
  189   	 * @param targetClass the class to test
  190   	 * @param hasIntroductions whether or not the advisor chain
  191   	 * for this bean includes any introductions
  192   	 * @return whether the pointcut can apply on any method
  193   	 */
  194   	public static boolean canApply(Pointcut pc, Class targetClass, boolean hasIntroductions) {
  195   		if (!pc.getClassFilter().matches(targetClass)) {
  196   			return false;
  197   		}
  198   
  199   		MethodMatcher methodMatcher = pc.getMethodMatcher();
  200   		IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
  201   		if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
  202   			introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
  203   		}
  204   
  205   		Set classes = new HashSet(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
  206   		classes.add(targetClass);
  207   		for (Iterator it = classes.iterator(); it.hasNext();) {
  208   			Class clazz = (Class) it.next();
  209   			Method[] methods = clazz.getMethods();
  210   			for (int j = 0; j < methods.length; j++) {
  211   				if ((introductionAwareMethodMatcher != null &&
  212   						introductionAwareMethodMatcher.matches(methods[j], targetClass, hasIntroductions)) ||
  213   						methodMatcher.matches(methods[j], targetClass)) {
  214   					return true;
  215   				}
  216   			}
  217   		}
  218   
  219   		return false;
  220   	}
  221   
  222   	/**
  223   	 * Can the given advisor apply at all on the given class?
  224   	 * This is an important test as it can be used to optimize
  225   	 * out a advisor for a class.
  226   	 * @param advisor the advisor to check
  227   	 * @param targetClass class we're testing
  228   	 * @return whether the pointcut can apply on any method
  229   	 */
  230   	public static boolean canApply(Advisor advisor, Class targetClass) {
  231   		return canApply(advisor, targetClass, false);
  232   	}
  233   
  234   	/**
  235   	 * Can the given advisor apply at all on the given class?
  236   	 * <p>This is an important test as it can be used to optimize out a advisor for a class.
  237   	 * This version also takes into account introductions (for IntroductionAwareMethodMatchers).
  238   	 * @param advisor the advisor to check
  239   	 * @param targetClass class we're testing
  240   	 * @param hasIntroductions whether or not the advisor chain for this bean includes
  241   	 * any introductions
  242   	 * @return whether the pointcut can apply on any method
  243   	 */
  244   	public static boolean canApply(Advisor advisor, Class targetClass, boolean hasIntroductions) {
  245   		if (advisor instanceof IntroductionAdvisor) {
  246   			return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
  247   		}
  248   		else if (advisor instanceof PointcutAdvisor) {
  249   			PointcutAdvisor pca = (PointcutAdvisor) advisor;
  250   			return canApply(pca.getPointcut(), targetClass, hasIntroductions);
  251   		}
  252   		else {
  253   			// It doesn't have a pointcut so we assume it applies.
  254   			return true;
  255   		}
  256   	}
  257   
  258   	/**
  259   	 * Determine the sublist of the <code>candidateAdvisors</code> list
  260   	 * that is applicable to the given class.
  261   	 * @param candidateAdvisors the Advisors to evaluate
  262   	 * @param clazz the target class
  263   	 * @return sublist of Advisors that can apply to an object of the given class
  264   	 * (may be the incoming List as-is)
  265   	 */
  266   	public static List findAdvisorsThatCanApply(List candidateAdvisors, Class clazz) {
  267   		if (candidateAdvisors.isEmpty()) {
  268   			return candidateAdvisors;
  269   		}
  270   		List eligibleAdvisors = new LinkedList();
  271   		for (Iterator it = candidateAdvisors.iterator(); it.hasNext();) {
  272   			Advisor candidate = (Advisor) it.next();
  273   			if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
  274   				eligibleAdvisors.add(candidate);
  275   			}
  276   		}
  277   		boolean hasIntroductions = !eligibleAdvisors.isEmpty();
  278   		for (Iterator it = candidateAdvisors.iterator(); it.hasNext();) {
  279   			Advisor candidate = (Advisor) it.next();
  280   			if (candidate instanceof IntroductionAdvisor) {
  281   				// already processed
  282   				continue;
  283   			}
  284   			if (canApply(candidate, clazz, hasIntroductions)) {
  285   				eligibleAdvisors.add(candidate);
  286   			}
  287   		}
  288   		return eligibleAdvisors;
  289   	}
  290   
  291   
  292   	/**
  293   	 * Invoke the given target via reflection, as part of an AOP method invocation.
  294   	 * @param target the target object
  295   	 * @param method the method to invoke
  296   	 * @param args the arguments for the method
  297   	 * @return the invocation result, if any
  298   	 * @throws Throwable if thrown by the target method
  299   	 * @throws org.springframework.aop.AopInvocationException in case of a reflection error
  300   	 */
  301   	public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
  302   	    throws Throwable {
  303   
  304   		// Use reflection to invoke the method.
  305   		try {
  306   			ReflectionUtils.makeAccessible(method);
  307   			return method.invoke(target, args);
  308   		}
  309   		catch (InvocationTargetException ex) {
  310   			// Invoked method threw a checked exception.
  311   			// We must rethrow it. The client won't see the interceptor.
  312   			throw ex.getTargetException();
  313   		}
  314   		catch (IllegalArgumentException ex) {
  315   			throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
  316   					method + "] on target [" + target + "]", ex);
  317   		}
  318   		catch (IllegalAccessException ex) {
  319   			throw new AopInvocationException("Could not access method [" + method + "]", ex);
  320   		}
  321   	}
  322   
  323   }

Save This Page
Home » spring-framework-2.5.6-with-dependencies » org.springframework » aop » support » [javadoc | source]