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