Home | History | Annotate | Download | only in codegen
      1 /*
      2  * Copyright (C) 2015 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.common.base.Predicate;
     19 import com.google.common.collect.Iterables;
     20 import dagger.internal.codegen.writer.ClassName;
     21 import dagger.internal.codegen.writer.ClassWriter;
     22 import dagger.internal.codegen.writer.JavaWriter;
     23 import dagger.internal.codegen.writer.MethodWriter;
     24 import javax.annotation.Generated;
     25 import javax.lang.model.element.TypeElement;
     26 import javax.lang.model.util.Elements;
     27 import javax.lang.model.util.Types;
     28 import javax.tools.Diagnostic.Kind;
     29 
     30 import static dagger.internal.codegen.Util.componentCanMakeNewInstances;
     31 import static javax.lang.model.element.Modifier.FINAL;
     32 import static javax.lang.model.element.Modifier.PUBLIC;
     33 import static javax.lang.model.element.Modifier.STATIC;
     34 
     35 /**
     36  * Creates the implementation class for a component.
     37  */
     38 class ComponentWriter extends AbstractComponentWriter {
     39 
     40   ComponentWriter(
     41       Types types,
     42       Elements elements,
     43       Key.Factory keyFactory,
     44       Kind nullableValidationType,
     45       ClassName name,
     46       BindingGraph graph) {
     47     super(types, elements, keyFactory, nullableValidationType, name, graph);
     48   }
     49 
     50   @Override
     51   protected ClassWriter createComponentClass() {
     52     JavaWriter javaWriter = JavaWriter.inPackage(name.packageName());
     53     javaWriters.add(javaWriter);
     54 
     55     ClassWriter componentWriter = javaWriter.addClass(name.simpleName());
     56     componentWriter.annotate(Generated.class).setValue(ComponentProcessor.class.getCanonicalName());
     57     componentWriter.addModifiers(PUBLIC, FINAL);
     58     componentWriter.setSupertype(componentDefinitionType());
     59     return componentWriter;
     60   }
     61 
     62   @Override
     63   protected ClassWriter createBuilder() {
     64     ClassWriter builderWriter = componentWriter.addNestedClass("Builder");
     65     builderWriter.addModifiers(STATIC);
     66 
     67     // Only top-level components have the factory builder() method.
     68     // Mirror the user's builder API type if they had one.
     69     MethodWriter builderFactoryMethod =
     70         graph.componentDescriptor().builderSpec().isPresent()
     71             ? componentWriter.addMethod(
     72                 graph
     73                     .componentDescriptor()
     74                     .builderSpec()
     75                     .get()
     76                     .builderDefinitionType()
     77                     .asType(),
     78                 "builder")
     79             : componentWriter.addMethod(builderWriter, "builder");
     80     builderFactoryMethod.addModifiers(PUBLIC, STATIC);
     81     builderFactoryMethod.body().addSnippet("return new %s();", builderWriter.name());
     82     return builderWriter;
     83   }
     84 
     85   @Override
     86   protected void addFactoryMethods() {
     87     if (canInstantiateAllRequirements()) {
     88       MethodWriter factoryMethod =
     89           componentWriter.addMethod(componentDefinitionTypeName(), "create");
     90       factoryMethod.addModifiers(PUBLIC, STATIC);
     91       // TODO(gak): replace this with something that doesn't allocate a builder
     92       factoryMethod
     93           .body()
     94           .addSnippet(
     95               "return builder().%s();",
     96               graph.componentDescriptor().builderSpec().isPresent()
     97                   ? graph
     98                       .componentDescriptor()
     99                       .builderSpec()
    100                       .get()
    101                       .buildMethod()
    102                       .getSimpleName()
    103                   : "build");
    104     }
    105   }
    106 
    107   /** {@code true} if all of the graph's required dependencies can be automatically constructed. */
    108   private boolean canInstantiateAllRequirements() {
    109     return Iterables.all(
    110         graph.componentRequirements(),
    111         new Predicate<TypeElement>() {
    112           @Override
    113           public boolean apply(TypeElement dependency) {
    114             return componentCanMakeNewInstances(dependency);
    115           }
    116         });
    117   }
    118 }
    119