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.writing; 18 19 import static com.google.common.base.CaseFormat.UPPER_CAMEL; 20 import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE; 21 import static com.google.common.base.Verify.verify; 22 import static com.google.common.collect.Iterables.getOnlyElement; 23 import static com.squareup.javapoet.MethodSpec.constructorBuilder; 24 import static com.squareup.javapoet.MethodSpec.methodBuilder; 25 import static com.squareup.javapoet.TypeSpec.anonymousClassBuilder; 26 import static com.squareup.javapoet.TypeSpec.classBuilder; 27 import static dagger.internal.codegen.base.RequestKinds.requestTypeName; 28 import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.RAWTYPES; 29 import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED; 30 import static dagger.internal.codegen.javapoet.TypeNames.abstractProducerOf; 31 import static dagger.internal.codegen.javapoet.TypeNames.daggerProviderOf; 32 import static dagger.internal.codegen.javapoet.TypeNames.listenableFutureOf; 33 import static dagger.internal.codegen.writing.ComponentImplementation.FieldSpecKind.ABSENT_OPTIONAL_FIELD; 34 import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.ABSENT_OPTIONAL_METHOD; 35 import static dagger.internal.codegen.writing.ComponentImplementation.TypeSpecKind.PRESENT_FACTORY; 36 import static javax.lang.model.element.Modifier.FINAL; 37 import static javax.lang.model.element.Modifier.PRIVATE; 38 import static javax.lang.model.element.Modifier.PUBLIC; 39 import static javax.lang.model.element.Modifier.STATIC; 40 41 import com.google.auto.value.AutoValue; 42 import com.google.common.base.Function; 43 import com.google.common.util.concurrent.Futures; 44 import com.google.common.util.concurrent.ListenableFuture; 45 import com.google.common.util.concurrent.MoreExecutors; 46 import com.squareup.javapoet.ClassName; 47 import com.squareup.javapoet.CodeBlock; 48 import com.squareup.javapoet.FieldSpec; 49 import com.squareup.javapoet.MethodSpec; 50 import com.squareup.javapoet.ParameterSpec; 51 import com.squareup.javapoet.ParameterizedTypeName; 52 import com.squareup.javapoet.TypeName; 53 import com.squareup.javapoet.TypeSpec; 54 import com.squareup.javapoet.TypeVariableName; 55 import dagger.internal.InstanceFactory; 56 import dagger.internal.Preconditions; 57 import dagger.internal.codegen.base.OptionalType; 58 import dagger.internal.codegen.base.OptionalType.OptionalKind; 59 import dagger.internal.codegen.binding.BindingType; 60 import dagger.internal.codegen.binding.ContributionBinding; 61 import dagger.internal.codegen.binding.FrameworkType; 62 import dagger.internal.codegen.javapoet.AnnotationSpecs; 63 import dagger.internal.codegen.javapoet.TypeNames; 64 import dagger.internal.codegen.model.RequestKind; 65 import java.util.Comparator; 66 import java.util.Map; 67 import java.util.Optional; 68 import java.util.TreeMap; 69 import java.util.concurrent.Executor; 70 import javax.inject.Inject; 71 72 /** The nested class and static methods required by the component to implement optional bindings. */ 73 // TODO(dpb): Name members simply if a component uses only one of Guava or JDK Optional. 74 final class OptionalFactories { 75 /** Keeps track of the fields, methods, and classes already added to the generated file. */ 76 @PerGeneratedFile 77 static final class PerGeneratedFileCache { 78 /** 79 * The factory classes that implement {@code Provider<Optional<T>>} or {@code 80 * Producer<Optional<T>>} for present optional bindings for a given kind of dependency request 81 * within the component. 82 * 83 * <p>The key is the {@code Provider<Optional<T>>} type. 84 */ 85 private final Map<PresentFactorySpec, TypeSpec> presentFactoryClasses = 86 new TreeMap<>( 87 Comparator.comparing(PresentFactorySpec::valueKind) 88 .thenComparing(PresentFactorySpec::frameworkType) 89 .thenComparing(PresentFactorySpec::optionalKind)); 90 91 /** 92 * The static methods that return a {@code Provider<Optional<T>>} that always returns an absent 93 * value. 94 */ 95 private final Map<OptionalKind, MethodSpec> absentOptionalProviderMethods = new TreeMap<>(); 96 97 /** 98 * The static fields for {@code Provider<Optional<T>>} objects that always return an absent 99 * value. 100 */ 101 private final Map<OptionalKind, FieldSpec> absentOptionalProviderFields = new TreeMap<>(); 102 103 @Inject PerGeneratedFileCache()104 PerGeneratedFileCache() {} 105 } 106 107 private final PerGeneratedFileCache perGeneratedFileCache; 108 private final GeneratedImplementation topLevelImplementation; 109 110 @Inject OptionalFactories( PerGeneratedFileCache perGeneratedFileCache, @TopLevel GeneratedImplementation topLevelImplementation)111 OptionalFactories( 112 PerGeneratedFileCache perGeneratedFileCache, 113 @TopLevel GeneratedImplementation topLevelImplementation) { 114 this.perGeneratedFileCache = perGeneratedFileCache; 115 this.topLevelImplementation = topLevelImplementation; 116 } 117 118 /** 119 * Returns an expression that calls a static method that returns a {@code Provider<Optional<T>>} 120 * for absent optional bindings. 121 */ absentOptionalProvider(ContributionBinding binding)122 CodeBlock absentOptionalProvider(ContributionBinding binding) { 123 verify( 124 binding.bindingType().equals(BindingType.PROVISION), 125 "Absent optional bindings should be provisions: %s", 126 binding); 127 OptionalKind optionalKind = OptionalType.from(binding.key()).kind(); 128 return CodeBlock.of( 129 "$N()", 130 perGeneratedFileCache.absentOptionalProviderMethods.computeIfAbsent( 131 optionalKind, 132 kind -> { 133 MethodSpec method = absentOptionalProviderMethod(kind); 134 topLevelImplementation.addMethod(ABSENT_OPTIONAL_METHOD, method); 135 return method; 136 })); 137 } 138 139 /** 140 * Creates a method specification for a {@code Provider<Optional<T>>} that always returns an 141 * absent value. 142 */ absentOptionalProviderMethod(OptionalKind optionalKind)143 private MethodSpec absentOptionalProviderMethod(OptionalKind optionalKind) { 144 TypeVariableName typeVariable = TypeVariableName.get("T"); 145 return methodBuilder( 146 String.format( 147 "absent%sProvider", UPPER_UNDERSCORE.to(UPPER_CAMEL, optionalKind.name()))) 148 .addModifiers(PRIVATE, STATIC) 149 .addTypeVariable(typeVariable) 150 .returns(daggerProviderOf(optionalKind.of(typeVariable))) 151 .addJavadoc( 152 "Returns a {@link $T} that returns {@code $L}.", 153 TypeNames.DAGGER_PROVIDER, 154 optionalKind.absentValueExpression()) 155 .addCode("$L // safe covariant cast\n", AnnotationSpecs.suppressWarnings(UNCHECKED)) 156 .addStatement( 157 "$1T provider = ($1T) $2N", 158 daggerProviderOf(optionalKind.of(typeVariable)), 159 perGeneratedFileCache.absentOptionalProviderFields.computeIfAbsent( 160 optionalKind, 161 kind -> { 162 FieldSpec field = absentOptionalProviderField(kind); 163 topLevelImplementation.addField(ABSENT_OPTIONAL_FIELD, field); 164 return field; 165 })) 166 .addStatement("return provider") 167 .build(); 168 } 169 170 /** 171 * Creates a field specification for a {@code Provider<Optional<T>>} that always returns an absent 172 * value. 173 */ 174 private FieldSpec absentOptionalProviderField(OptionalKind optionalKind) { 175 return FieldSpec.builder( 176 TypeNames.DAGGER_PROVIDER, 177 String.format("ABSENT_%s_PROVIDER", optionalKind.name()), 178 PRIVATE, 179 STATIC, 180 FINAL) 181 .addAnnotation(AnnotationSpecs.suppressWarnings(RAWTYPES)) 182 .initializer("$T.create($L)", InstanceFactory.class, optionalKind.absentValueExpression()) 183 .addJavadoc( 184 "A {@link $T} that returns {@code $L}.", 185 TypeNames.DAGGER_PROVIDER, 186 optionalKind.absentValueExpression()) 187 .build(); 188 } 189 190 /** Information about the type of a factory for present bindings. */ 191 @AutoValue 192 abstract static class PresentFactorySpec { 193 /** Whether the factory is a {@code Provider} or a {@code Producer}. */ 194 abstract FrameworkType frameworkType(); 195 196 /** What kind of {@code Optional} is returned. */ 197 abstract OptionalKind optionalKind(); 198 199 /** The kind of request satisfied by the value of the {@code Optional}. */ 200 abstract RequestKind valueKind(); 201 202 /** The type variable for the factory class. */ 203 TypeVariableName typeVariable() { 204 return TypeVariableName.get("T"); 205 } 206 207 /** The type contained by the {@code Optional}. */ 208 TypeName valueType() { 209 return requestTypeName(valueKind(), typeVariable()); 210 } 211 212 /** The type provided or produced by the factory. */ 213 ParameterizedTypeName optionalType() { 214 return optionalKind().of(valueType()); 215 } 216 217 /** The type of the factory. */ 218 ParameterizedTypeName factoryType() { 219 return frameworkType().frameworkClassOf(optionalType()); 220 } 221 222 /** The type of the delegate provider or producer. */ 223 ParameterizedTypeName delegateType() { 224 return frameworkType().frameworkClassOf(typeVariable()); 225 } 226 227 /** Returns the superclass the generated factory should have, if any. */ 228 Optional<ParameterizedTypeName> superclass() { 229 switch (frameworkType()) { 230 case PRODUCER_NODE: 231 // TODO(cgdecker): This probably isn't a big issue for now, but it's possible this 232 // shouldn't be an AbstractProducer: 233 // - As AbstractProducer, it'll only call the delegate's get() method once and then cache 234 // that result (essentially) rather than calling the delegate's get() method each time 235 // its get() method is called (which was what it did before the cancellation change). 236 // - It's not 100% clear to me whether the view-creation methods should return a view of 237 // the same view created by the delegate or if they should just return their own views. 238 return Optional.of(abstractProducerOf(optionalType())); 239 default: 240 return Optional.empty(); 241 } 242 } 243 244 /** Returns the superinterface the generated factory should have, if any. */ 245 Optional<ParameterizedTypeName> superinterface() { 246 switch (frameworkType()) { 247 case PROVIDER: 248 return Optional.of(factoryType()); 249 default: 250 return Optional.empty(); 251 } 252 } 253 254 /** Returns the name of the factory method to generate. */ 255 String factoryMethodName() { 256 switch (frameworkType()) { 257 case PROVIDER: 258 return "get"; 259 case PRODUCER_NODE: 260 return "compute"; 261 } 262 throw new AssertionError(frameworkType()); 263 } 264 265 /** The name of the factory class. */ 266 String factoryClassName() { 267 return new StringBuilder("Present") 268 .append(UPPER_UNDERSCORE.to(UPPER_CAMEL, optionalKind().name())) 269 .append(UPPER_UNDERSCORE.to(UPPER_CAMEL, valueKind().toString())) 270 .append(frameworkType().frameworkClassName().simpleName()) 271 .toString(); 272 } 273 274 private static PresentFactorySpec of(ContributionBinding binding) { 275 return new AutoValue_OptionalFactories_PresentFactorySpec( 276 FrameworkType.forBindingType(binding.bindingType()), 277 OptionalType.from(binding.key()).kind(), 278 getOnlyElement(binding.dependencies()).kind()); 279 } 280 } 281 282 /** 283 * Returns an expression for an instance of a nested class that implements {@code 284 * Provider<Optional<T>>} or {@code Producer<Optional<T>>} for a present optional binding, where 285 * {@code T} represents dependency requests of that kind. 286 * 287 * <ul> 288 * <li>If {@code optionalRequestKind} is {@link RequestKind#INSTANCE}, the class implements 289 * {@code ProviderOrProducer<Optional<T>>}. 290 * <li>If {@code optionalRequestKind} is {@link RequestKind#PROVIDER}, the class implements 291 * {@code Provider<Optional<Provider<T>>>}. 292 * <li>If {@code optionalRequestKind} is {@link RequestKind#LAZY}, the class implements {@code 293 * Provider<Optional<Lazy<T>>>}. 294 * <li>If {@code optionalRequestKind} is {@link RequestKind#PROVIDER_OF_LAZY}, the class 295 * implements {@code Provider<Optional<Provider<Lazy<T>>>>}. 296 * <li>If {@code optionalRequestKind} is {@link RequestKind#PRODUCER}, the class implements 297 * {@code Producer<Optional<Producer<T>>>}. 298 * <li>If {@code optionalRequestKind} is {@link RequestKind#PRODUCED}, the class implements 299 * {@code Producer<Optional<Produced<T>>>}. 300 * </ul> 301 * 302 * @param delegateFactory an expression for a {@code Provider} or {@code Producer} of the 303 * underlying type 304 */ 305 CodeBlock presentOptionalFactory(ContributionBinding binding, CodeBlock delegateFactory) { 306 return CodeBlock.of( 307 "$N.of($L)", 308 perGeneratedFileCache.presentFactoryClasses.computeIfAbsent( 309 PresentFactorySpec.of(binding), 310 spec -> { 311 TypeSpec type = presentOptionalFactoryClass(spec); 312 topLevelImplementation.addType(PRESENT_FACTORY, type); 313 return type; 314 }), 315 delegateFactory); 316 } 317 318 private TypeSpec presentOptionalFactoryClass(PresentFactorySpec spec) { 319 FieldSpec delegateField = 320 FieldSpec.builder(spec.delegateType(), "delegate", PRIVATE, FINAL).build(); 321 ParameterSpec delegateParameter = ParameterSpec.builder(delegateField.type, "delegate").build(); 322 TypeSpec.Builder factoryClassBuilder = 323 classBuilder(spec.factoryClassName()) 324 .addTypeVariable(spec.typeVariable()) 325 .addModifiers(PRIVATE, STATIC, FINAL) 326 .addJavadoc( 327 "A {@code $T} that uses a delegate {@code $T}.", 328 spec.factoryType(), 329 delegateField.type); 330 331 spec.superclass().ifPresent(factoryClassBuilder::superclass); 332 spec.superinterface().ifPresent(factoryClassBuilder::addSuperinterface); 333 334 return factoryClassBuilder 335 .addField(delegateField) 336 .addMethod( 337 constructorBuilder() 338 .addModifiers(PRIVATE) 339 .addParameter(delegateParameter) 340 .addCode( 341 "this.$N = $T.checkNotNull($N);", 342 delegateField, 343 Preconditions.class, 344 delegateParameter) 345 .build()) 346 .addMethod(presentOptionalFactoryGetMethod(spec, delegateField)) 347 .addMethod( 348 methodBuilder("of") 349 .addModifiers(PRIVATE, STATIC) 350 .addTypeVariable(spec.typeVariable()) 351 .returns(spec.factoryType()) 352 .addParameter(delegateParameter) 353 .addCode( 354 "return new $L<$T>($N);", 355 spec.factoryClassName(), 356 spec.typeVariable(), 357 delegateParameter) 358 .build()) 359 .build(); 360 } 361 362 private MethodSpec presentOptionalFactoryGetMethod( 363 PresentFactorySpec spec, FieldSpec delegateField) { 364 MethodSpec.Builder getMethodBuilder = 365 methodBuilder(spec.factoryMethodName()).addAnnotation(Override.class).addModifiers(PUBLIC); 366 367 switch (spec.frameworkType()) { 368 case PROVIDER: 369 return getMethodBuilder 370 .returns(spec.optionalType()) 371 .addCode( 372 "return $L;", 373 spec.optionalKind() 374 .presentExpression( 375 FrameworkType.PROVIDER.to( 376 spec.valueKind(), 377 CodeBlock.of("$N", delegateField)))) 378 .build(); 379 380 case PRODUCER_NODE: 381 getMethodBuilder.returns(listenableFutureOf(spec.optionalType())); 382 383 switch (spec.valueKind()) { 384 case FUTURE: // return a ListenableFuture<Optional<ListenableFuture<T>>> 385 case PRODUCER: // return a ListenableFuture<Optional<Producer<T>>> 386 return getMethodBuilder 387 .addCode( 388 "return $T.immediateFuture($L);", 389 Futures.class, 390 spec.optionalKind() 391 .presentExpression( 392 FrameworkType.PRODUCER_NODE.to( 393 spec.valueKind(), 394 CodeBlock.of("$N", delegateField)))) 395 .build(); 396 397 case INSTANCE: // return a ListenableFuture<Optional<T>> 398 return getMethodBuilder 399 .addCode( 400 "return $L;", 401 transformFutureToOptional( 402 spec.optionalKind(), 403 spec.typeVariable(), 404 CodeBlock.of("$N.get()", delegateField))) 405 .build(); 406 407 case PRODUCED: // return a ListenableFuture<Optional<Produced<T>>> 408 return getMethodBuilder 409 .addCode( 410 "return $L;", 411 transformFutureToOptional( 412 spec.optionalKind(), 413 spec.valueType(), 414 CodeBlock.of( 415 "$T.createFutureProduced($N.get())", 416 TypeNames.PRODUCERS, 417 delegateField))) 418 .build(); 419 420 default: 421 throw new UnsupportedOperationException( 422 spec.factoryType() + " objects are not supported"); 423 } 424 } 425 throw new AssertionError(spec.frameworkType()); 426 } 427 428 /** 429 * An expression that uses {@link Futures#transform(ListenableFuture, Function, Executor)} to 430 * transform a {@code ListenableFuture<inputType>} into a {@code 431 * ListenableFuture<Optional<inputType>>}. 432 * 433 * @param inputFuture an expression of type {@code ListenableFuture<inputType>} 434 */ 435 private static CodeBlock transformFutureToOptional( 436 OptionalKind optionalKind, TypeName inputType, CodeBlock inputFuture) { 437 return CodeBlock.of( 438 "$T.transform($L, $L, $T.directExecutor())", 439 Futures.class, 440 inputFuture, 441 anonymousClassBuilder("") 442 .addSuperinterface( 443 ParameterizedTypeName.get( 444 ClassName.get(Function.class), inputType, optionalKind.of(inputType))) 445 .addMethod( 446 methodBuilder("apply") 447 .addAnnotation(Override.class) 448 .addModifiers(PUBLIC) 449 .returns(optionalKind.of(inputType)) 450 .addParameter(inputType, "input") 451 .addCode("return $L;", optionalKind.presentExpression(CodeBlock.of("input"))) 452 .build()) 453 .build(), 454 MoreExecutors.class); 455 } 456 } 457