001/* 002 * Copyright 2002-2012 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.support; 018 019import org.aopalliance.intercept.MethodInvocation; 020 021import org.springframework.aop.DynamicIntroductionAdvice; 022import org.springframework.aop.IntroductionInterceptor; 023import org.springframework.aop.ProxyMethodInvocation; 024import org.springframework.util.Assert; 025 026/** 027 * Convenient implementation of the 028 * {@link org.springframework.aop.IntroductionInterceptor} interface. 029 * 030 * <p>Subclasses merely need to extend this class and implement the interfaces 031 * to be introduced themselves. In this case the delegate is the subclass 032 * instance itself. Alternatively a separate delegate may implement the 033 * interface, and be set via the delegate bean property. 034 * 035 * <p>Delegates or subclasses may implement any number of interfaces. 036 * All interfaces except IntroductionInterceptor are picked up from 037 * the subclass or delegate by default. 038 * 039 * <p>The {@code suppressInterface} method can be used to suppress interfaces 040 * implemented by the delegate but which should not be introduced to the owning 041 * AOP proxy. 042 * 043 * <p>An instance of this class is serializable if the delegate is. 044 * 045 * @author Rod Johnson 046 * @author Juergen Hoeller 047 * @since 16.11.2003 048 * @see #suppressInterface 049 * @see DelegatePerTargetObjectIntroductionInterceptor 050 */ 051@SuppressWarnings("serial") 052public class DelegatingIntroductionInterceptor extends IntroductionInfoSupport 053 implements IntroductionInterceptor { 054 055 /** 056 * Object that actually implements the interfaces. 057 * May be "this" if a subclass implements the introduced interfaces. 058 */ 059 private Object delegate; 060 061 062 /** 063 * Construct a new DelegatingIntroductionInterceptor, providing 064 * a delegate that implements the interfaces to be introduced. 065 * @param delegate the delegate that implements the introduced interfaces 066 */ 067 public DelegatingIntroductionInterceptor(Object delegate) { 068 init(delegate); 069 } 070 071 /** 072 * Construct a new DelegatingIntroductionInterceptor. 073 * The delegate will be the subclass, which must implement 074 * additional interfaces. 075 */ 076 protected DelegatingIntroductionInterceptor() { 077 init(this); 078 } 079 080 081 /** 082 * Both constructors use this init method, as it is impossible to pass 083 * a "this" reference from one constructor to another. 084 * @param delegate the delegate object 085 */ 086 private void init(Object delegate) { 087 Assert.notNull(delegate, "Delegate must not be null"); 088 this.delegate = delegate; 089 implementInterfacesOnObject(delegate); 090 091 // We don't want to expose the control interface 092 suppressInterface(IntroductionInterceptor.class); 093 suppressInterface(DynamicIntroductionAdvice.class); 094 } 095 096 097 /** 098 * Subclasses may need to override this if they want to perform custom 099 * behaviour in around advice. However, subclasses should invoke this 100 * method, which handles introduced interfaces and forwarding to the target. 101 */ 102 @Override 103 public Object invoke(MethodInvocation mi) throws Throwable { 104 if (isMethodOnIntroducedInterface(mi)) { 105 // Using the following method rather than direct reflection, we 106 // get correct handling of InvocationTargetException 107 // if the introduced method throws an exception. 108 Object retVal = AopUtils.invokeJoinpointUsingReflection(this.delegate, mi.getMethod(), mi.getArguments()); 109 110 // Massage return value if possible: if the delegate returned itself, 111 // we really want to return the proxy. 112 if (retVal == this.delegate && mi instanceof ProxyMethodInvocation) { 113 Object proxy = ((ProxyMethodInvocation) mi).getProxy(); 114 if (mi.getMethod().getReturnType().isInstance(proxy)) { 115 retVal = proxy; 116 } 117 } 118 return retVal; 119 } 120 121 return doProceed(mi); 122 } 123 124 /** 125 * Proceed with the supplied {@link org.aopalliance.intercept.MethodInterceptor}. 126 * Subclasses can override this method to intercept method invocations on the 127 * target object which is useful when an introduction needs to monitor the object 128 * that it is introduced into. This method is <strong>never</strong> called for 129 * {@link MethodInvocation MethodInvocations} on the introduced interfaces. 130 */ 131 protected Object doProceed(MethodInvocation mi) throws Throwable { 132 // If we get here, just pass the invocation on. 133 return mi.proceed(); 134 } 135 136}