1 /* 2 * Copyright (C) 2019 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.definecomponent; 18 19 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList; 20 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; 21 22 import androidx.room.compiler.processing.XTypeElement; 23 import com.google.common.collect.ArrayListMultimap; 24 import com.google.common.collect.ImmutableSet; 25 import com.google.common.collect.ListMultimap; 26 import dagger.hilt.processor.internal.ClassNames; 27 import dagger.hilt.processor.internal.ComponentDescriptor; 28 import dagger.hilt.processor.internal.ProcessorErrors; 29 import dagger.hilt.processor.internal.definecomponent.DefineComponentBuilderMetadatas.DefineComponentBuilderMetadata; 30 import dagger.hilt.processor.internal.definecomponent.DefineComponentMetadatas.DefineComponentMetadata; 31 import dagger.internal.codegen.xprocessing.XElements; 32 import java.util.LinkedHashMap; 33 import java.util.Map; 34 35 /** 36 * A utility class for getting {@link DefineComponentMetadata} and {@link 37 * DefineComponentBuilderMetadata}. 38 */ 39 public final class DefineComponents { create()40 public static DefineComponents create() { 41 return new DefineComponents(); 42 } 43 44 private final DefineComponentMetadatas componentMetadatas = DefineComponentMetadatas.create(); 45 private final DefineComponentBuilderMetadatas componentBuilderMetadatas = 46 DefineComponentBuilderMetadatas.create(componentMetadatas); 47 DefineComponents()48 private DefineComponents() {} 49 50 /** Returns the set of aggregated {@link ComponentDescriptor}s. */ getComponentDescriptors( ImmutableSet<DefineComponentClassesMetadata> aggregatedMetadatas)51 public ImmutableSet<ComponentDescriptor> getComponentDescriptors( 52 ImmutableSet<DefineComponentClassesMetadata> aggregatedMetadatas) { 53 ImmutableSet<DefineComponentMetadata> components = 54 aggregatedMetadatas.stream() 55 .filter(DefineComponentClassesMetadata::isComponent) 56 .map(DefineComponentClassesMetadata::element) 57 .map(componentMetadatas::get) 58 .collect(toImmutableSet()); 59 60 ImmutableSet<DefineComponentBuilderMetadata> builders = 61 aggregatedMetadatas.stream() 62 .filter(DefineComponentClassesMetadata::isComponentBuilder) 63 .map(DefineComponentClassesMetadata::element) 64 .map(componentBuilderMetadatas::get) 65 .collect(toImmutableSet()); 66 67 ListMultimap<DefineComponentMetadata, DefineComponentBuilderMetadata> builderMultimap = 68 ArrayListMultimap.create(); 69 builders.forEach(builder -> builderMultimap.put(builder.componentMetadata(), builder)); 70 71 // Check that there are not multiple builders per component 72 for (DefineComponentMetadata componentMetadata : builderMultimap.keySet()) { 73 XTypeElement component = componentMetadata.component(); 74 ProcessorErrors.checkState( 75 builderMultimap.get(componentMetadata).size() <= 1, 76 component, 77 "Multiple @%s declarations are not allowed for @%s type, %s. Found: %s", 78 ClassNames.DEFINE_COMPONENT_BUILDER, 79 ClassNames.DEFINE_COMPONENT, 80 XElements.toStableString(component), 81 builderMultimap.get(componentMetadata).stream() 82 .map(DefineComponentBuilderMetadata::builder) 83 .map(XTypeElement::getQualifiedName) 84 .sorted() 85 .collect(toImmutableList())); 86 } 87 88 // Now that we know there is at most 1 builder per component, convert the Multimap to Map. 89 Map<DefineComponentMetadata, DefineComponentBuilderMetadata> builderMap = new LinkedHashMap<>(); 90 builderMultimap.entries().forEach(e -> builderMap.put(e.getKey(), e.getValue())); 91 92 return components.stream() 93 .map(componentMetadata -> toComponentDescriptor(componentMetadata, builderMap)) 94 .collect(toImmutableSet()); 95 } 96 toComponentDescriptor( DefineComponentMetadata componentMetadata, Map<DefineComponentMetadata, DefineComponentBuilderMetadata> builderMap)97 private static ComponentDescriptor toComponentDescriptor( 98 DefineComponentMetadata componentMetadata, 99 Map<DefineComponentMetadata, DefineComponentBuilderMetadata> builderMap) { 100 ComponentDescriptor.Builder builder = 101 ComponentDescriptor.builder() 102 .component(componentMetadata.component().getClassName()) 103 .scopes( 104 componentMetadata.scopes().stream() 105 .map(XTypeElement::getClassName) 106 .collect(toImmutableSet())); 107 108 109 if (builderMap.containsKey(componentMetadata)) { 110 builder.creator(builderMap.get(componentMetadata).builder().getClassName()); 111 } 112 113 componentMetadata 114 .parentMetadata() 115 .map(parent -> toComponentDescriptor(parent, builderMap)) 116 .ifPresent(builder::parent); 117 118 return builder.build(); 119 } 120 } 121