• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.hilt.android.processor.internal.customtestapplication;
18 
19 import com.squareup.javapoet.FieldSpec;
20 import com.squareup.javapoet.JavaFile;
21 import com.squareup.javapoet.MethodSpec;
22 import com.squareup.javapoet.ParameterSpec;
23 import com.squareup.javapoet.ParameterizedTypeName;
24 import com.squareup.javapoet.TypeName;
25 import com.squareup.javapoet.TypeSpec;
26 import dagger.hilt.processor.internal.ClassNames;
27 import dagger.hilt.processor.internal.Processors;
28 import java.io.IOException;
29 import javax.annotation.processing.ProcessingEnvironment;
30 import javax.lang.model.element.Modifier;
31 
32 /**
33  * Generates an Android Application that holds the Singleton component.
34  */
35 final class CustomTestApplicationGenerator {
36   private static final ParameterSpec COMPONENT_MANAGER =
37       ParameterSpec.builder(ClassNames.TEST_APPLICATION_COMPONENT_MANAGER, "componentManager")
38           .build();
39 
40   private final ProcessingEnvironment processingEnv;
41   private final CustomTestApplicationMetadata metadata;
42 
CustomTestApplicationGenerator( ProcessingEnvironment processingEnv, CustomTestApplicationMetadata metadata)43   public CustomTestApplicationGenerator(
44       ProcessingEnvironment processingEnv, CustomTestApplicationMetadata metadata) {
45     this.processingEnv = processingEnv;
46     this.metadata = metadata;
47   }
48 
generate()49   public void generate() throws IOException {
50     TypeSpec.Builder generator =
51         TypeSpec.classBuilder(metadata.appName())
52             .addOriginatingElement(metadata.element())
53             .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
54             .superclass(metadata.baseAppName())
55             .addSuperinterface(
56                 ParameterizedTypeName.get(ClassNames.GENERATED_COMPONENT_MANAGER, TypeName.OBJECT))
57             .addSuperinterface(ClassNames.TEST_APPLICATION_COMPONENT_MANAGER_HOLDER)
58             .addField(getComponentManagerField())
59             .addMethod(getAttachBaseContextMethod())
60             .addMethod(getComponentManagerMethod())
61             .addMethod(getComponentMethod());
62 
63     Processors.addGeneratedAnnotation(
64         generator, processingEnv, CustomTestApplicationProcessor.class);
65 
66     JavaFile.builder(metadata.appName().packageName(), generator.build())
67         .build()
68         .writeTo(processingEnv.getFiler());
69   }
70 
71   // Initialize this in attachBaseContext to not pull it into the main dex.
72   /** private TestApplicationComponentManager componentManager; */
getComponentManagerField()73   private static FieldSpec getComponentManagerField() {
74     return FieldSpec.builder(COMPONENT_MANAGER.type, COMPONENT_MANAGER.name, Modifier.PRIVATE)
75         .build();
76   }
77 
78   /**
79    * Initializes application fields. These fields are initialized in attachBaseContext to avoid
80    * potential multidexing issues.
81    *
82    * <pre><code>
83    * {@literal @Override} protected void attachBaseContext(Context base) {
84    *   super.attachBaseContext(base);
85    *   componentManager = new TestApplicationComponentManager(this);
86    * }
87    * </code></pre>
88    */
getAttachBaseContextMethod()89   private static MethodSpec getAttachBaseContextMethod() {
90     return MethodSpec.methodBuilder("attachBaseContext")
91         .addAnnotation(Override.class)
92         .addModifiers(Modifier.PROTECTED, Modifier.FINAL)
93         .addParameter(ClassNames.CONTEXT, "base")
94         .addStatement("super.attachBaseContext(base)")
95         .addStatement("$N = new $T(this)", COMPONENT_MANAGER, COMPONENT_MANAGER.type)
96         .build();
97   }
98 
getComponentMethod()99   private static MethodSpec getComponentMethod() {
100     return MethodSpec.methodBuilder("generatedComponent")
101         .addAnnotation(Override.class)
102         .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
103         .returns(TypeName.OBJECT)
104         .addStatement("return $N.generatedComponent()", COMPONENT_MANAGER)
105         .build();
106   }
107 
getComponentManagerMethod()108   private static MethodSpec getComponentManagerMethod() {
109     return MethodSpec.methodBuilder("componentManager")
110         .addAnnotation(Override.class)
111         .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
112         .returns(TypeName.OBJECT)
113         .addStatement("return $N", COMPONENT_MANAGER)
114         .build();
115   }
116 }
117