1 /* 2 * Copyright (C) 2014 Google, Inc. 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 package dagger.internal.codegen; 17 18 import com.google.auto.common.MoreTypes; 19 import com.google.common.base.Function; 20 import com.google.common.base.Joiner; 21 import com.google.common.base.Optional; 22 import com.google.common.base.Predicate; 23 import com.google.common.collect.FluentIterable; 24 import com.google.common.collect.ImmutableList; 25 import com.google.common.collect.ImmutableMap; 26 import com.google.common.collect.ImmutableSet; 27 import com.google.common.collect.Iterables; 28 import com.google.common.util.concurrent.AsyncFunction; 29 import com.google.common.util.concurrent.Futures; 30 import com.google.common.util.concurrent.ListenableFuture; 31 import dagger.Provides.Type; 32 import dagger.internal.codegen.writer.ClassName; 33 import dagger.internal.codegen.writer.ClassWriter; 34 import dagger.internal.codegen.writer.ConstructorWriter; 35 import dagger.internal.codegen.writer.FieldWriter; 36 import dagger.internal.codegen.writer.JavaWriter; 37 import dagger.internal.codegen.writer.MethodWriter; 38 import dagger.internal.codegen.writer.ParameterizedTypeName; 39 import dagger.internal.codegen.writer.Snippet; 40 import dagger.internal.codegen.writer.TypeName; 41 import dagger.internal.codegen.writer.TypeNames; 42 import dagger.producers.Produced; 43 import dagger.producers.Producer; 44 import dagger.producers.Produces; 45 import dagger.producers.internal.AbstractProducer; 46 import dagger.producers.internal.Producers; 47 import dagger.producers.monitoring.ProducerMonitor; 48 import dagger.producers.monitoring.ProducerToken; 49 import java.util.List; 50 import java.util.concurrent.Executor; 51 import javax.annotation.Generated; 52 import javax.annotation.processing.Filer; 53 import javax.lang.model.element.Element; 54 import javax.lang.model.type.TypeMirror; 55 56 import static dagger.internal.codegen.SourceFiles.frameworkTypeUsageStatement; 57 import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding; 58 import static dagger.internal.codegen.writer.Snippet.makeParametersSnippet; 59 import static javax.lang.model.element.Modifier.FINAL; 60 import static javax.lang.model.element.Modifier.PRIVATE; 61 import static javax.lang.model.element.Modifier.PROTECTED; 62 import static javax.lang.model.element.Modifier.PUBLIC; 63 import static javax.lang.model.element.Modifier.STATIC; 64 65 /** 66 * Generates {@link Producer} implementations from {@link ProductionBinding} instances. 67 * 68 * @author Jesse Beder 69 * @since 2.0 70 */ 71 final class ProducerFactoryGenerator extends SourceFileGenerator<ProductionBinding> { 72 private final DependencyRequestMapper dependencyRequestMapper; 73 74 ProducerFactoryGenerator(Filer filer, DependencyRequestMapper dependencyRequestMapper) { 75 super(filer); 76 this.dependencyRequestMapper = dependencyRequestMapper; 77 } 78 79 @Override 80 ClassName nameGeneratedType(ProductionBinding binding) { 81 return generatedClassNameForBinding(binding); 82 } 83 84 @Override 85 Iterable<? extends Element> getOriginatingElements(ProductionBinding binding) { 86 return ImmutableSet.of(binding.bindingElement()); 87 } 88 89 @Override 90 Optional<? extends Element> getElementForErrorReporting(ProductionBinding binding) { 91 return Optional.of(binding.bindingElement()); 92 } 93 94 @Override 95 ImmutableSet<JavaWriter> write(ClassName generatedTypeName, ProductionBinding binding) { 96 TypeMirror keyType = binding.productionType().equals(Type.MAP) 97 ? Util.getProvidedValueTypeOfMap(MoreTypes.asDeclared(binding.key().type())) 98 : binding.key().type(); 99 TypeName providedTypeName = TypeNames.forTypeMirror(keyType); 100 TypeName futureTypeName = ParameterizedTypeName.create( 101 ClassName.fromClass(ListenableFuture.class), providedTypeName); 102 JavaWriter writer = JavaWriter.inPackage(generatedTypeName.packageName()); 103 104 ClassWriter factoryWriter = writer.addClass(generatedTypeName.simpleName()); 105 ConstructorWriter constructorWriter = factoryWriter.addConstructor(); 106 constructorWriter.addModifiers(PUBLIC); 107 108 ImmutableMap<BindingKey, FrameworkField> fields = 109 SourceFiles.generateBindingFieldsForDependencies( 110 dependencyRequestMapper, binding.implicitDependencies()); 111 112 constructorWriter 113 .body() 114 .addSnippet( 115 "super(%s, %s.create(%s.class));", 116 fields.get(binding.monitorRequest().get().bindingKey()).name(), 117 ClassName.fromClass(ProducerToken.class), 118 factoryWriter.name()); 119 120 if (!binding.bindingElement().getModifiers().contains(STATIC)) { 121 factoryWriter.addField(binding.bindingTypeElement(), "module") 122 .addModifiers(PRIVATE, FINAL); 123 constructorWriter.addParameter(binding.bindingTypeElement(), "module"); 124 constructorWriter.body() 125 .addSnippet("assert module != null;") 126 .addSnippet("this.module = module;"); 127 } 128 129 factoryWriter.addField(Executor.class, "executor") 130 .addModifiers(PRIVATE, FINAL); 131 constructorWriter.addParameter(Executor.class, "executor"); 132 constructorWriter.body() 133 .addSnippet("assert executor != null;") 134 .addSnippet("this.executor = executor;"); 135 136 factoryWriter.annotate(Generated.class).setValue(ComponentProcessor.class.getName()); 137 factoryWriter.addModifiers(PUBLIC); 138 factoryWriter.addModifiers(FINAL); 139 factoryWriter.setSuperclass( 140 ParameterizedTypeName.create(AbstractProducer.class, providedTypeName)); 141 142 MethodWriter computeMethodWriter = factoryWriter.addMethod(futureTypeName, "compute"); 143 computeMethodWriter.annotate(Override.class); 144 computeMethodWriter.addModifiers(PROTECTED); 145 computeMethodWriter.addParameter(ProducerMonitor.class, "monitor").addModifiers(FINAL); 146 147 for (FrameworkField bindingField : fields.values()) { 148 TypeName fieldType = bindingField.frameworkType(); 149 FieldWriter field = factoryWriter.addField(fieldType, bindingField.name()); 150 field.addModifiers(PRIVATE, FINAL); 151 constructorWriter.addParameter(field.type(), field.name()); 152 constructorWriter.body() 153 .addSnippet("assert %s != null;", field.name()) 154 .addSnippet("this.%1$s = %1$s;", field.name()); 155 } 156 157 boolean returnsFuture = 158 binding.bindingKind().equals(ContributionBinding.Kind.FUTURE_PRODUCTION); 159 ImmutableList<DependencyRequest> asyncDependencies = 160 FluentIterable.from(binding.implicitDependencies()) 161 .filter( 162 new Predicate<DependencyRequest>() { 163 @Override 164 public boolean apply(DependencyRequest dependency) { 165 return isAsyncDependency(dependency); 166 } 167 }) 168 .toList(); 169 170 for (DependencyRequest dependency : asyncDependencies) { 171 ParameterizedTypeName futureType = ParameterizedTypeName.create( 172 ClassName.fromClass(ListenableFuture.class), 173 asyncDependencyType(dependency)); 174 String name = fields.get(dependency.bindingKey()).name(); 175 Snippet futureAccess = Snippet.format("%s.get()", name); 176 computeMethodWriter 177 .body() 178 .addSnippet( 179 "%s %sFuture = %s;", 180 futureType, 181 name, 182 dependency.kind().equals(DependencyRequest.Kind.PRODUCED) 183 ? Snippet.format( 184 "%s.createFutureProduced(%s)", 185 ClassName.fromClass(Producers.class), 186 futureAccess) 187 : futureAccess); 188 } 189 190 FutureTransform futureTransform = FutureTransform.create(fields, binding, asyncDependencies); 191 Snippet transformSnippet = 192 Snippet.format( 193 Joiner.on('\n') 194 .join( 195 "new %1$s<%2$s, %3$s>() {", 196 " %4$s", 197 " @Override public %5$s apply(%2$s %6$s) %7$s {", 198 " %8$s", 199 " }", 200 "}"), 201 ClassName.fromClass(AsyncFunction.class), 202 futureTransform.applyArgType(), 203 providedTypeName, 204 futureTransform.hasUncheckedCast() 205 ? "@SuppressWarnings(\"unchecked\") // safe by specification" 206 : "", 207 futureTypeName, 208 futureTransform.applyArgName(), 209 getThrowsClause(binding.thrownTypes()), 210 getInvocationSnippet(!returnsFuture, binding, futureTransform.parameterSnippets())); 211 computeMethodWriter 212 .body() 213 .addSnippet( 214 "return %s.transform(%s, %s, executor);", 215 ClassName.fromClass(Futures.class), 216 futureTransform.futureSnippet(), 217 transformSnippet); 218 219 // TODO(gak): write a sensible toString 220 return ImmutableSet.of(writer); 221 } 222 223 /** Represents the transformation of an input future by a producer method. */ 224 abstract static class FutureTransform { 225 protected final ImmutableMap<BindingKey, FrameworkField> fields; 226 protected final ProductionBinding binding; 227 228 FutureTransform(ImmutableMap<BindingKey, FrameworkField> fields, ProductionBinding binding) { 229 this.fields = fields; 230 this.binding = binding; 231 } 232 233 /** The snippet representing the future that should be transformed. */ 234 abstract Snippet futureSnippet(); 235 236 /** The type of the argument to the apply method. */ 237 abstract TypeName applyArgType(); 238 239 /** The name of the argument to the apply method */ 240 abstract String applyArgName(); 241 242 /** The snippets to be passed to the produces method itself. */ 243 abstract ImmutableList<Snippet> parameterSnippets(); 244 245 /** Whether the transform method has an unchecked cast. */ 246 boolean hasUncheckedCast() { 247 return false; 248 } 249 250 static FutureTransform create( 251 ImmutableMap<BindingKey, FrameworkField> fields, 252 ProductionBinding binding, 253 ImmutableList<DependencyRequest> asyncDependencies) { 254 if (asyncDependencies.isEmpty()) { 255 return new NoArgFutureTransform(fields, binding); 256 } else if (asyncDependencies.size() == 1) { 257 return new SingleArgFutureTransform( 258 fields, binding, Iterables.getOnlyElement(asyncDependencies)); 259 } else { 260 return new MultiArgFutureTransform(fields, binding, asyncDependencies); 261 } 262 } 263 } 264 265 static final class NoArgFutureTransform extends FutureTransform { 266 NoArgFutureTransform( 267 ImmutableMap<BindingKey, FrameworkField> fields, ProductionBinding binding) { 268 super(fields, binding); 269 } 270 271 @Override 272 Snippet futureSnippet() { 273 return Snippet.format( 274 "%s.<%s>immediateFuture(null)", 275 ClassName.fromClass(Futures.class), 276 ClassName.fromClass(Void.class)); 277 } 278 279 @Override 280 TypeName applyArgType() { 281 return ClassName.fromClass(Void.class); 282 } 283 284 @Override 285 String applyArgName() { 286 return "ignoredVoidArg"; 287 } 288 289 @Override 290 ImmutableList<Snippet> parameterSnippets() { 291 ImmutableList.Builder<Snippet> parameterSnippets = ImmutableList.builder(); 292 for (DependencyRequest dependency : binding.dependencies()) { 293 parameterSnippets.add( 294 frameworkTypeUsageStatement( 295 Snippet.format( 296 "%s", fields.get(dependency.bindingKey()).name()), dependency.kind())); 297 } 298 return parameterSnippets.build(); 299 } 300 } 301 302 static final class SingleArgFutureTransform extends FutureTransform { 303 private final DependencyRequest asyncDependency; 304 305 SingleArgFutureTransform( 306 ImmutableMap<BindingKey, FrameworkField> fields, 307 ProductionBinding binding, 308 DependencyRequest asyncDependency) { 309 super(fields, binding); 310 this.asyncDependency = asyncDependency; 311 } 312 313 @Override 314 Snippet futureSnippet() { 315 return Snippet.format("%s", fields.get(asyncDependency.bindingKey()).name() + "Future"); 316 } 317 318 @Override 319 TypeName applyArgType() { 320 return asyncDependencyType(asyncDependency); 321 } 322 323 @Override 324 String applyArgName() { 325 return asyncDependency.requestElement().getSimpleName().toString(); 326 } 327 328 @Override 329 ImmutableList<Snippet> parameterSnippets() { 330 ImmutableList.Builder<Snippet> parameterSnippets = ImmutableList.builder(); 331 for (DependencyRequest dependency : binding.dependencies()) { 332 // We really want to compare instances here, because asyncDependency is an element in the 333 // set binding.dependencies(). 334 if (dependency == asyncDependency) { 335 parameterSnippets.add(Snippet.format("%s", applyArgName())); 336 } else { 337 parameterSnippets.add( 338 frameworkTypeUsageStatement( 339 Snippet.format( 340 "%s", fields.get(dependency.bindingKey()).name()), dependency.kind())); 341 } 342 } 343 return parameterSnippets.build(); 344 } 345 } 346 347 static final class MultiArgFutureTransform extends FutureTransform { 348 private final ImmutableList<DependencyRequest> asyncDependencies; 349 350 MultiArgFutureTransform( 351 ImmutableMap<BindingKey, FrameworkField> fields, 352 ProductionBinding binding, 353 ImmutableList<DependencyRequest> asyncDependencies) { 354 super(fields, binding); 355 this.asyncDependencies = asyncDependencies; 356 } 357 358 @Override 359 Snippet futureSnippet() { 360 return Snippet.format( 361 "%s.<%s>allAsList(%s)", 362 ClassName.fromClass(Futures.class), 363 ClassName.fromClass(Object.class), 364 makeParametersSnippet( 365 FluentIterable.from(asyncDependencies) 366 .transform(DependencyRequest.BINDING_KEY_FUNCTION) 367 .transform( 368 new Function<BindingKey, Snippet>() { 369 @Override 370 public Snippet apply(BindingKey bindingKey) { 371 return Snippet.format("%s", fields.get(bindingKey).name() + "Future"); 372 } 373 }))); 374 } 375 376 @Override 377 TypeName applyArgType() { 378 return ParameterizedTypeName.create( 379 ClassName.fromClass(List.class), ClassName.fromClass(Object.class)); 380 } 381 382 @Override 383 String applyArgName() { 384 return "args"; 385 } 386 387 @Override 388 ImmutableList<Snippet> parameterSnippets() { 389 return getParameterSnippets(binding, fields, applyArgName()); 390 } 391 392 @Override 393 boolean hasUncheckedCast() { 394 return true; 395 } 396 } 397 398 private static boolean isAsyncDependency(DependencyRequest dependency) { 399 switch (dependency.kind()) { 400 case INSTANCE: 401 case PRODUCED: 402 return true; 403 default: 404 return false; 405 } 406 } 407 408 private static TypeName asyncDependencyType(DependencyRequest dependency) { 409 TypeName keyName = TypeNames.forTypeMirror(dependency.key().type()); 410 switch (dependency.kind()) { 411 case INSTANCE: 412 return keyName; 413 case PRODUCED: 414 return ParameterizedTypeName.create(ClassName.fromClass(Produced.class), keyName); 415 default: 416 throw new AssertionError(); 417 } 418 } 419 420 private static ImmutableList<Snippet> getParameterSnippets( 421 ProductionBinding binding, 422 ImmutableMap<BindingKey, FrameworkField> fields, 423 String listArgName) { 424 int argIndex = 0; 425 ImmutableList.Builder<Snippet> snippets = ImmutableList.builder(); 426 for (DependencyRequest dependency : binding.dependencies()) { 427 if (isAsyncDependency(dependency)) { 428 snippets.add(Snippet.format( 429 "(%s) %s.get(%s)", 430 asyncDependencyType(dependency), 431 listArgName, 432 argIndex)); 433 argIndex++; 434 } else { 435 snippets.add(frameworkTypeUsageStatement( 436 Snippet.format("%s", fields.get(dependency.bindingKey()).name()), dependency.kind())); 437 } 438 } 439 return snippets.build(); 440 } 441 442 /** 443 * Creates a snippet for the invocation of the producer method from the module, which should be 444 * used entirely within a method body. 445 * 446 * @param wrapWithFuture If true, wraps the result of the call to the producer method 447 * in an immediate future. 448 * @param binding The binding to generate the invocation snippet for. 449 * @param parameterSnippets The snippets for all the parameters to the producer method. 450 */ 451 private Snippet getInvocationSnippet( 452 boolean wrapWithFuture, ProductionBinding binding, ImmutableList<Snippet> parameterSnippets) { 453 Snippet moduleSnippet = Snippet.format("%s.%s(%s)", 454 binding.bindingElement().getModifiers().contains(STATIC) 455 ? ClassName.fromTypeElement(binding.bindingTypeElement()) 456 : "module", 457 binding.bindingElement().getSimpleName(), 458 makeParametersSnippet(parameterSnippets)); 459 460 // NOTE(beder): We don't worry about catching exeptions from the monitor methods themselves 461 // because we'll wrap all monitoring in non-throwing monitors before we pass them to the 462 // factories. 463 ImmutableList.Builder<Snippet> snippets = ImmutableList.builder(); 464 snippets.add(Snippet.format("monitor.methodStarting();")); 465 466 final Snippet valueSnippet; 467 if (binding.productionType().equals(Produces.Type.SET)) { 468 if (binding.bindingKind().equals(ContributionBinding.Kind.FUTURE_PRODUCTION)) { 469 valueSnippet = 470 Snippet.format( 471 "%s.createFutureSingletonSet(%s)", 472 ClassName.fromClass(Producers.class), 473 moduleSnippet); 474 } else { 475 valueSnippet = 476 Snippet.format("%s.of(%s)", ClassName.fromClass(ImmutableSet.class), moduleSnippet); 477 } 478 } else { 479 valueSnippet = moduleSnippet; 480 } 481 Snippet returnSnippet = 482 wrapWithFuture 483 ? Snippet.format( 484 "%s.<%s>immediateFuture(%s)", 485 ClassName.fromClass(Futures.class), 486 TypeNames.forTypeMirror(binding.key().type()), 487 valueSnippet) 488 : valueSnippet; 489 return Snippet.format( 490 Joiner.on('\n') 491 .join( 492 "monitor.methodStarting();", 493 "try {", 494 " return %s;", 495 "} finally {", 496 " monitor.methodFinished();", 497 "}"), 498 returnSnippet); 499 } 500 501 /** 502 * Creates a Snippet for the throws clause. 503 * 504 * @param thrownTypes the list of thrown types. 505 */ 506 private Snippet getThrowsClause(List<? extends TypeMirror> thrownTypes) { 507 if (thrownTypes.isEmpty()) { 508 return Snippet.format(""); 509 } 510 return Snippet.format("throws %s ", 511 Snippet.makeParametersSnippet(FluentIterable 512 .from(thrownTypes) 513 .transform(new Function<TypeMirror, Snippet>() { 514 @Override public Snippet apply(TypeMirror thrownType) { 515 return Snippet.format("%s", TypeNames.forTypeMirror(thrownType)); 516 } 517 }) 518 .toList())); 519 } 520 } 521