• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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 package dagger.internal.codegen;
17 
18 import com.google.auto.common.MoreElements;
19 import com.google.auto.common.MoreTypes;
20 import com.google.auto.value.AutoValue;
21 import com.google.common.base.Function;
22 import com.google.common.base.Optional;
23 import com.google.common.collect.FluentIterable;
24 import com.google.common.collect.ImmutableSet;
25 import com.google.common.collect.Iterables;
26 import com.google.common.util.concurrent.ListenableFuture;
27 import dagger.Lazy;
28 import dagger.MembersInjector;
29 import dagger.Provides;
30 import dagger.producers.Produced;
31 import dagger.producers.Producer;
32 import dagger.producers.internal.AbstractProducer;
33 import java.util.List;
34 import javax.inject.Inject;
35 import javax.inject.Provider;
36 import javax.lang.model.element.AnnotationMirror;
37 import javax.lang.model.element.Element;
38 import javax.lang.model.element.ExecutableElement;
39 import javax.lang.model.element.TypeElement;
40 import javax.lang.model.element.VariableElement;
41 import javax.lang.model.type.DeclaredType;
42 import javax.lang.model.type.ExecutableType;
43 import javax.lang.model.type.TypeKind;
44 import javax.lang.model.type.TypeMirror;
45 import javax.lang.model.util.Elements;
46 
47 import static com.google.auto.common.MoreTypes.isTypeOf;
48 import static com.google.common.base.Preconditions.checkArgument;
49 import static com.google.common.base.Preconditions.checkNotNull;
50 import static com.google.common.base.Preconditions.checkState;
51 import static javax.lang.model.type.TypeKind.DECLARED;
52 import static javax.lang.model.util.ElementFilter.constructorsIn;
53 
54 /**
55  * Represents a request for a key at an injection point. Parameters to {@link Inject} constructors
56  * or {@link Provides} methods are examples of key requests.
57  *
58  * @author Gregory Kick
59  * @since 2.0
60  */
61 // TODO(gak): Set bindings and the permutations thereof need to be addressed
62 @AutoValue
63 abstract class DependencyRequest {
64   static final Function<DependencyRequest, BindingKey> BINDING_KEY_FUNCTION =
65       new Function<DependencyRequest, BindingKey>() {
66         @Override public BindingKey apply(DependencyRequest request) {
67           return request.bindingKey();
68         }
69       };
70 
71   enum Kind {
72     /** A default request for an instance.  E.g.: {@code Blah} */
73     INSTANCE,
74     /** A request for a {@link Provider}.  E.g.: {@code Provider<Blah>} */
75     PROVIDER,
76     /** A request for a {@link Lazy}.  E.g.: {@code Lazy<Blah>} */
77     LAZY,
78     /** A request for a {@link MembersInjector}.  E.g.: {@code MembersInjector<Blah>} */
79     MEMBERS_INJECTOR,
80     /** A request for a {@link Producer}.  E.g.: {@code Producer<Blah>} */
81     PRODUCER,
82     /** A request for a {@link Produced}.  E.g.: {@code Produced<Blah>} */
83     PRODUCED,
84     /**
85      * A request for a {@link ListenableFuture}.  E.g.: {@code ListenableFuture<Blah>}.
86      * These can only be requested by component interfaces.
87      */
88     FUTURE,
89   }
90 
kind()91   abstract Kind kind();
key()92   abstract Key key();
93 
bindingKey()94   BindingKey bindingKey() {
95     switch (kind()) {
96       case INSTANCE:
97       case LAZY:
98       case PROVIDER:
99       case PRODUCER:
100       case PRODUCED:
101       case FUTURE:
102         return BindingKey.create(BindingKey.Kind.CONTRIBUTION, key());
103       case MEMBERS_INJECTOR:
104         return BindingKey.create(BindingKey.Kind.MEMBERS_INJECTION, key());
105       default:
106         throw new AssertionError();
107     }
108   }
109 
requestElement()110   abstract Element requestElement();
111 
112   /**
113    * Returns the possibly resolved type that contained the requesting element. For members injection
114    * requests, this is the type itself.
115    */
enclosingType()116   abstract DeclaredType enclosingType();
117 
118   /** Returns true if this request allows null objects. */
isNullable()119   abstract boolean isNullable();
120 
121   /**
122    * An optional name for this request when it's referred to in generated code. If absent, it will
123    * use a name derived from {@link #requestElement}.
124    */
overriddenVariableName()125   abstract Optional<String> overriddenVariableName();
126 
127   /**
128    * Factory for {@link DependencyRequest}s.
129    *
130    * <p>Any factory method may throw {@link TypeNotPresentException} if a type is not available,
131    * which may mean that the type will be generated in a later round of processing.
132    */
133   static final class Factory {
134     private final Elements elements;
135     private final Key.Factory keyFactory;
136 
Factory(Elements elements, Key.Factory keyFactory)137     Factory(Elements elements, Key.Factory keyFactory) {
138       this.elements = elements;
139       this.keyFactory = keyFactory;
140     }
141 
forRequiredResolvedVariables(DeclaredType container, List<? extends VariableElement> variables, List<? extends TypeMirror> resolvedTypes)142     ImmutableSet<DependencyRequest> forRequiredResolvedVariables(DeclaredType container,
143         List<? extends VariableElement> variables, List<? extends TypeMirror> resolvedTypes) {
144       checkState(resolvedTypes.size() == variables.size());
145       ImmutableSet.Builder<DependencyRequest> builder = ImmutableSet.builder();
146       for (int i = 0; i < variables.size(); i++) {
147         builder.add(forRequiredResolvedVariable(container, variables.get(i), resolvedTypes.get(i)));
148       }
149       return builder.build();
150     }
151 
forRequiredVariables( List<? extends VariableElement> variables)152     ImmutableSet<DependencyRequest> forRequiredVariables(
153         List<? extends VariableElement> variables) {
154       return FluentIterable.from(variables)
155           .transform(
156               new Function<VariableElement, DependencyRequest>() {
157                 @Override
158                 public DependencyRequest apply(VariableElement input) {
159                   return forRequiredVariable(input);
160                 }
161               })
162           .toSet();
163     }
164 
165     /**
166      * Creates a implicit {@link DependencyRequest} for {@code mapOfFactoryKey}, which will be used
167      * to satisfy the {@code mapOfValueRequest}.
168      *
169      * @param mapOfValueRequest a request for {@code Map<K, V>}
170      * @param mapOfFactoryKey a key equivalent to {@code mapOfValueRequest}'s key, whose type is
171      *     {@code Map<K, Provider<V>>} or {@code Map<K, Producer<V>>}
172      */
forImplicitMapBinding( DependencyRequest mapOfValueRequest, Key mapOfFactoryKey)173     DependencyRequest forImplicitMapBinding(
174         DependencyRequest mapOfValueRequest, Key mapOfFactoryKey) {
175       checkNotNull(mapOfValueRequest);
176       return new AutoValue_DependencyRequest(
177           Kind.PROVIDER,
178           mapOfFactoryKey,
179           mapOfValueRequest.requestElement(),
180           mapOfValueRequest.enclosingType(),
181           false /* doesn't allow null */,
182           Optional.<String>absent());
183     }
184 
forRequiredVariable(VariableElement variableElement)185     DependencyRequest forRequiredVariable(VariableElement variableElement) {
186       return forRequiredVariable(variableElement, Optional.<String>absent());
187     }
188 
forRequiredVariable(VariableElement variableElement, Optional<String> name)189     DependencyRequest forRequiredVariable(VariableElement variableElement, Optional<String> name) {
190       checkNotNull(variableElement);
191       TypeMirror type = variableElement.asType();
192       Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(variableElement);
193       return newDependencyRequest(
194           variableElement, type, qualifier, getEnclosingType(variableElement), name);
195     }
196 
forRequiredResolvedVariable(DeclaredType container, VariableElement variableElement, TypeMirror resolvedType)197     DependencyRequest forRequiredResolvedVariable(DeclaredType container,
198         VariableElement variableElement,
199         TypeMirror resolvedType) {
200       checkNotNull(variableElement);
201       checkNotNull(resolvedType);
202       Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(variableElement);
203       return newDependencyRequest(
204           variableElement, resolvedType, qualifier, container, Optional.<String>absent());
205     }
206 
forComponentProvisionMethod(ExecutableElement provisionMethod, ExecutableType provisionMethodType)207     DependencyRequest forComponentProvisionMethod(ExecutableElement provisionMethod,
208         ExecutableType provisionMethodType) {
209       checkNotNull(provisionMethod);
210       checkNotNull(provisionMethodType);
211       checkArgument(
212           provisionMethod.getParameters().isEmpty(),
213           "Component provision methods must be empty: %s",
214           provisionMethod);
215       Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(provisionMethod);
216       return newDependencyRequest(
217           provisionMethod,
218           provisionMethodType.getReturnType(),
219           qualifier,
220           getEnclosingType(provisionMethod),
221           Optional.<String>absent());
222     }
223 
forComponentProductionMethod(ExecutableElement productionMethod, ExecutableType productionMethodType)224     DependencyRequest forComponentProductionMethod(ExecutableElement productionMethod,
225         ExecutableType productionMethodType) {
226       checkNotNull(productionMethod);
227       checkNotNull(productionMethodType);
228       checkArgument(productionMethod.getParameters().isEmpty(),
229           "Component production methods must be empty: %s", productionMethod);
230       TypeMirror type = productionMethodType.getReturnType();
231       Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(productionMethod);
232       DeclaredType container = getEnclosingType(productionMethod);
233       // Only a component production method can be a request for a ListenableFuture, so we
234       // special-case it here.
235       if (isTypeOf(ListenableFuture.class, type)) {
236         return new AutoValue_DependencyRequest(
237             Kind.FUTURE,
238             keyFactory.forQualifiedType(
239                 qualifier, Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments())),
240             productionMethod,
241             container,
242             false /* doesn't allow null */,
243             Optional.<String>absent());
244       } else {
245         return newDependencyRequest(
246             productionMethod, type, qualifier, container, Optional.<String>absent());
247       }
248     }
249 
forComponentMembersInjectionMethod(ExecutableElement membersInjectionMethod, ExecutableType membersInjectionMethodType)250     DependencyRequest forComponentMembersInjectionMethod(ExecutableElement membersInjectionMethod,
251         ExecutableType membersInjectionMethodType) {
252       checkNotNull(membersInjectionMethod);
253       checkNotNull(membersInjectionMethodType);
254       Optional<AnnotationMirror> qualifier =
255           InjectionAnnotations.getQualifier(membersInjectionMethod);
256       checkArgument(!qualifier.isPresent());
257       TypeMirror returnType = membersInjectionMethodType.getReturnType();
258       if (returnType.getKind().equals(DECLARED)
259           && MoreTypes.isTypeOf(MembersInjector.class, returnType)) {
260         return new AutoValue_DependencyRequest(
261             Kind.MEMBERS_INJECTOR,
262             keyFactory.forMembersInjectedType(
263                 Iterables.getOnlyElement(((DeclaredType) returnType).getTypeArguments())),
264             membersInjectionMethod,
265             getEnclosingType(membersInjectionMethod),
266             false /* doesn't allow null */,
267             Optional.<String>absent());
268       } else {
269         return new AutoValue_DependencyRequest(
270             Kind.MEMBERS_INJECTOR,
271             keyFactory.forMembersInjectedType(
272                 Iterables.getOnlyElement(membersInjectionMethodType.getParameterTypes())),
273             membersInjectionMethod,
274             getEnclosingType(membersInjectionMethod),
275             false /* doesn't allow null */,
276             Optional.<String>absent());
277       }
278     }
279 
forMembersInjectedType(DeclaredType type)280     DependencyRequest forMembersInjectedType(DeclaredType type) {
281       return new AutoValue_DependencyRequest(
282           Kind.MEMBERS_INJECTOR,
283           keyFactory.forMembersInjectedType(type),
284           type.asElement(),
285           type,
286           false /* doesn't allow null */,
287           Optional.<String>absent());
288     }
289 
forProductionComponentMonitorProvider()290     DependencyRequest forProductionComponentMonitorProvider() {
291       TypeElement element = elements.getTypeElement(AbstractProducer.class.getCanonicalName());
292       for (ExecutableElement constructor : constructorsIn(element.getEnclosedElements())) {
293         if (constructor.getParameters().size() == 2) {
294           // the 2-arg constructor has the appropriate dependency as its first arg
295           return forRequiredVariable(constructor.getParameters().get(0), Optional.of("monitor"));
296         }
297       }
298       throw new AssertionError("expected 2-arg constructor in AbstractProducer");
299     }
300 
newDependencyRequest( Element requestElement, TypeMirror type, Optional<AnnotationMirror> qualifier, DeclaredType container, Optional<String> name)301     private DependencyRequest newDependencyRequest(
302         Element requestElement,
303         TypeMirror type,
304         Optional<AnnotationMirror> qualifier,
305         DeclaredType container,
306         Optional<String> name) {
307       KindAndType kindAndType = extractKindAndType(type);
308       if (kindAndType.kind().equals(Kind.MEMBERS_INJECTOR)) {
309         checkArgument(!qualifier.isPresent());
310       }
311       // Only instance types can be non-null -- all other requests are wrapped
312       // inside something (e.g, Provider, Lazy, etc..).
313       // TODO(sameb): should Produced/Producer always require non-nullable?
314       boolean allowsNull = !kindAndType.kind().equals(Kind.INSTANCE)
315           || ConfigurationAnnotations.getNullableType(requestElement).isPresent();
316       return new AutoValue_DependencyRequest(
317           kindAndType.kind(),
318           keyFactory.forQualifiedType(qualifier, kindAndType.type()),
319           requestElement,
320           container,
321           allowsNull,
322           name);
323     }
324 
325     @AutoValue
326     static abstract class KindAndType {
kind()327       abstract Kind kind();
type()328       abstract TypeMirror type();
329     }
330 
331     /**
332      * Extracts the correct requesting type & kind out a request type. For example, if a user
333      * requests {@code Provider<Foo>}, this will return ({@link Kind#PROVIDER}, {@code Foo}).
334      *
335      * @throws TypeNotPresentException if {@code type}'s kind is {@link TypeKind#ERROR}, which may
336      *     mean that the type will be generated in a later round of processing
337      */
extractKindAndType(TypeMirror type)338     static KindAndType extractKindAndType(TypeMirror type) {
339       if (type.getKind().equals(TypeKind.ERROR)) {
340         throw new TypeNotPresentException(type.toString(), null);
341       }
342 
343       // We must check TYPEVAR explicitly before the below checks because calling
344       // isTypeOf(..) on a TYPEVAR throws an exception (because it can't be
345       // represented as a Class).
346       if (type.getKind().equals(TypeKind.TYPEVAR)) {
347         return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.INSTANCE, type);
348       } else if (isTypeOf(Provider.class, type)) {
349         return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.PROVIDER,
350             Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments()));
351       } else if (isTypeOf(Lazy.class, type)) {
352         return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.LAZY,
353             Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments()));
354       } else if (isTypeOf(MembersInjector.class, type)) {
355         return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.MEMBERS_INJECTOR,
356             Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments()));
357       } else if (isTypeOf(Producer.class, type)) {
358         return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.PRODUCER,
359             Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments()));
360       } else if (isTypeOf(Produced.class, type)) {
361         return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.PRODUCED,
362             Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments()));
363       } else {
364         return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.INSTANCE, type);
365       }
366     }
367 
getEnclosingType(Element element)368     static DeclaredType getEnclosingType(Element element) {
369       while (!MoreElements.isType(element)) {
370         element = element.getEnclosingElement();
371       }
372       return MoreTypes.asDeclared(element.asType());
373     }
374   }
375 }
376