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