1 16 17 package com.google.inject; 18 19 import com.google.inject.util.GuiceFastClass; 20 import com.google.inject.util.GuiceNamingPolicy; 21 import com.google.inject.util.Objects; 22 import com.google.inject.util.ReferenceCache; 23 import java.lang.reflect.Constructor ; 24 import java.lang.reflect.InvocationTargetException ; 25 import java.lang.reflect.Method ; 26 import java.util.ArrayList ; 27 import java.util.HashMap ; 28 import java.util.List ; 29 import java.util.Map ; 30 import net.sf.cglib.proxy.Callback; 31 import net.sf.cglib.proxy.CallbackFilter; 32 import net.sf.cglib.proxy.Enhancer; 33 import net.sf.cglib.proxy.NoOp; 34 import net.sf.cglib.reflect.FastClass; 35 import net.sf.cglib.reflect.FastConstructor; 36 import org.aopalliance.intercept.MethodInterceptor; 37 38 44 class ProxyFactory implements ConstructionProxyFactory { 45 46 final List <MethodAspect> methodAspects; 47 final ConstructionProxyFactory defaultFactory 48 = new DefaultConstructionProxyFactory(); 49 50 ProxyFactory(List <MethodAspect> methodAspects) { 51 this.methodAspects = methodAspects; 52 } 53 54 Map <Constructor <?>, ConstructionProxy<?>> constructionProxies 55 = new ReferenceCache<Constructor <?>, ConstructionProxy<?>>() { 56 protected ConstructionProxy<?> create(Constructor <?> constructor) { 57 return createConstructionProxy(constructor); 58 } 59 }; 60 61 66 public <T> Provider<T> getFactory(Class <T> type) throws NoSuchMethodException { 67 final ConstructionProxy<T> constructionProxy 68 = createConstructionProxy(type.getDeclaredConstructor()); 69 return new Provider<T>() { 70 public T get() { 71 try { 72 return constructionProxy.newInstance(); 73 } 74 catch (InvocationTargetException e) { 75 throw new RuntimeException (e); 76 } 77 } 78 }; 79 } 80 81 <T> ConstructionProxy<T> createConstructionProxy(Constructor <T> constructor) { 82 Class <T> declaringClass = constructor.getDeclaringClass(); 83 84 List <MethodAspect> applicableAspects = new ArrayList <MethodAspect>(); 86 for (MethodAspect methodAspect : methodAspects) { 87 if (methodAspect.matches(declaringClass)) { 88 applicableAspects.add(methodAspect); 89 } 90 } 91 if (applicableAspects.isEmpty()) { 92 return defaultFactory.get(constructor); 93 } 94 95 List <Method > methods = new ArrayList <Method >(); 97 Enhancer.getMethods(declaringClass, null, methods); 98 final Map <Method , Integer > indices = new HashMap <Method , Integer >(); 99 100 List <MethodInterceptorsPair> methodInterceptorsPairs 102 = new ArrayList <MethodInterceptorsPair>(); 103 for (int i = 0; i < methods.size(); i++) { 104 Method method = methods.get(i); 105 methodInterceptorsPairs.add(new MethodInterceptorsPair(method)); 106 indices.put(method, i); 107 } 108 109 boolean anyMatched = false; 111 for (MethodAspect methodAspect : applicableAspects) { 112 for (MethodInterceptorsPair pair : methodInterceptorsPairs) { 113 if (methodAspect.matches(pair.method)) { 114 pair.addAll(methodAspect.interceptors()); 115 anyMatched = true; 116 } 117 } 118 } 119 if (!anyMatched) { 120 return defaultFactory.get(constructor); 122 } 123 124 Callback[] callbacks = new Callback[methods.size()]; 126 127 @SuppressWarnings ("unchecked") 128 Class <? extends Callback>[] callbackTypes = new Class [methods.size()]; 129 for (int i = 0; i < methods.size(); i++) { 130 MethodInterceptorsPair pair = methodInterceptorsPairs.get(i); 131 if (!pair.hasInterceptors()) { 132 callbacks[i] = NoOp.INSTANCE; 133 callbackTypes[i] = NoOp.class; 134 } 135 else { 136 callbacks[i] = new InterceptorStackCallback( 137 pair.method, pair.interceptors); 138 callbackTypes[i] = net.sf.cglib.proxy.MethodInterceptor.class; 139 } 140 } 141 142 Enhancer enhancer = new Enhancer(); 144 enhancer.setSuperclass(declaringClass); 145 enhancer.setUseCache(false); enhancer.setCallbackFilter(new CallbackFilter() { 147 public int accept(Method method) { 148 return indices.get(method); 149 } 150 }); 151 enhancer.setCallbackTypes(callbackTypes); 152 enhancer.setUseFactory(false); 153 enhancer.setNamingPolicy(new GuiceNamingPolicy()); 154 155 Class <?> proxied = enhancer.createClass(); 156 157 Enhancer.registerStaticCallbacks(proxied, callbacks); 159 160 return createConstructionProxy(proxied, constructor.getParameterTypes()); 161 } 162 163 166 <T> ConstructionProxy<T> createConstructionProxy(Class <?> clazz, 167 Class [] parameterTypes) { 168 FastClass fastClass = GuiceFastClass.create(clazz); 169 final FastConstructor fastConstructor 170 = fastClass.getConstructor(parameterTypes); 171 return new ConstructionProxy<T>() { 172 @SuppressWarnings ("unchecked") 173 public T newInstance(Object ... arguments) 174 throws InvocationTargetException { 175 Objects.assertNoNulls(arguments); 176 return (T) fastConstructor.newInstance(arguments); 177 } 178 }; 179 } 180 181 static class MethodInterceptorsPair { 182 183 final Method method; 184 List <MethodInterceptor> interceptors; 185 186 public MethodInterceptorsPair(Method method) { 187 this.method = method; 188 } 189 190 void addAll(List <MethodInterceptor> interceptors) { 191 if (this.interceptors == null) { 192 this.interceptors = new ArrayList <MethodInterceptor>(); 193 } 194 this.interceptors.addAll(interceptors); 195 } 196 197 boolean hasInterceptors() { 198 return interceptors != null; 199 } 200 } 201 202 @SuppressWarnings ("unchecked") 203 public <T> ConstructionProxy<T> get(Constructor <T> constructor) { 204 return (ConstructionProxy<T>) constructionProxies.get(constructor); 205 } 206 } 207 | Popular Tags |