All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.aop.framework.AopProxyUtils Maven / Gradle / Ivy

There is a newer version: 6.1.6
Show newest version
/*
 * Copyright 2002-2020 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
 *
 *      https://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.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
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.core.DecoratingProxy;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

/**
 * 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 { /** * Obtain the singleton target object behind the given proxy, if any. * @param candidate the (potential) proxy to check * @return the singleton target object managed in a {@link SingletonTargetSource}, * or {@code null} in any other case (not a proxy, not an existing singleton target) * @since 4.3.8 * @see Advised#getTargetSource() * @see SingletonTargetSource#getTarget() */ @Nullable public static Object getSingletonTarget(Object candidate) { if (candidate instanceof Advised) { TargetSource targetSource = ((Advised) candidate).getTargetSource(); if (targetSource instanceof SingletonTargetSource) { return ((SingletonTargetSource) targetSource).getTarget(); } } return null; } /** * 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 ultimate target class (or the plain class of the given * object as fallback; never {@code null}) * @see org.springframework.aop.TargetClassAware#getTargetClass() * @see 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(); current = getSingletonTarget(current); } 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. * @param advised the proxy config * @return the complete set of interfaces to proxy * @see SpringProxy * @see Advised */ public static Class[] completeProxiedInterfaces(AdvisedSupport advised) { return completeProxiedInterfaces(advised, false); } /** * 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. * @param advised the proxy config * @param decoratingProxy whether to expose the {@link DecoratingProxy} interface * @return the complete set of interfaces to proxy * @since 4.3 * @see SpringProxy * @see Advised * @see DecoratingProxy */ static Class[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) { 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) { if (targetClass.isInterface()) { advised.setInterfaces(targetClass); } else if (Proxy.isProxyClass(targetClass)) { advised.setInterfaces(targetClass.getInterfaces()); } specifiedInterfaces = advised.getProxiedInterfaces(); } } boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class); boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class); boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class)); int nonUserIfcCount = 0; if (addSpringProxy) { nonUserIfcCount++; } if (addAdvised) { nonUserIfcCount++; } if (addDecoratingProxy) { nonUserIfcCount++; } Class[] proxiedInterfaces = new Class[specifiedInterfaces.length + nonUserIfcCount]; System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length); int index = specifiedInterfaces.length; if (addSpringProxy) { proxiedInterfaces[index] = SpringProxy.class; index++; } if (addAdvised) { proxiedInterfaces[index] = Advised.class; index++; } if (addDecoratingProxy) { proxiedInterfaces[index] = DecoratingProxy.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} 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++; } if (proxy instanceof DecoratingProxy) { nonUserIfcCount++; } Class[] userInterfaces = Arrays.copyOf(proxyInterfaces, proxyInterfaces.length - nonUserIfcCount); 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 a.getAdvisorCount() == b.getAdvisorCount() && Arrays.equals(a.getAdvisors(), b.getAdvisors()); } /** * Adapt the given arguments to the target signature in the given method, * if necessary: in particular, if a given vararg argument array does not * match the array type of the declared vararg parameter in the method. * @param method the target method * @param arguments the given arguments * @return a cloned argument array, or the original if no adaptation is needed * @since 4.2.3 */ static Object[] adaptArgumentsIfNecessary(Method method, @Nullable Object[] arguments) { if (ObjectUtils.isEmpty(arguments)) { return new Object[0]; } if (method.isVarArgs()) { if (method.getParameterCount() == arguments.length) { Class[] paramTypes = method.getParameterTypes(); int varargIndex = paramTypes.length - 1; Class varargType = paramTypes[varargIndex]; if (varargType.isArray()) { Object varargArray = arguments[varargIndex]; if (varargArray instanceof Object[] && !varargType.isInstance(varargArray)) { Object[] newArguments = new Object[arguments.length]; System.arraycopy(arguments, 0, newArguments, 0, varargIndex); Class targetElementType = varargType.getComponentType(); int varargLength = Array.getLength(varargArray); Object newVarargArray = Array.newInstance(targetElementType, varargLength); System.arraycopy(varargArray, 0, newVarargArray, 0, varargLength); newArguments[varargIndex] = newVarargArray; return newArguments; } } } } return arguments; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy