>} for optional bindings.
- * Adds it to the root component if it hasn't already been added.
- *
- * If {@code optionalValueKind} is absent, returns a {@link Provider} class that returns {@link
- * Optional#absent()}.
- *
- *
If {@code optionalValueKind} is present, returns a {@link Provider} class where {@code T}
- * represents dependency requests of that kind.
- */
- protected TypeSpec optionalFactoryClass(Optional optionalValueKind) {
- if (!optionalFactoryClasses.containsKey(optionalValueKind)) {
- TypeSpec factory =
- optionalValueKind.isPresent()
- ? OptionalFactoryClasses.presentFactoryClass(optionalValueKind.get())
- : OptionalFactoryClasses.ABSENT_FACTORY_CLASS;
- component.addType(factory);
- optionalFactoryClasses.put(optionalValueKind, factory);
+ return optionalFactories.presentOptionalProvider(valueKind, dependencyArgument);
}
- return optionalFactoryClasses.get(optionalValueKind);
}
private static String simpleVariableName(TypeElement typeElement) {
diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentWriter.java b/compiler/src/main/java/dagger/internal/codegen/ComponentWriter.java
index 1237643facf..f14e3ffbce5 100644
--- a/compiler/src/main/java/dagger/internal/codegen/ComponentWriter.java
+++ b/compiler/src/main/java/dagger/internal/codegen/ComponentWriter.java
@@ -64,7 +64,8 @@ final class ComponentWriter extends AbstractComponentWriter {
compilerOptions,
name,
graph,
- new UniqueSubcomponentNamesGenerator(graph).generate());
+ new UniqueSubcomponentNamesGenerator(graph).generate(),
+ new OptionalFactories());
}
/**
@@ -142,10 +143,9 @@ private static ImmutableListMultimap qualifiedNames
}
@Override
- protected TypeSpec.Builder createComponentClass() {
- TypeSpec.Builder component = classBuilder(name).addModifiers(PUBLIC, FINAL);
+ protected void decorateComponent() {
+ component.addModifiers(PUBLIC, FINAL);
addSupertype(component, componentDefinitionType());
- return component;
}
@Override
diff --git a/compiler/src/main/java/dagger/internal/codegen/MemberSelect.java b/compiler/src/main/java/dagger/internal/codegen/MemberSelect.java
index 99f5ead6fa9..015ad36bf6b 100644
--- a/compiler/src/main/java/dagger/internal/codegen/MemberSelect.java
+++ b/compiler/src/main/java/dagger/internal/codegen/MemberSelect.java
@@ -26,7 +26,6 @@
import static dagger.internal.codegen.TypeNames.MAP_PROVIDER_FACTORY;
import static dagger.internal.codegen.TypeNames.MEMBERS_INJECTOR;
import static dagger.internal.codegen.TypeNames.MEMBERS_INJECTORS;
-import static dagger.internal.codegen.TypeNames.SET;
import com.google.common.collect.ImmutableList;
import com.squareup.javapoet.ClassName;
@@ -144,10 +143,7 @@ static MemberSelect emptyFrameworkMapFactory(
*/
static MemberSelect emptySetProvider(ClassName setFactoryType, SetType setType) {
return new ParameterizedStaticMethod(
- setFactoryType,
- ImmutableList.of(setType.elementType()),
- CodeBlock.of("empty()"),
- SET);
+ setFactoryType, ImmutableList.of(setType.elementType()), CodeBlock.of("empty()"), FACTORY);
}
private static final class ParameterizedStaticMethod extends MemberSelect {
diff --git a/compiler/src/main/java/dagger/internal/codegen/OptionalFactoryClasses.java b/compiler/src/main/java/dagger/internal/codegen/OptionalFactories.java
similarity index 54%
rename from compiler/src/main/java/dagger/internal/codegen/OptionalFactoryClasses.java
rename to compiler/src/main/java/dagger/internal/codegen/OptionalFactories.java
index c40a725607c..d9a03cbc2cc 100644
--- a/compiler/src/main/java/dagger/internal/codegen/OptionalFactoryClasses.java
+++ b/compiler/src/main/java/dagger/internal/codegen/OptionalFactories.java
@@ -23,6 +23,7 @@
import static com.squareup.javapoet.TypeSpec.classBuilder;
import static dagger.internal.codegen.AnnotationSpecs.SUPPRESS_WARNINGS_RAWTYPES;
import static dagger.internal.codegen.AnnotationSpecs.SUPPRESS_WARNINGS_UNCHECKED;
+import static dagger.internal.codegen.TypeNames.PROVIDER;
import static dagger.internal.codegen.TypeNames.lazyOf;
import static dagger.internal.codegen.TypeNames.optionalOf;
import static dagger.internal.codegen.TypeNames.providerOf;
@@ -34,59 +35,87 @@
import com.google.common.base.Optional;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeVariableName;
+import dagger.internal.InstanceFactory;
import dagger.internal.Preconditions;
+import java.util.EnumMap;
+import java.util.Map;
import javax.inject.Provider;
-/** Factory class specifications for optional bindings. */
+/**
+ * The nested class and static methods required by the component to implement optional bindings.
+ */
// TODO(dpb): Name classes correctly if a component uses both Guava and JDK Optional.
-final class OptionalFactoryClasses {
+final class OptionalFactories {
/**
- * The class specification for a {@link Provider>} that always returns {@code
+ * A field specification for a {@link Provider>} that always returns {@code
* Optional.absent()}.
*/
- static final TypeSpec ABSENT_FACTORY_CLASS = absentFactoryClass();
+ private static final FieldSpec ABSENT_OPTIONAL_PROVIDER_FIELD =
+ FieldSpec.builder(PROVIDER, "ABSENT_OPTIONAL_PROVIDER", PRIVATE, STATIC, FINAL)
+ .addAnnotation(SUPPRESS_WARNINGS_RAWTYPES)
+ .initializer("$T.create($T.absent())", InstanceFactory.class, Optional.class)
+ .addJavadoc(
+ "A {@link $T} that returns {@code $T.absent()}.", Provider.class, Optional.class)
+ .build();
- private static TypeSpec absentFactoryClass() {
- String className = "AbsentOptionalFactory";
- TypeVariableName typeVariable = TypeVariableName.get("T");
-
- return classBuilder(className)
- .addTypeVariable(typeVariable)
- .addModifiers(PRIVATE, STATIC, FINAL)
- .addSuperinterface(providerOf(optionalOf(typeVariable)))
- .addJavadoc("A {@link $T} that returns {$T.absent()}.", Provider.class, Optional.class)
- .addField(FieldSpec.builder(Provider.class, "INSTANCE", PRIVATE, STATIC, FINAL)
- .addAnnotation(SUPPRESS_WARNINGS_RAWTYPES)
- .initializer("new $L()", className)
- .build())
- .addMethod(
- methodBuilder("instance")
- .addModifiers(PRIVATE, STATIC)
- .addTypeVariable(typeVariable)
- .returns(providerOf(optionalOf(typeVariable)))
- .addCode("$L // safe covariant cast\n", SUPPRESS_WARNINGS_UNCHECKED)
- .addCode("$1T provider = ($1T) INSTANCE;", providerOf(optionalOf(typeVariable)))
- .addCode("return provider;")
- .build())
- .addMethod(
- methodBuilder("get")
- .addAnnotation(Override.class)
- .addModifiers(PUBLIC)
- .returns(optionalOf(typeVariable))
- .addCode("return $T.absent();", Optional.class)
- .build())
- .build();
+ /**
+ * A method specification for a {@link Provider>} that always returns {@code
+ * Optional.absent()}.
+ */
+ private static final MethodSpec ABSENT_OPTIONAL_PROVIDER_METHOD =
+ methodBuilder("absentOptionalProvider")
+ .addModifiers(PRIVATE, STATIC)
+ .addTypeVariable(TypeVariableName.get("T"))
+ .returns(providerOf(optionalOf(TypeVariableName.get("T"))))
+ .addJavadoc(
+ "Returns a {@link $T} that returns {@code $T.absent()}.",
+ Provider.class,
+ Optional.class)
+ .addCode("$L // safe covariant cast\n", SUPPRESS_WARNINGS_UNCHECKED)
+ .addCode(
+ "$1T provider = ($1T) $2N;",
+ providerOf(optionalOf(TypeVariableName.get("T"))),
+ ABSENT_OPTIONAL_PROVIDER_FIELD)
+ .addCode("return provider;")
+ .build();
+
+ /**
+ * The factory classes that implement present optional bindings for a given kind of dependency
+ * request within the component.
+ */
+ private final Map presentFactoryClasses =
+ new EnumMap<>(DependencyRequest.Kind.class);
+
+ /**
+ * If the component contains any absent optional bindings, this will be the member select for a
+ * static method that returns a Provider> that always returns {@link
+ * Optional#absent()}.
+ */
+ private Optional absentOptionalProviderMethod = Optional.absent();
+
+ /**
+ * Returns an expression that calls a static method that returns a {@code Provider>}
+ * for absent optional bindings.
+ */
+ CodeBlock absentOptionalProvider() {
+ if (!absentOptionalProviderMethod.isPresent()) {
+ absentOptionalProviderMethod =
+ Optional.of(CodeBlock.of("$N()", ABSENT_OPTIONAL_PROVIDER_METHOD));
+ }
+ return absentOptionalProviderMethod.get();
}
/**
- * Returns the class specification for a {@link Provider} that returns a present value. The class
- * is generic in {@code T}.
+ * Returns an expression for an instance of a nested class that implements {@code
+ * Provider>} for a present optional binding, where {@code T} represents dependency
+ * requests of that kind.
*
*
* - If {@code optionalRequestKind} is {@link DependencyRequest.Kind#INSTANCE}, the class
@@ -100,23 +129,44 @@ private static TypeSpec absentFactoryClass() {
*
*
* Production requests are not yet supported.
+ *
+ * @param delegateProvider an expression for a {@link Provider} of the underlying type
+ */
+ CodeBlock presentOptionalProvider(DependencyRequest.Kind valueKind, CodeBlock delegateProvider) {
+ if (!presentFactoryClasses.containsKey(valueKind)) {
+ presentFactoryClasses.put(valueKind, createPresentFactoryClass(valueKind));
+ }
+ return CodeBlock.of("$N.of($L)", presentFactoryClasses.get(valueKind), delegateProvider);
+ }
+
+ /**
+ * Adds classes and methods required by previous calls to {@link #absentOptionalProvider()} and
+ * {@link #presentOptionalProvider(DependencyRequest.Kind, CodeBlock)} to the top-level {@code
+ * component}.
*/
- static TypeSpec presentFactoryClass(DependencyRequest.Kind optionalValueKind) {
+ void addMembers(TypeSpec.Builder component) {
+ if (absentOptionalProviderMethod.isPresent()) {
+ component.addField(ABSENT_OPTIONAL_PROVIDER_FIELD).addMethod(ABSENT_OPTIONAL_PROVIDER_METHOD);
+ }
+ for (TypeSpec presentFactoryClass : presentFactoryClasses.values()) {
+ component.addType(presentFactoryClass);
+ }
+ }
+
+ private TypeSpec createPresentFactoryClass(DependencyRequest.Kind valueKind) {
String factoryClassName =
String.format(
- "PresentOptional%sFactory",
- UPPER_UNDERSCORE.to(UPPER_CAMEL, optionalValueKind.toString()));
-
+ "PresentOptional%sFactory", UPPER_UNDERSCORE.to(UPPER_CAMEL, valueKind.toString()));
+
TypeVariableName typeVariable = TypeVariableName.get("T");
-
+
FieldSpec providerField =
FieldSpec.builder(providerOf(typeVariable), "provider", PRIVATE, FINAL).build();
-
+
ParameterSpec providerParameter =
ParameterSpec.builder(providerOf(typeVariable), "provider").build();
-
- ParameterizedTypeName optionalType = optionalType(optionalValueKind, typeVariable);
-
+
+ ParameterizedTypeName optionalType = optionalType(valueKind, typeVariable);
return classBuilder(factoryClassName)
.addTypeVariable(typeVariable)
.addModifiers(PRIVATE, STATIC, FINAL)
@@ -144,7 +194,7 @@ static TypeSpec presentFactoryClass(DependencyRequest.Kind optionalValueKind) {
.addCode(
"return $T.of($L);",
Optional.class,
- FrameworkType.PROVIDER.to(optionalValueKind, CodeBlock.of("$N", providerField)))
+ FrameworkType.PROVIDER.to(valueKind, CodeBlock.of("$N", providerField)))
.build())
.addMethod(
methodBuilder("of")
@@ -157,7 +207,7 @@ static TypeSpec presentFactoryClass(DependencyRequest.Kind optionalValueKind) {
.build();
}
- private static ParameterizedTypeName optionalType(
+ private ParameterizedTypeName optionalType(
DependencyRequest.Kind optionalValueKind, TypeName valueType) {
switch (optionalValueKind) {
case INSTANCE:
diff --git a/compiler/src/main/java/dagger/internal/codegen/SubcomponentWriter.java b/compiler/src/main/java/dagger/internal/codegen/SubcomponentWriter.java
index 5c87ab4d562..7a4b7155f51 100644
--- a/compiler/src/main/java/dagger/internal/codegen/SubcomponentWriter.java
+++ b/compiler/src/main/java/dagger/internal/codegen/SubcomponentWriter.java
@@ -42,7 +42,6 @@
import com.squareup.javapoet.TypeSpec;
import dagger.internal.Preconditions;
import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.internal.codegen.DependencyRequest.Kind;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.TypeElement;
@@ -67,14 +66,7 @@ final class SubcomponentWriter extends AbstractComponentWriter {
AbstractComponentWriter parent,
Optional subcomponentFactoryMethod,
BindingGraph subgraph) {
- super(
- parent.types,
- parent.elements,
- parent.keyFactory,
- parent.compilerOptions,
- subcomponentName(parent, subgraph),
- subgraph,
- parent.subcomponentNames);
+ super(parent, subcomponentName(parent, subgraph), subgraph);
this.parent = parent;
this.subcomponentFactoryMethod = subcomponentFactoryMethod;
}
@@ -118,16 +110,14 @@ private ExecutableType resolvedSubcomponentFactoryMethod() {
}
@Override
- protected TypeSpec.Builder createComponentClass() {
- TypeSpec.Builder subcomponent = classBuilder(name).addModifiers(PRIVATE, FINAL);
-
+ protected void decorateComponent() {
+ component.addModifiers(PRIVATE, FINAL);
addSupertype(
- subcomponent,
+ component,
MoreTypes.asTypeElement(
graph.componentDescriptor().builderSpec().isPresent()
? graph.componentDescriptor().builderSpec().get().componentType()
: resolvedSubcomponentFactoryMethod().getReturnType()));
- return subcomponent;
}
@Override
@@ -173,11 +163,6 @@ protected void addFactoryMethods() {
parent.component.addMethod(componentMethod.build());
}
- @Override
- protected TypeSpec optionalFactoryClass(Optional optionalValueKind) {
- return parent.optionalFactoryClass(optionalValueKind);
- }
-
private void writeSubcomponentWithoutBuilder(
MethodSpec.Builder componentMethod, ExecutableType resolvedMethod) {
ImmutableList.Builder subcomponentConstructorParameters = ImmutableList.builder();
diff --git a/compiler/src/main/java/dagger/internal/codegen/TypeSpecs.java b/compiler/src/main/java/dagger/internal/codegen/TypeSpecs.java
index 3adcde1ad6d..92f1a3aedc5 100644
--- a/compiler/src/main/java/dagger/internal/codegen/TypeSpecs.java
+++ b/compiler/src/main/java/dagger/internal/codegen/TypeSpecs.java
@@ -16,6 +16,7 @@
package dagger.internal.codegen;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeSpec;
import javax.lang.model.element.TypeElement;
@@ -28,15 +29,16 @@ final class TypeSpecs {
/**
* If {@code supertype} is a class, adds it as a superclass for {@code typeBuilder}; if it is an
* interface, adds it as a superinterface.
+ *
+ * @return {@code typeBuilder}
*/
- static void addSupertype(TypeSpec.Builder typeBuilder, TypeElement supertype) {
+ @CanIgnoreReturnValue
+ static TypeSpec.Builder addSupertype(TypeSpec.Builder typeBuilder, TypeElement supertype) {
switch (supertype.getKind()) {
case CLASS:
- typeBuilder.superclass(ClassName.get(supertype));
- break;
+ return typeBuilder.superclass(ClassName.get(supertype));
case INTERFACE:
- typeBuilder.addSuperinterface(ClassName.get(supertype));
- break;
+ return typeBuilder.addSuperinterface(ClassName.get(supertype));
default:
throw new AssertionError(supertype + " is neither a class nor an interface.");
}