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