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.processor.internal.root; 18 19 import static javax.lang.model.element.Modifier.FINAL; 20 import static javax.lang.model.element.Modifier.PRIVATE; 21 import static javax.lang.model.element.Modifier.PROTECTED; 22 import static javax.lang.model.element.Modifier.PUBLIC; 23 24 import com.google.common.collect.ImmutableList; 25 import com.squareup.javapoet.ClassName; 26 import com.squareup.javapoet.FieldSpec; 27 import com.squareup.javapoet.JavaFile; 28 import com.squareup.javapoet.MethodSpec; 29 import com.squareup.javapoet.ParameterizedTypeName; 30 import com.squareup.javapoet.TypeName; 31 import com.squareup.javapoet.TypeSpec; 32 import com.squareup.javapoet.WildcardTypeName; 33 import dagger.hilt.processor.internal.ClassNames; 34 import dagger.hilt.processor.internal.Processors; 35 import java.io.IOException; 36 import javax.annotation.processing.ProcessingEnvironment; 37 38 /** Generates an implementation of {@link dagger.hilt.android.internal.TestComponentDataSupplier} */ 39 public final class TestComponentDataSupplierGenerator { 40 private static final ClassName TEST_COMPONENT_DATA_SUPPLIER_IMPL = 41 ClassName.get("dagger.hilt.android.internal.testing", "TestComponentDataSupplierImpl"); 42 private static final ParameterizedTypeName CLASS_TYPE = 43 ParameterizedTypeName.get(ClassNames.CLASS, WildcardTypeName.subtypeOf(TypeName.OBJECT)); 44 private static final ParameterizedTypeName TEST_COMPONENT_DATA_MAP_TYPE = 45 ParameterizedTypeName.get(ClassNames.MAP, CLASS_TYPE, ClassNames.TEST_COMPONENT_DATA); 46 47 private final ProcessingEnvironment processingEnv; 48 private final ImmutableList<RootMetadata> rootMetadatas; 49 TestComponentDataSupplierGenerator( ProcessingEnvironment processingEnv, ImmutableList<RootMetadata> rootMetadatas)50 public TestComponentDataSupplierGenerator( 51 ProcessingEnvironment processingEnv, 52 ImmutableList<RootMetadata> rootMetadatas) { 53 this.processingEnv = processingEnv; 54 this.rootMetadatas = rootMetadatas; 55 } 56 57 /** 58 * <pre><code>{@code 59 * public final class TestComponentDataSupplierImpl extends TestComponentDataSupplier { 60 * private final Map<Class<?>, TestComponentData> testComponentDataMap = new HashMap<>(); 61 * 62 * protected TestComponentDataSupplierImpl() { 63 * testComponentDataMap.put(FooTest.class, new FooTest_ComponentData()); 64 * testComponentDataMap.put(BarTest.class, new BarTest_ComponentData()); 65 * ... 66 * } 67 * 68 * @Override 69 * protected Map<Class<?>, TestComponentData> get() { 70 * return testComponentDataMap; 71 * } 72 * } 73 * }</code></pre> 74 */ generate()75 public void generate() throws IOException { 76 TypeSpec.Builder generator = 77 TypeSpec.classBuilder(TEST_COMPONENT_DATA_SUPPLIER_IMPL) 78 .addModifiers(PUBLIC, FINAL) 79 .superclass(ClassNames.TEST_COMPONENT_DATA_SUPPLIER) 80 .addField( 81 FieldSpec.builder( 82 TEST_COMPONENT_DATA_MAP_TYPE, "testComponentDataMap", PRIVATE, FINAL) 83 .initializer("new $T<>($L)", ClassNames.HASH_MAP, rootMetadatas.size()) 84 .build()) 85 .addMethod(constructor()) 86 .addMethod(getMethod()); 87 88 Processors.addGeneratedAnnotation( 89 generator, processingEnv, ClassNames.ROOT_PROCESSOR.toString()); 90 91 JavaFile.builder(TEST_COMPONENT_DATA_SUPPLIER_IMPL.packageName(), generator.build()) 92 .build() 93 .writeTo(processingEnv.getFiler()); 94 } 95 96 constructor()97 private MethodSpec constructor() { 98 MethodSpec.Builder constructor = MethodSpec.constructorBuilder(); 99 for (RootMetadata rootMetadata : rootMetadatas) { 100 ClassName testName = rootMetadata.testRootMetadata().testName(); 101 ClassName testComponentDataHolderName = 102 Processors.append(Processors.getEnclosedClassName(testName), "_ComponentDataHolder"); 103 constructor.addStatement( 104 "testComponentDataMap.put($T.class, $T.get())", 105 testName, 106 testComponentDataHolderName); 107 } 108 return constructor.build(); 109 } 110 getMethod()111 private MethodSpec getMethod() { 112 return MethodSpec.methodBuilder("get") 113 .addAnnotation(Override.class) 114 .addModifiers(PROTECTED) 115 .returns(TEST_COMPONENT_DATA_MAP_TYPE) 116 .addStatement("return testComponentDataMap") 117 .build(); 118 } 119 } 120