• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.throwingproviders;
18 
19 import com.google.common.collect.ImmutableSet;
20 import com.google.inject.Binder;
21 import com.google.inject.Exposed;
22 import com.google.inject.Key;
23 import com.google.inject.PrivateBinder;
24 import com.google.inject.Provider;
25 import com.google.inject.TypeLiteral;
26 import com.google.inject.binder.ScopedBindingBuilder;
27 import com.google.inject.internal.util.StackTraceElements;
28 import com.google.inject.spi.Dependency;
29 import com.google.inject.spi.HasDependencies;
30 import com.google.inject.throwingproviders.ThrowingProviderBinder.SecondaryBinder;
31 import java.lang.annotation.Annotation;
32 import java.lang.reflect.InvocationTargetException;
33 import java.lang.reflect.Method;
34 import java.util.List;
35 import java.util.Set;
36 
37 /**
38  * A provider that invokes a method and returns its result.
39  *
40  * @author sameb@google.com (Sam Berlin)
41  */
42 class CheckedProviderMethod<T> implements CheckedProvider<T>, HasDependencies {
43   private final Key<T> key;
44   private final Class<? extends Annotation> scopeAnnotation;
45   private final Object instance;
46   private final Method method;
47   private final ImmutableSet<Dependency<?>> dependencies;
48   private final List<Provider<?>> parameterProviders;
49   private final boolean exposed;
50   private final Class<? extends CheckedProvider> checkedProvider;
51   private final List<TypeLiteral<?>> exceptionTypes;
52   private final boolean scopeExceptions;
53 
CheckedProviderMethod( Key<T> key, Method method, Object instance, ImmutableSet<Dependency<?>> dependencies, List<Provider<?>> parameterProviders, Class<? extends Annotation> scopeAnnotation, Class<? extends CheckedProvider> checkedProvider, List<TypeLiteral<?>> exceptionTypes, boolean scopeExceptions)54   CheckedProviderMethod(
55       Key<T> key,
56       Method method,
57       Object instance,
58       ImmutableSet<Dependency<?>> dependencies,
59       List<Provider<?>> parameterProviders,
60       Class<? extends Annotation> scopeAnnotation,
61       Class<? extends CheckedProvider> checkedProvider,
62       List<TypeLiteral<?>> exceptionTypes,
63       boolean scopeExceptions) {
64     this.key = key;
65     this.scopeAnnotation = scopeAnnotation;
66     this.instance = instance;
67     this.dependencies = dependencies;
68     this.method = method;
69     this.parameterProviders = parameterProviders;
70     this.exposed = method.isAnnotationPresent(Exposed.class);
71     this.checkedProvider = checkedProvider;
72     this.exceptionTypes = exceptionTypes;
73     this.scopeExceptions = scopeExceptions;
74 
75     method.setAccessible(true);
76   }
77 
configure(Binder binder)78   void configure(Binder binder) {
79     binder = binder.withSource(method);
80 
81     SecondaryBinder<?, ?> sbinder =
82         ThrowingProviderBinder.create(binder).bind(checkedProvider, key.getTypeLiteral());
83     if (key.getAnnotation() != null) {
84       sbinder = sbinder.annotatedWith(key.getAnnotation());
85     } else if (key.getAnnotationType() != null) {
86       sbinder = sbinder.annotatedWith(key.getAnnotationType());
87     }
88     sbinder.scopeExceptions(scopeExceptions);
89     ScopedBindingBuilder sbbuilder = sbinder.toProviderMethod(this);
90     if (scopeAnnotation != null) {
91       sbbuilder.in(scopeAnnotation);
92     }
93 
94     if (exposed) {
95       // the cast is safe 'cause the only binder we have implements PrivateBinder. If there's a
96       // misplaced @Exposed, calling this will add an error to the binder's error queue
97       ((PrivateBinder) binder).expose(sbinder.getKey());
98     }
99 
100     CheckedProvideUtils.validateExceptions(
101         binder, exceptionTypes, sbinder.getExceptionTypes(), checkedProvider);
102   }
103 
104   @Override
get()105   public T get() throws Exception {
106     Object[] parameters = new Object[parameterProviders.size()];
107     for (int i = 0; i < parameters.length; i++) {
108       parameters[i] = parameterProviders.get(i).get();
109     }
110 
111     try {
112       // We know this cast is safe becase T is the method's return type.
113       @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
114       T result = (T) method.invoke(instance, parameters);
115       return result;
116     } catch (IllegalAccessException e) {
117       throw new AssertionError(e);
118     } catch (InvocationTargetException e) {
119       Throwable t = e.getCause();
120       if (t instanceof Exception) {
121         throw (Exception) t;
122       } else if (t instanceof Error) {
123         throw (Error) t;
124       } else {
125         throw new IllegalStateException(t);
126       }
127     }
128   }
129 
130   @Override
getDependencies()131   public Set<Dependency<?>> getDependencies() {
132     return dependencies;
133   }
134 
135   @Override
toString()136   public String toString() {
137     return "@CheckedProvides " + StackTraceElements.forMember(method);
138   }
139 }
140