• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ComponentWriter( Types types, Elements elements, Key.Factory keyFactory, Kind nullableValidationType, ClassName name, BindingGraph graph)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
createComponentClass()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
createBuilder()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
addFactoryMethods()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. */
canInstantiateAllRequirements()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