1 /**
2  * Copyright (C) 2008 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.inject.internal.BytecodeGen.Visibility;
20 import com.google.inject.internal.InjectorImpl.MethodInvoker;
21 import com.google.inject.spi.InjectionPoint;
22 
23 import java.lang.reflect.InvocationTargetException;
24 import java.lang.reflect.Method;
25 import java.lang.reflect.Modifier;
26 
27 /**
28  * Invokes an injectable method.
29  */
30 final class SingleMethodInjector implements SingleMemberInjector {
31   private final MethodInvoker methodInvoker;
32   private final SingleParameterInjector<?>[] parameterInjectors;
33   private final InjectionPoint injectionPoint;
34 
SingleMethodInjector(InjectorImpl injector, InjectionPoint injectionPoint, Errors errors)35   SingleMethodInjector(InjectorImpl injector, InjectionPoint injectionPoint, Errors errors)
36       throws ErrorsException {
37     this.injectionPoint = injectionPoint;
38     final Method method = (Method) injectionPoint.getMember();
39     methodInvoker = createMethodInvoker(method);
40     parameterInjectors = injector.getParametersInjectors(injectionPoint.getDependencies(), errors);
41   }
42 
createMethodInvoker(final Method method)43   private MethodInvoker createMethodInvoker(final Method method) {
44 
45     // We can't use FastMethod if the method is private.
46     int modifiers = method.getModifiers();
47     if (!Modifier.isPrivate(modifiers) && !Modifier.isProtected(modifiers)) {
48       /*if[AOP]*/
49       try {
50       final net.sf.cglib.reflect.FastMethod fastMethod
51           = BytecodeGen.newFastClass(method.getDeclaringClass(), Visibility.forMember(method))
52               .getMethod(method);
53 
54       return new MethodInvoker() {
55         public Object invoke(Object target, Object... parameters)
56             throws IllegalAccessException, InvocationTargetException {
57           return fastMethod.invoke(target, parameters);
58         }
59       };
60       } catch (net.sf.cglib.core.CodeGenerationException e) {/* fall-through */}
61       /*end[AOP]*/
62     }
63 
64     if (!Modifier.isPublic(modifiers) ||
65         !Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
66       method.setAccessible(true);
67     }
68 
69     return new MethodInvoker() {
70       public Object invoke(Object target, Object... parameters)
71           throws IllegalAccessException, InvocationTargetException {
72         return method.invoke(target, parameters);
73       }
74     };
75   }
76 
77   public InjectionPoint getInjectionPoint() {
78     return injectionPoint;
79   }
80 
81   public void inject(Errors errors, InternalContext context, Object o) {
82     Object[] parameters;
83     try {
84       parameters = SingleParameterInjector.getAll(errors, context, parameterInjectors);
85     } catch (ErrorsException e) {
86       errors.merge(e.getErrors());
87       return;
88     }
89 
90     try {
91       methodInvoker.invoke(o, parameters);
92     } catch (IllegalAccessException e) {
93       throw new AssertionError(e); // a security manager is blocking us, we're hosed
94     } catch (InvocationTargetException userException) {
95       Throwable cause = userException.getCause() != null
96           ? userException.getCause()
97           : userException;
98       errors.withSource(injectionPoint).errorInjectingMethod(cause);
99     }
100   }
101 }
102