001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.aop.aspectj; 018 019import java.io.Serializable; 020import java.lang.reflect.Method; 021import java.lang.reflect.Type; 022 023import org.springframework.aop.AfterAdvice; 024import org.springframework.aop.AfterReturningAdvice; 025import org.springframework.util.ClassUtils; 026import org.springframework.util.TypeUtils; 027 028/** 029 * Spring AOP advice wrapping an AspectJ after-returning advice method. 030 * 031 * @author Rod Johnson 032 * @author Juergen Hoeller 033 * @author Ramnivas Laddad 034 * @since 2.0 035 */ 036@SuppressWarnings("serial") 037public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice 038 implements AfterReturningAdvice, AfterAdvice, Serializable { 039 040 public AspectJAfterReturningAdvice( 041 Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { 042 043 super(aspectJBeforeAdviceMethod, pointcut, aif); 044 } 045 046 047 @Override 048 public boolean isBeforeAdvice() { 049 return false; 050 } 051 052 @Override 053 public boolean isAfterAdvice() { 054 return true; 055 } 056 057 @Override 058 public void setReturningName(String name) { 059 setReturningNameNoCheck(name); 060 } 061 062 @Override 063 public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { 064 if (shouldInvokeOnReturnValueOf(method, returnValue)) { 065 invokeAdviceMethod(getJoinPointMatch(), returnValue, null); 066 } 067 } 068 069 070 /** 071 * Following AspectJ semantics, if a returning clause was specified, then the 072 * advice is only invoked if the returned value is an instance of the given 073 * returning type and generic type parameters, if any, match the assignment 074 * rules. If the returning type is Object, the advice is *always* invoked. 075 * @param returnValue the return value of the target method 076 * @return whether to invoke the advice method for the given return value 077 */ 078 private boolean shouldInvokeOnReturnValueOf(Method method, Object returnValue) { 079 Class<?> type = getDiscoveredReturningType(); 080 Type genericType = getDiscoveredReturningGenericType(); 081 // If we aren't dealing with a raw type, check if generic parameters are assignable. 082 return (matchesReturnValue(type, method, returnValue) && 083 (genericType == null || genericType == type || 084 TypeUtils.isAssignable(genericType, method.getGenericReturnType()))); 085 } 086 087 /** 088 * Following AspectJ semantics, if a return value is null (or return type is void), 089 * then the return type of target method should be used to determine whether advice 090 * is invoked or not. Also, even if the return type is void, if the type of argument 091 * declared in the advice method is Object, then the advice must still get invoked. 092 * @param type the type of argument declared in advice method 093 * @param method the advice method 094 * @param returnValue the return value of the target method 095 * @return whether to invoke the advice method for the given return value and type 096 */ 097 private boolean matchesReturnValue(Class<?> type, Method method, Object returnValue) { 098 if (returnValue != null) { 099 return ClassUtils.isAssignableValue(type, returnValue); 100 } 101 else if (Object.class == type && void.class == method.getReturnType()) { 102 return true; 103 } 104 else { 105 return ClassUtils.isAssignable(type, method.getReturnType()); 106 } 107 } 108 109}