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