Skip to content

Commit 0322eb5

Browse files
netdpbronshapiro
authored andcommitted
Use InstanceFactory for absent optional providers.
Move state management for which classes and methods have been added from AbstractComponentWriter to OptionalFactories. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=132000312
1 parent a4bb781 commit 0322eb5

File tree

5 files changed

+146
-117
lines changed

5 files changed

+146
-117
lines changed

compiler/src/main/java/dagger/internal/codegen/AbstractComponentWriter.java

+34-42
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import static com.google.common.collect.Iterables.getOnlyElement;
2424
import static com.squareup.javapoet.MethodSpec.constructorBuilder;
2525
import static com.squareup.javapoet.MethodSpec.methodBuilder;
26+
import static com.squareup.javapoet.TypeSpec.classBuilder;
2627
import static dagger.internal.codegen.AbstractComponentWriter.InitializationState.DELEGATED;
2728
import static dagger.internal.codegen.AbstractComponentWriter.InitializationState.INITIALIZED;
2829
import static dagger.internal.codegen.AbstractComponentWriter.InitializationState.UNINITIALIZED;
@@ -140,13 +141,15 @@ abstract class AbstractComponentWriter {
140141
protected final BindingGraph graph;
141142
protected final ImmutableMap<ComponentDescriptor, String> subcomponentNames;
142143
private final Map<BindingKey, InitializationState> initializationStates = new HashMap<>();
143-
protected TypeSpec.Builder component;
144+
protected final TypeSpec.Builder component;
144145
private final UniqueNameSet componentFieldNames = new UniqueNameSet();
145146
private final Map<BindingKey, MemberSelect> memberSelects = new HashMap<>();
146147
private final Map<BindingKey, MemberSelect> producerFromProviderMemberSelects = new HashMap<>();
147148
private final Map<BindingKey, RequestFulfillment> requestFulfillments = Maps.newLinkedHashMap();
148149
protected final MethodSpec.Builder constructor = constructorBuilder().addModifiers(PRIVATE);
149150
protected Optional<ClassName> builderName = Optional.absent();
151+
private final OptionalFactories optionalFactories;
152+
private boolean done;
150153

151154
/**
152155
* For each component requirement, the builder field. This map is empty for subcomponents that do
@@ -162,28 +165,37 @@ abstract class AbstractComponentWriter {
162165
*/
163166
protected final Map<TypeElement, MemberSelect> componentContributionFields = Maps.newHashMap();
164167

165-
/**
166-
* The factory classes that implement {@code Provider<Optional<T>>} within the component. If the
167-
* key is {@link Optional#absent()}, the class provides absent values.
168-
*/
169-
private final Map<Optional<DependencyRequest.Kind>, TypeSpec> optionalFactoryClasses =
170-
new HashMap<>();
171-
172168
AbstractComponentWriter(
173169
Types types,
174170
Elements elements,
175171
Key.Factory keyFactory,
176172
CompilerOptions compilerOptions,
177173
ClassName name,
178174
BindingGraph graph,
179-
ImmutableMap<ComponentDescriptor, String> subcomponentNames) {
175+
ImmutableMap<ComponentDescriptor, String> subcomponentNames,
176+
OptionalFactories optionalFactories) {
180177
this.types = types;
181178
this.elements = elements;
182179
this.keyFactory = keyFactory;
183180
this.compilerOptions = compilerOptions;
181+
this.component = classBuilder(name);
184182
this.name = name;
185183
this.graph = graph;
186184
this.subcomponentNames = subcomponentNames;
185+
this.optionalFactories = optionalFactories;
186+
}
187+
188+
protected AbstractComponentWriter(
189+
AbstractComponentWriter parent, ClassName name, BindingGraph graph) {
190+
this(
191+
parent.types,
192+
parent.elements,
193+
parent.keyFactory,
194+
parent.compilerOptions,
195+
name,
196+
graph,
197+
parent.subcomponentNames,
198+
parent.optionalFactories);
187199
}
188200

189201
protected final TypeElement componentDefinitionType() {
@@ -267,22 +279,27 @@ private void setInitializationState(BindingKey bindingKey, InitializationState s
267279
* component must be regenerated, use a new instance.
268280
*/
269281
final TypeSpec.Builder write() {
270-
checkState(component == null, "ComponentWriter has already been generated.");
271-
component = createComponentClass();
282+
checkState(!done, "ComponentWriter has already been generated.");
283+
decorateComponent();
272284
addBuilder();
273285
addFactoryMethods();
274286
addFrameworkFields();
275287
initializeFrameworkTypes();
276288
implementInterfaceMethods();
277289
addSubcomponents();
278290
component.addMethod(constructor.build());
291+
if (graph.componentDescriptor().kind().isTopLevel()) {
292+
optionalFactories.addMembers(component);
293+
}
294+
done = true;
279295
return component;
280296
}
281297

282298
/**
283-
* Creates the component implementation class.
299+
* Adds Javadoc, modifiers, supertypes, and annotations to the component implementation class
300+
* declaration.
284301
*/
285-
protected abstract TypeSpec.Builder createComponentClass();
302+
protected abstract void decorateComponent();
286303

287304
/**
288305
* Adds a builder type.
@@ -737,7 +754,7 @@ private void implementInterfaceMethods() {
737754
}
738755
}
739756

740-
public MethodSpec.Builder methodSpecForComponentMethod(
757+
private MethodSpec.Builder methodSpecForComponentMethod(
741758
ExecutableElement method, ExecutableType methodType) {
742759
String methodName = method.getSimpleName().toString();
743760
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(methodName);
@@ -1279,41 +1296,16 @@ private CodeBlock initializeFactoryForSyntheticOptionalBinding(ContributionBindi
12791296
}
12801297

12811298
if (binding.dependencies().isEmpty()) {
1282-
return CodeBlock.of(
1283-
"$N.instance()", optionalFactoryClass(Optional.<DependencyRequest.Kind>absent()));
1299+
return optionalFactories.absentOptionalProvider();
12841300
} else {
12851301
TypeMirror valueType = OptionalType.from(binding.key()).valueType();
1286-
DependencyRequest.Kind optionalValueKind =
1287-
DependencyRequest.extractKindAndType(valueType).kind();
1302+
DependencyRequest.Kind valueKind = DependencyRequest.extractKindAndType(valueType).kind();
12881303
FrameworkDependency frameworkDependency =
12891304
getOnlyElement(frameworkDependenciesForBinding(binding));
12901305
CodeBlock dependencyArgument =
12911306
getDependencyArgument(frameworkDependency).getExpressionFor(name);
1292-
return CodeBlock.of(
1293-
"$N.of($L)", optionalFactoryClass(Optional.of(optionalValueKind)), dependencyArgument);
1294-
}
1295-
}
1296-
1297-
/**
1298-
* Returns the nested class that implements {@code Provider<Optional<T>>} for optional bindings.
1299-
* Adds it to the root component if it hasn't already been added.
1300-
*
1301-
* <p>If {@code optionalValueKind} is absent, returns a {@link Provider} class that returns {@link
1302-
* Optional#absent()}.
1303-
*
1304-
* <p>If {@code optionalValueKind} is present, returns a {@link Provider} class where {@code T}
1305-
* represents dependency requests of that kind.
1306-
*/
1307-
protected TypeSpec optionalFactoryClass(Optional<DependencyRequest.Kind> optionalValueKind) {
1308-
if (!optionalFactoryClasses.containsKey(optionalValueKind)) {
1309-
TypeSpec factory =
1310-
optionalValueKind.isPresent()
1311-
? OptionalFactoryClasses.presentFactoryClass(optionalValueKind.get())
1312-
: OptionalFactoryClasses.ABSENT_FACTORY_CLASS;
1313-
component.addType(factory);
1314-
optionalFactoryClasses.put(optionalValueKind, factory);
1307+
return optionalFactories.presentOptionalProvider(valueKind, dependencyArgument);
13151308
}
1316-
return optionalFactoryClasses.get(optionalValueKind);
13171309
}
13181310

13191311
private static String simpleVariableName(TypeElement typeElement) {

compiler/src/main/java/dagger/internal/codegen/ComponentWriter.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ final class ComponentWriter extends AbstractComponentWriter {
6464
compilerOptions,
6565
name,
6666
graph,
67-
new UniqueSubcomponentNamesGenerator(graph).generate());
67+
new UniqueSubcomponentNamesGenerator(graph).generate(),
68+
new OptionalFactories());
6869
}
6970

7071
/**
@@ -142,10 +143,9 @@ private static ImmutableListMultimap<ComponentDescriptor, String> qualifiedNames
142143
}
143144

144145
@Override
145-
protected TypeSpec.Builder createComponentClass() {
146-
TypeSpec.Builder component = classBuilder(name).addModifiers(PUBLIC, FINAL);
146+
protected void decorateComponent() {
147+
component.addModifiers(PUBLIC, FINAL);
147148
addSupertype(component, componentDefinitionType());
148-
return component;
149149
}
150150

151151
@Override

compiler/src/main/java/dagger/internal/codegen/OptionalFactoryClasses.java compiler/src/main/java/dagger/internal/codegen/OptionalFactories.java

+97-47
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import static com.squareup.javapoet.TypeSpec.classBuilder;
2424
import static dagger.internal.codegen.AnnotationSpecs.SUPPRESS_WARNINGS_RAWTYPES;
2525
import static dagger.internal.codegen.AnnotationSpecs.SUPPRESS_WARNINGS_UNCHECKED;
26+
import static dagger.internal.codegen.TypeNames.PROVIDER;
2627
import static dagger.internal.codegen.TypeNames.lazyOf;
2728
import static dagger.internal.codegen.TypeNames.optionalOf;
2829
import static dagger.internal.codegen.TypeNames.providerOf;
@@ -34,59 +35,87 @@
3435
import com.google.common.base.Optional;
3536
import com.squareup.javapoet.CodeBlock;
3637
import com.squareup.javapoet.FieldSpec;
38+
import com.squareup.javapoet.MethodSpec;
3739
import com.squareup.javapoet.ParameterSpec;
3840
import com.squareup.javapoet.ParameterizedTypeName;
3941
import com.squareup.javapoet.TypeName;
4042
import com.squareup.javapoet.TypeSpec;
4143
import com.squareup.javapoet.TypeVariableName;
44+
import dagger.internal.InstanceFactory;
4245
import dagger.internal.Preconditions;
46+
import java.util.EnumMap;
47+
import java.util.Map;
4348
import javax.inject.Provider;
4449

45-
/** Factory class specifications for optional bindings. */
50+
/**
51+
* The nested class and static methods required by the component to implement optional bindings.
52+
*/
4653
// TODO(dpb): Name classes correctly if a component uses both Guava and JDK Optional.
47-
final class OptionalFactoryClasses {
54+
final class OptionalFactories {
4855

4956
/**
50-
* The class specification for a {@link Provider<Optional<T>>} that always returns {@code
57+
* A field specification for a {@link Provider<Optional<T>>} that always returns {@code
5158
* Optional.absent()}.
5259
*/
53-
static final TypeSpec ABSENT_FACTORY_CLASS = absentFactoryClass();
60+
private static final FieldSpec ABSENT_OPTIONAL_PROVIDER_FIELD =
61+
FieldSpec.builder(PROVIDER, "ABSENT_OPTIONAL_PROVIDER", PRIVATE, STATIC, FINAL)
62+
.addAnnotation(SUPPRESS_WARNINGS_RAWTYPES)
63+
.initializer("$T.create($T.absent())", InstanceFactory.class, Optional.class)
64+
.addJavadoc(
65+
"A {@link $T} that returns {@code $T.absent()}.", Provider.class, Optional.class)
66+
.build();
5467

55-
private static TypeSpec absentFactoryClass() {
56-
String className = "AbsentOptionalFactory";
57-
TypeVariableName typeVariable = TypeVariableName.get("T");
58-
59-
return classBuilder(className)
60-
.addTypeVariable(typeVariable)
61-
.addModifiers(PRIVATE, STATIC, FINAL)
62-
.addSuperinterface(providerOf(optionalOf(typeVariable)))
63-
.addJavadoc("A {@link $T} that returns {$T.absent()}.", Provider.class, Optional.class)
64-
.addField(FieldSpec.builder(Provider.class, "INSTANCE", PRIVATE, STATIC, FINAL)
65-
.addAnnotation(SUPPRESS_WARNINGS_RAWTYPES)
66-
.initializer("new $L()", className)
67-
.build())
68-
.addMethod(
69-
methodBuilder("instance")
70-
.addModifiers(PRIVATE, STATIC)
71-
.addTypeVariable(typeVariable)
72-
.returns(providerOf(optionalOf(typeVariable)))
73-
.addCode("$L // safe covariant cast\n", SUPPRESS_WARNINGS_UNCHECKED)
74-
.addCode("$1T provider = ($1T) INSTANCE;", providerOf(optionalOf(typeVariable)))
75-
.addCode("return provider;")
76-
.build())
77-
.addMethod(
78-
methodBuilder("get")
79-
.addAnnotation(Override.class)
80-
.addModifiers(PUBLIC)
81-
.returns(optionalOf(typeVariable))
82-
.addCode("return $T.absent();", Optional.class)
83-
.build())
84-
.build();
68+
/**
69+
* A method specification for a {@link Provider<Optional<T>>} that always returns {@code
70+
* Optional.absent()}.
71+
*/
72+
private static final MethodSpec ABSENT_OPTIONAL_PROVIDER_METHOD =
73+
methodBuilder("absentOptionalProvider")
74+
.addModifiers(PRIVATE, STATIC)
75+
.addTypeVariable(TypeVariableName.get("T"))
76+
.returns(providerOf(optionalOf(TypeVariableName.get("T"))))
77+
.addJavadoc(
78+
"Returns a {@link $T} that returns {@code $T.absent()}.",
79+
Provider.class,
80+
Optional.class)
81+
.addCode("$L // safe covariant cast\n", SUPPRESS_WARNINGS_UNCHECKED)
82+
.addCode(
83+
"$1T provider = ($1T) $2N;",
84+
providerOf(optionalOf(TypeVariableName.get("T"))),
85+
ABSENT_OPTIONAL_PROVIDER_FIELD)
86+
.addCode("return provider;")
87+
.build();
88+
89+
/**
90+
* The factory classes that implement present optional bindings for a given kind of dependency
91+
* request within the component.
92+
*/
93+
private final Map<DependencyRequest.Kind, TypeSpec> presentFactoryClasses =
94+
new EnumMap<>(DependencyRequest.Kind.class);
95+
96+
/**
97+
* If the component contains any absent optional bindings, this will be the member select for a
98+
* static method that returns a Provider<Optional<T>> that always returns {@link
99+
* Optional#absent()}.
100+
*/
101+
private Optional<CodeBlock> absentOptionalProviderMethod = Optional.absent();
102+
103+
/**
104+
* Returns an expression that calls a static method that returns a {@code Provider<Optional<T>>}
105+
* for absent optional bindings.
106+
*/
107+
CodeBlock absentOptionalProvider() {
108+
if (!absentOptionalProviderMethod.isPresent()) {
109+
absentOptionalProviderMethod =
110+
Optional.of(CodeBlock.of("$N()", ABSENT_OPTIONAL_PROVIDER_METHOD));
111+
}
112+
return absentOptionalProviderMethod.get();
85113
}
86114

87115
/**
88-
* Returns the class specification for a {@link Provider} that returns a present value. The class
89-
* is generic in {@code T}.
116+
* Returns an expression for an instance of a nested class that implements {@code
117+
* Provider<Optional<T>>} for a present optional binding, where {@code T} represents dependency
118+
* requests of that kind.
90119
*
91120
* <ul>
92121
* <li>If {@code optionalRequestKind} is {@link DependencyRequest.Kind#INSTANCE}, the class
@@ -100,23 +129,44 @@ private static TypeSpec absentFactoryClass() {
100129
* </ul>
101130
*
102131
* <p>Production requests are not yet supported.
132+
*
133+
* @param delegateProvider an expression for a {@link Provider} of the underlying type
134+
*/
135+
CodeBlock presentOptionalProvider(DependencyRequest.Kind valueKind, CodeBlock delegateProvider) {
136+
if (!presentFactoryClasses.containsKey(valueKind)) {
137+
presentFactoryClasses.put(valueKind, createPresentFactoryClass(valueKind));
138+
}
139+
return CodeBlock.of("$N.of($L)", presentFactoryClasses.get(valueKind), delegateProvider);
140+
}
141+
142+
/**
143+
* Adds classes and methods required by previous calls to {@link #absentOptionalProvider()} and
144+
* {@link #presentOptionalProvider(DependencyRequest.Kind, CodeBlock)} to the top-level {@code
145+
* component}.
103146
*/
104-
static TypeSpec presentFactoryClass(DependencyRequest.Kind optionalValueKind) {
147+
void addMembers(TypeSpec.Builder component) {
148+
if (absentOptionalProviderMethod.isPresent()) {
149+
component.addField(ABSENT_OPTIONAL_PROVIDER_FIELD).addMethod(ABSENT_OPTIONAL_PROVIDER_METHOD);
150+
}
151+
for (TypeSpec presentFactoryClass : presentFactoryClasses.values()) {
152+
component.addType(presentFactoryClass);
153+
}
154+
}
155+
156+
private TypeSpec createPresentFactoryClass(DependencyRequest.Kind valueKind) {
105157
String factoryClassName =
106158
String.format(
107-
"PresentOptional%sFactory",
108-
UPPER_UNDERSCORE.to(UPPER_CAMEL, optionalValueKind.toString()));
109-
159+
"PresentOptional%sFactory", UPPER_UNDERSCORE.to(UPPER_CAMEL, valueKind.toString()));
160+
110161
TypeVariableName typeVariable = TypeVariableName.get("T");
111-
162+
112163
FieldSpec providerField =
113164
FieldSpec.builder(providerOf(typeVariable), "provider", PRIVATE, FINAL).build();
114-
165+
115166
ParameterSpec providerParameter =
116167
ParameterSpec.builder(providerOf(typeVariable), "provider").build();
117-
118-
ParameterizedTypeName optionalType = optionalType(optionalValueKind, typeVariable);
119-
168+
169+
ParameterizedTypeName optionalType = optionalType(valueKind, typeVariable);
120170
return classBuilder(factoryClassName)
121171
.addTypeVariable(typeVariable)
122172
.addModifiers(PRIVATE, STATIC, FINAL)
@@ -144,7 +194,7 @@ static TypeSpec presentFactoryClass(DependencyRequest.Kind optionalValueKind) {
144194
.addCode(
145195
"return $T.of($L);",
146196
Optional.class,
147-
FrameworkType.PROVIDER.to(optionalValueKind, CodeBlock.of("$N", providerField)))
197+
FrameworkType.PROVIDER.to(valueKind, CodeBlock.of("$N", providerField)))
148198
.build())
149199
.addMethod(
150200
methodBuilder("of")
@@ -157,7 +207,7 @@ static TypeSpec presentFactoryClass(DependencyRequest.Kind optionalValueKind) {
157207
.build();
158208
}
159209

160-
private static ParameterizedTypeName optionalType(
210+
private ParameterizedTypeName optionalType(
161211
DependencyRequest.Kind optionalValueKind, TypeName valueType) {
162212
switch (optionalValueKind) {
163213
case INSTANCE:

0 commit comments

Comments
 (0)