1 /* 2 * Copyright (C) 2015 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.internal.codegen.writing; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 import static dagger.internal.codegen.binding.MapKeys.getMapKeyExpression; 21 import static dagger.internal.codegen.binding.SourceFiles.mapFactoryClassName; 22 import static dagger.internal.codegen.extension.DaggerCollectors.toOptional; 23 24 import androidx.room.compiler.processing.XProcessingEnv; 25 import com.squareup.javapoet.ClassName; 26 import com.squareup.javapoet.CodeBlock; 27 import com.squareup.javapoet.TypeName; 28 import dagger.assisted.Assisted; 29 import dagger.assisted.AssistedFactory; 30 import dagger.assisted.AssistedInject; 31 import dagger.internal.codegen.base.MapType; 32 import dagger.internal.codegen.binding.BindingGraph; 33 import dagger.internal.codegen.binding.ContributionBinding; 34 import dagger.internal.codegen.binding.MapKeys; 35 import dagger.internal.codegen.javapoet.TypeNames; 36 import dagger.internal.codegen.model.DependencyRequest; 37 import java.util.stream.Stream; 38 39 /** A factory creation expression for a multibound map. */ 40 final class MapFactoryCreationExpression extends MultibindingFactoryCreationExpression { 41 42 private final XProcessingEnv processingEnv; 43 private final ComponentImplementation componentImplementation; 44 private final BindingGraph graph; 45 private final ContributionBinding binding; 46 private final boolean useLazyClassKey; 47 private final LazyClassKeyProviders lazyClassKeyProviders; 48 49 @AssistedInject MapFactoryCreationExpression( @ssisted ContributionBinding binding, XProcessingEnv processingEnv, ComponentImplementation componentImplementation, ComponentRequestRepresentations componentRequestRepresentations, BindingGraph graph)50 MapFactoryCreationExpression( 51 @Assisted ContributionBinding binding, 52 XProcessingEnv processingEnv, 53 ComponentImplementation componentImplementation, 54 ComponentRequestRepresentations componentRequestRepresentations, 55 BindingGraph graph) { 56 super(binding, componentImplementation, componentRequestRepresentations); 57 this.processingEnv = processingEnv; 58 this.binding = checkNotNull(binding); 59 this.componentImplementation = componentImplementation; 60 this.graph = graph; 61 this.useLazyClassKey = MapKeys.useLazyClassKey(binding, graph); 62 this.lazyClassKeyProviders = 63 componentImplementation.shardImplementation(binding).getLazyClassKeyProviders(); 64 } 65 66 @Override creationExpression()67 public CodeBlock creationExpression() { 68 ClassName mapFactoryClassName = mapFactoryClassName(binding); 69 CodeBlock.Builder builder = CodeBlock.builder().add("$T.", mapFactoryClassName); 70 TypeName valueTypeName = TypeName.OBJECT; 71 if (!useRawType()) { 72 MapType mapType = MapType.from(binding.key()); 73 // TODO(ronshapiro): either inline this into mapFactoryClassName, or add a 74 // mapType.unwrappedValueType() method that doesn't require a framework type 75 valueTypeName = 76 Stream.of(TypeNames.PROVIDER, TypeNames.PRODUCER, TypeNames.PRODUCED) 77 .filter(mapType::valuesAreTypeOf) 78 .map(mapType::unwrappedValueType) 79 .collect(toOptional()) 80 .orElseGet(mapType::valueType) 81 .getTypeName(); 82 builder.add( 83 "<$T, $T>", 84 useLazyClassKey ? TypeNames.STRING : mapType.keyType().getTypeName(), 85 valueTypeName); 86 } 87 88 builder.add("builder($L)", binding.dependencies().size()); 89 90 for (DependencyRequest dependency : binding.dependencies()) { 91 ContributionBinding contributionBinding = graph.contributionBinding(dependency.key()); 92 builder.add( 93 ".put($L, $L)", 94 useLazyClassKey 95 ? lazyClassKeyProviders.getMapKeyExpression(dependency.key()) 96 : getMapKeyExpression( 97 contributionBinding, componentImplementation.name(), processingEnv), 98 multibindingDependencyExpression(dependency)); 99 } 100 101 return useLazyClassKey 102 ? CodeBlock.of( 103 "$T.<$T>of($L)", 104 TypeNames.LAZY_CLASS_KEY_MAP_FACTORY, 105 valueTypeName, 106 builder.add(".build()").build()) 107 : builder.add(".build()").build(); 108 } 109 110 @AssistedFactory 111 static interface Factory { create(ContributionBinding binding)112 MapFactoryCreationExpression create(ContributionBinding binding); 113 } 114 } 115