• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.SourceFiles.generatedClassNameForBinding;
21 import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
22 import static dagger.internal.codegen.model.BindingKind.ASSISTED_FACTORY;
23 import static dagger.internal.codegen.model.BindingKind.INJECTION;
24 import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
25 
26 import androidx.room.compiler.processing.XMethodElement;
27 import androidx.room.compiler.processing.XProcessingEnv;
28 import androidx.room.compiler.processing.XTypeElement;
29 import com.squareup.javapoet.ClassName;
30 import com.squareup.javapoet.CodeBlock;
31 import dagger.assisted.Assisted;
32 import dagger.assisted.AssistedFactory;
33 import dagger.assisted.AssistedInject;
34 import dagger.internal.codegen.binding.ContributionBinding;
35 import dagger.internal.codegen.javapoet.CodeBlocks;
36 import dagger.internal.codegen.javapoet.TypeNames;
37 import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
38 import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
39 import java.util.Optional;
40 import javax.inject.Provider;
41 
42 /**
43  * A {@link Provider} creation expression for an {@link javax.inject.Inject @Inject}-constructed
44  * class or a {@link dagger.Provides @Provides}-annotated module method.
45  */
46 // TODO(dpb): Resolve with ProducerCreationExpression.
47 final class InjectionOrProvisionProviderCreationExpression
48     implements FrameworkInstanceCreationExpression {
49 
50   private final ContributionBinding binding;
51   private final ShardImplementation shardImplementation;
52   private final ComponentRequestRepresentations componentRequestRepresentations;
53   private final XProcessingEnv processingEnv;
54 
55   @AssistedInject
InjectionOrProvisionProviderCreationExpression( @ssisted ContributionBinding binding, ComponentImplementation componentImplementation, ComponentRequestRepresentations componentRequestRepresentations, XProcessingEnv processingEnv)56   InjectionOrProvisionProviderCreationExpression(
57       @Assisted ContributionBinding binding,
58       ComponentImplementation componentImplementation,
59       ComponentRequestRepresentations componentRequestRepresentations,
60       XProcessingEnv processingEnv) {
61     this.binding = checkNotNull(binding);
62     this.shardImplementation = componentImplementation.shardImplementation(binding);
63     this.componentRequestRepresentations = componentRequestRepresentations;
64     this.processingEnv = processingEnv;
65   }
66 
67   @Override
creationExpression()68   public CodeBlock creationExpression() {
69     ClassName factoryImpl = generatedClassNameForBinding(binding);
70     CodeBlock createFactory =
71         CodeBlock.of(
72             "$T.$L($L)",
73             factoryImpl,
74             // A different name is used for assisted factories due to backwards compatibility
75             // issues when migrating from the javax Provider.
76             binding.kind().equals(ASSISTED_FACTORY) ? "createFactoryProvider" : "create",
77             componentRequestRepresentations.getCreateMethodArgumentsCodeBlock(
78                 binding, shardImplementation.name()));
79 
80     // If this is for an AssistedFactory, then we may need to change the call in case we're building
81     // against a library built at an older version of Dagger before the changes to make factories
82     // return a Dagger Provider instead of a javax.inject.Provider.
83     if (binding.kind().equals(ASSISTED_FACTORY)) {
84       XTypeElement factoryType = processingEnv.findTypeElement(factoryImpl);
85       // If we can't find the factory, then assume it is being generated this run, which means
86       // it should be the newer version and not need wrapping. If it is missing for some other
87       // reason, then that likely means there will just be some other compilation failure.
88       if (factoryType != null) {
89         Optional<XMethodElement> createMethod = factoryType.getDeclaredMethods().stream()
90             .filter(method -> method.isStatic()
91                 && getSimpleName(method).equals("createFactoryProvider"))
92             .collect(toOptional());
93         // Only convert it if the newer method doesn't exist.
94         if (createMethod.isEmpty()) {
95           createFactory = CodeBlock.of(
96             "$T.asDaggerProvider($T.create($L))",
97             TypeNames.DAGGER_PROVIDERS,
98             factoryImpl,
99             componentRequestRepresentations.getCreateMethodArgumentsCodeBlock(
100                 binding, shardImplementation.name()));
101         }
102       }
103     }
104 
105     // When scoping a parameterized factory for an @Inject class, Java 7 cannot always infer the
106     // type properly, so cast to a raw framework type before scoping.
107     if (binding.kind().equals(INJECTION)
108         && binding.unresolved().isPresent()
109         && binding.scope().isPresent()) {
110       return CodeBlocks.cast(createFactory, TypeNames.DAGGER_PROVIDER);
111     } else {
112       return createFactory;
113     }
114   }
115 
116   @AssistedFactory
117   static interface Factory {
create(ContributionBinding binding)118     InjectionOrProvisionProviderCreationExpression create(ContributionBinding binding);
119   }
120 }
121