1 /** 2 * Copyright (C) 2006 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.inject.internal; 18 19 import com.google.common.collect.Lists; 20 21 import net.sf.cglib.proxy.MethodProxy; 22 23 import org.aopalliance.intercept.MethodInterceptor; 24 import org.aopalliance.intercept.MethodInvocation; 25 26 import java.lang.reflect.AccessibleObject; 27 import java.lang.reflect.Method; 28 import java.util.Arrays; 29 import java.util.HashSet; 30 import java.util.List; 31 import java.util.Set; 32 33 /** 34 * Intercepts a method with a stack of interceptors. 35 * 36 * @author crazybob@google.com (Bob Lee) 37 */ 38 final class InterceptorStackCallback implements net.sf.cglib.proxy.MethodInterceptor { 39 private static final Set<String> AOP_INTERNAL_CLASSES = new HashSet<String>(Arrays.asList( 40 InterceptorStackCallback.class.getName(), 41 InterceptedMethodInvocation.class.getName(), 42 MethodProxy.class.getName())); 43 44 final MethodInterceptor[] interceptors; 45 final Method method; 46 InterceptorStackCallback(Method method, List<MethodInterceptor> interceptors)47 public InterceptorStackCallback(Method method, 48 List<MethodInterceptor> interceptors) { 49 this.method = method; 50 this.interceptors = interceptors.toArray(new MethodInterceptor[interceptors.size()]); 51 } 52 intercept(Object proxy, Method method, Object[] arguments, MethodProxy methodProxy)53 public Object intercept(Object proxy, Method method, Object[] arguments, 54 MethodProxy methodProxy) throws Throwable { 55 return new InterceptedMethodInvocation(proxy, methodProxy, arguments, 0).proceed(); 56 } 57 58 private class InterceptedMethodInvocation implements MethodInvocation { 59 60 final Object proxy; 61 final Object[] arguments; 62 final MethodProxy methodProxy; 63 final int index; 64 InterceptedMethodInvocation(Object proxy, MethodProxy methodProxy, Object[] arguments, int index)65 public InterceptedMethodInvocation(Object proxy, MethodProxy methodProxy, 66 Object[] arguments, int index) { 67 this.proxy = proxy; 68 this.methodProxy = methodProxy; 69 this.arguments = arguments; 70 this.index = index; 71 } 72 proceed()73 public Object proceed() throws Throwable { 74 try { 75 return index == interceptors.length 76 ? methodProxy.invokeSuper(proxy, arguments) 77 : interceptors[index].invoke( 78 new InterceptedMethodInvocation(proxy, methodProxy, arguments, index + 1)); 79 } catch (Throwable t) { 80 pruneStacktrace(t); 81 throw t; 82 } 83 } 84 getMethod()85 public Method getMethod() { 86 return method; 87 } 88 getArguments()89 public Object[] getArguments() { 90 return arguments; 91 } 92 getThis()93 public Object getThis() { 94 return proxy; 95 } 96 getStaticPart()97 public AccessibleObject getStaticPart() { 98 return getMethod(); 99 } 100 } 101 102 /** 103 * Removes stacktrace elements related to AOP internal mechanics from the 104 * throwable's stack trace and any causes it may have. 105 */ pruneStacktrace(Throwable throwable)106 private void pruneStacktrace(Throwable throwable) { 107 for(Throwable t = throwable; t != null; t = t.getCause()) { 108 StackTraceElement[] stackTrace = t.getStackTrace(); 109 List<StackTraceElement> pruned = Lists.newArrayList(); 110 for (StackTraceElement element : stackTrace) { 111 String className = element.getClassName(); 112 if (!AOP_INTERNAL_CLASSES.contains(className) && !className.contains("$EnhancerByGuice$")) { 113 pruned.add(element); 114 } 115 } 116 t.setStackTrace(pruned.toArray(new StackTraceElement[pruned.size()])); 117 } 118 } 119 } 120