• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Dagger Authors.
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 dagger.internal.codegen.binding;
18 
19 import static com.google.common.base.CaseFormat.UPPER_CAMEL;
20 import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
21 import static dagger.model.RequestKind.INSTANCE;
22 
23 import com.google.common.util.concurrent.Futures;
24 import com.google.common.util.concurrent.ListenableFuture;
25 import com.squareup.javapoet.ClassName;
26 import com.squareup.javapoet.CodeBlock;
27 import com.squareup.javapoet.ParameterizedTypeName;
28 import com.squareup.javapoet.TypeName;
29 import dagger.Lazy;
30 import dagger.internal.DoubleCheck;
31 import dagger.internal.ProviderOfLazy;
32 import dagger.internal.codegen.base.RequestKinds;
33 import dagger.internal.codegen.javapoet.Expression;
34 import dagger.internal.codegen.langmodel.DaggerTypes;
35 import dagger.model.DependencyRequest;
36 import dagger.model.RequestKind;
37 import dagger.producers.Produced;
38 import dagger.producers.Producer;
39 import dagger.producers.internal.Producers;
40 import java.util.Optional;
41 import javax.inject.Provider;
42 import javax.lang.model.type.TypeMirror;
43 
44 /** One of the core types initialized as fields in a generated component. */
45 public enum FrameworkType {
46   /** A {@link Provider}. */
47   PROVIDER {
48     @Override
frameworkClass()49     public Class<?> frameworkClass() {
50       return Provider.class;
51     }
52 
53     @Override
requestKind()54     public Optional<RequestKind> requestKind() {
55       return Optional.of(RequestKind.PROVIDER);
56     }
57 
58     @Override
to(RequestKind requestKind, CodeBlock from)59     public CodeBlock to(RequestKind requestKind, CodeBlock from) {
60       switch (requestKind) {
61         case INSTANCE:
62           return CodeBlock.of("$L.get()", from);
63 
64         case LAZY:
65           return CodeBlock.of("$T.lazy($L)", DoubleCheck.class, from);
66 
67         case PROVIDER:
68           return from;
69 
70         case PROVIDER_OF_LAZY:
71           return CodeBlock.of("$T.create($L)", ProviderOfLazy.class, from);
72 
73         case PRODUCER:
74           return CodeBlock.of("$T.producerFromProvider($L)", Producers.class, from);
75 
76         case FUTURE:
77           return CodeBlock.of("$T.immediateFuture($L)", Futures.class, to(INSTANCE, from));
78 
79         case PRODUCED:
80           return CodeBlock.of("$T.successful($L)", Produced.class, to(INSTANCE, from));
81 
82         default:
83           throw new IllegalArgumentException(
84               String.format("Cannot request a %s from a %s", requestKind, this));
85       }
86     }
87 
88     @Override
to(RequestKind requestKind, Expression from, DaggerTypes types)89     public Expression to(RequestKind requestKind, Expression from, DaggerTypes types) {
90       CodeBlock codeBlock = to(requestKind, from.codeBlock());
91       switch (requestKind) {
92         case INSTANCE:
93           return Expression.create(types.unwrapTypeOrObject(from.type()), codeBlock);
94 
95         case PROVIDER:
96           return from;
97 
98         case PROVIDER_OF_LAZY:
99           TypeMirror lazyType = types.rewrapType(from.type(), Lazy.class);
100           return Expression.create(types.wrapType(lazyType, Provider.class), codeBlock);
101 
102         case FUTURE:
103           return Expression.create(
104               types.rewrapType(from.type(), ListenableFuture.class), codeBlock);
105 
106         default:
107           return Expression.create(
108               types.rewrapType(from.type(), RequestKinds.frameworkClass(requestKind)), codeBlock);
109       }
110     }
111   },
112 
113   /** A {@link Producer}. */
114   PRODUCER_NODE {
115     @Override
frameworkClass()116     public Class<?> frameworkClass() {
117       // TODO(cgdecker): Replace this with new class for representing internal producer nodes.
118       // Currently the new class is CancellableProducer, but it may be changed to ProducerNode and
119       // made to not implement Producer.
120       return Producer.class;
121     }
122 
123     @Override
requestKind()124     public Optional<RequestKind> requestKind() {
125       return Optional.empty();
126     }
127 
128     @Override
to(RequestKind requestKind, CodeBlock from)129     public CodeBlock to(RequestKind requestKind, CodeBlock from) {
130       switch (requestKind) {
131         case FUTURE:
132           return CodeBlock.of("$L.get()", from);
133 
134         case PRODUCER:
135           return from;
136 
137         default:
138           throw new IllegalArgumentException(
139               String.format("Cannot request a %s from a %s", requestKind, this));
140       }
141     }
142 
143     @Override
to(RequestKind requestKind, Expression from, DaggerTypes types)144     public Expression to(RequestKind requestKind, Expression from, DaggerTypes types) {
145       switch (requestKind) {
146         case FUTURE:
147           return Expression.create(
148               types.rewrapType(from.type(), ListenableFuture.class),
149               to(requestKind, from.codeBlock()));
150 
151         case PRODUCER:
152           return Expression.create(from.type(), to(requestKind, from.codeBlock()));
153 
154         default:
155           throw new IllegalArgumentException(
156               String.format("Cannot request a %s from a %s", requestKind, this));
157       }
158     }
159   },
160   ;
161 
162   /** Returns the framework type appropriate for fields for a given binding type. */
forBindingType(BindingType bindingType)163   public static FrameworkType forBindingType(BindingType bindingType) {
164     switch (bindingType) {
165       case PROVISION:
166         return PROVIDER;
167       case PRODUCTION:
168         return PRODUCER_NODE;
169       case MEMBERS_INJECTION:
170     }
171     throw new AssertionError(bindingType);
172   }
173 
174   /** Returns the framework type that exactly matches the given request kind, if one exists. */
forRequestKind(RequestKind requestKind)175   public static Optional<FrameworkType> forRequestKind(RequestKind requestKind) {
176     switch (requestKind) {
177       case PROVIDER:
178         return Optional.of(FrameworkType.PROVIDER);
179       default:
180         return Optional.empty();
181     }
182   }
183 
184   /** The class of fields of this type. */
frameworkClass()185   public abstract Class<?> frameworkClass();
186 
187   /** Returns the {@link #frameworkClass()} parameterized with a type. */
frameworkClassOf(TypeName valueType)188   public ParameterizedTypeName frameworkClassOf(TypeName valueType) {
189     return ParameterizedTypeName.get(ClassName.get(frameworkClass()), valueType);
190   }
191 
192   /** The request kind that an instance of this framework type can satisfy directly, if any. */
requestKind()193   public abstract Optional<RequestKind> requestKind();
194 
195   /**
196    * Returns a {@link CodeBlock} that evaluates to a requested object given an expression that
197    * evaluates to an instance of this framework type.
198    *
199    * @param requestKind the kind of {@link DependencyRequest} that the returned expression can
200    *     satisfy
201    * @param from a {@link CodeBlock} that evaluates to an instance of this framework type
202    * @throws IllegalArgumentException if a valid expression cannot be generated for {@code
203    *     requestKind}
204    */
to(RequestKind requestKind, CodeBlock from)205   public abstract CodeBlock to(RequestKind requestKind, CodeBlock from);
206 
207   /**
208    * Returns an {@link Expression} that evaluates to a requested object given an expression that
209    * evaluates to an instance of this framework type.
210    *
211    * @param requestKind the kind of {@link DependencyRequest} that the returned expression can
212    *     satisfy
213    * @param from an expression that evaluates to an instance of this framework type
214    * @throws IllegalArgumentException if a valid expression cannot be generated for {@code
215    *     requestKind}
216    */
to(RequestKind requestKind, Expression from, DaggerTypes types)217   public abstract Expression to(RequestKind requestKind, Expression from, DaggerTypes types);
218 
219   @Override
toString()220   public String toString() {
221     return UPPER_UNDERSCORE.to(UPPER_CAMEL, super.toString());
222   }
223 }
224