Open Source Repository

Home /spring/spring-aop-3.0.5 | Repository Home



org/springframework/aop/framework/AopProxyUtils.java
/*
 * Copyright 2002-2010 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.aop.framework;

import java.util.Arrays;

import org.springframework.aop.SpringProxy;
import org.springframework.aop.TargetClassAware;
import org.springframework.aop.TargetSource;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.target.SingletonTargetSource;
import org.springframework.util.Assert;

/**
 * Utility methods for AOP proxy factories.
 * Mainly for internal use within the AOP framework.
 *
 <p>See {@link org.springframework.aop.support.AopUtils} for a collection of
 * generic AOP utility methods which do not depend on AOP framework internals.
 *
 @author Rod Johnson
 @author Juergen Hoeller
 @see org.springframework.aop.support.AopUtils
 */
public abstract class AopProxyUtils {

  /**
   * Determine the ultimate target class of the given bean instance, traversing
   * not only a top-level proxy but any number of nested proxies as well -
   * as long as possible without side effects, that is, just for singleton targets.
   @param candidate the instance to check (might be an AOP proxy)
   @return the target class (or the plain class of the given object as fallback;
   * never <code>null</code>)
   @see org.springframework.aop.TargetClassAware#getTargetClass()
   @see org.springframework.aop.framework.Advised#getTargetSource()
   */
  public static Class<?> ultimateTargetClass(Object candidate) {
    Assert.notNull(candidate, "Candidate object must not be null");
    Object current = candidate;
    Class<?> result = null;
    while (current instanceof TargetClassAware) {
      result = ((TargetClassAwarecurrent).getTargetClass();
      Object nested = null;
      if (current instanceof Advised) {
        TargetSource targetSource = ((Advisedcurrent).getTargetSource();
        if (targetSource instanceof SingletonTargetSource) {
          nested = ((SingletonTargetSourcetargetSource).getTarget();
        }
      }
      current = nested;
    }
    if (result == null) {
      result = (AopUtils.isCglibProxy(candidate? candidate.getClass().getSuperclass() : candidate.getClass());
    }
    return result;
  }

  /**
   * Determine the complete set of interfaces to proxy for the given AOP configuration.
   <p>This will always add the {@link Advised} interface unless the AdvisedSupport's
   {@link AdvisedSupport#setOpaque "opaque"} flag is on. Always adds the
   {@link org.springframework.aop.SpringProxy} marker interface.
   @return the complete set of interfaces to proxy
   @see Advised
   @see org.springframework.aop.SpringProxy
   */
  public static Class[] completeProxiedInterfaces(AdvisedSupport advised) {
    Class[] specifiedInterfaces = advised.getProxiedInterfaces();
    if (specifiedInterfaces.length == 0) {
      // No user-specified interfaces: check whether target class is an interface.
      Class targetClass = advised.getTargetClass();
      if (targetClass != null && targetClass.isInterface()) {
        specifiedInterfaces = new Class[] {targetClass};
      }
    }
    boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
    boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
    int nonUserIfcCount = 0;
    if (addSpringProxy) {
      nonUserIfcCount++;
    }
    if (addAdvised) {
      nonUserIfcCount++;
    }
    Class[] proxiedInterfaces = new Class[specifiedInterfaces.length + nonUserIfcCount];
    System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length);
    if (addSpringProxy) {
      proxiedInterfaces[specifiedInterfaces.length= SpringProxy.class;
    }
    if (addAdvised) {
      proxiedInterfaces[proxiedInterfaces.length - 1= Advised.class;
    }
    return proxiedInterfaces;
  }

  /**
   * Extract the user-specified interfaces that the given proxy implements,
   * i.e. all non-Advised interfaces that the proxy implements.
   @param proxy the proxy to analyze (usually a JDK dynamic proxy)
   @return all user-specified interfaces that the proxy implements,
   * in the original order (never <code>null</code> or empty)
   @see Advised
   */
  public static Class[] proxiedUserInterfaces(Object proxy) {
    Class[] proxyInterfaces = proxy.getClass().getInterfaces();
    int nonUserIfcCount = 0;
    if (proxy instanceof SpringProxy) {
      nonUserIfcCount++;
    }
    if (proxy instanceof Advised) {
      nonUserIfcCount++;
    }
    Class[] userInterfaces = new Class[proxyInterfaces.length - nonUserIfcCount];
    System.arraycopy(proxyInterfaces, 0, userInterfaces, 0, userInterfaces.length);
    Assert.notEmpty(userInterfaces, "JDK proxy must implement one or more interfaces");
    return userInterfaces;
  }

  /**
   * Check equality of the proxies behind the given AdvisedSupport objects.
   * Not the same as equality of the AdvisedSupport objects:
   * rather, equality of interfaces, advisors and target sources.
   */
  public static boolean equalsInProxy(AdvisedSupport a, AdvisedSupport b) {
    return (a == b ||
        (equalsProxiedInterfaces(a, b&& equalsAdvisors(a, b&& a.getTargetSource().equals(b.getTargetSource())));
  }

  /**
   * Check equality of the proxied interfaces behind the given AdvisedSupport objects.
   */
  public static boolean equalsProxiedInterfaces(AdvisedSupport a, AdvisedSupport b) {
    return Arrays.equals(a.getProxiedInterfaces(), b.getProxiedInterfaces());
  }

  /**
   * Check equality of the advisors behind the given AdvisedSupport objects.
   */
  public static boolean equalsAdvisors(AdvisedSupport a, AdvisedSupport b) {
    return Arrays.equals(a.getAdvisors(), b.getAdvisors());
  }

}