/* * 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. * *

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 null) * @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 = ((TargetClassAware) current).getTargetClass(); Object nested = null; if (current instanceof Advised) { TargetSource targetSource = ((Advised) current).getTargetSource(); if (targetSource instanceof SingletonTargetSource) { nested = ((SingletonTargetSource) targetSource).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. *

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 null 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()); } }