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