Extract FrameworkInstanceCreationExpression from FrameworkFieldSupplier, and split ProviderOrProducerFieldInitializer up into implementations of that by binding kind.
RELNOTES=n/a
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=180805825
diff --git a/java/dagger/internal/codegen/BUILD b/java/dagger/internal/codegen/BUILD
index efeb75c..f10ee5e 100644
--- a/java/dagger/internal/codegen/BUILD
+++ b/java/dagger/internal/codegen/BUILD
@@ -199,34 +199,45 @@
"ComponentRequirementBindingExpression.java",
"ComponentRequirementField.java",
"ComponentRequirementFields.java",
+ "ComponentRequirementProviderCreationExpression.java",
"ComponentWriter.java",
"DelegateBindingExpression.java",
+ "DelegatingFrameworkInstanceCreationExpression.java",
+ "DependencyMethodProducerCreationExpression.java",
+ "DependencyMethodProviderCreationExpression.java",
"FactoryGenerator.java",
"FrameworkFieldInitializer.java",
- "FrameworkFieldSupplier.java",
"FrameworkInstanceBindingExpression.java",
+ "FrameworkInstanceSupplier.java",
"GeneratedComponentModel.java",
"GwtCompatibility.java",
"InjectionMethods.java",
+ "InjectionOrProvisionProviderCreationExpression.java",
"MapBindingExpression.java",
+ "MapFactoryCreationExpression.java",
"MemberSelect.java",
"MembersInjectionBindingExpression.java",
"MembersInjectionMethods.java",
"MembersInjectorGenerator.java",
+ "MembersInjectorProviderCreationExpression.java",
"MonitoringModuleGenerator.java",
"MonitoringModuleProcessingStep.java",
"OptionalBindingExpression.java",
"OptionalFactories.java",
"PrivateMethodBindingExpression.java",
+ "ProducerCreationExpression.java",
"ProducerFactoryGenerator.java",
- "ProducerFromProviderFieldInitializer.java",
+ "ProducerFromProviderCreationExpression.java",
"ProductionExecutorModuleGenerator.java",
- "ProviderOrProducerFieldInitializer.java",
"ReferenceReleasingManagerFields.java",
+ "ReleasableReferenceManagerProviderCreationExpression.java",
+ "ReleasableReferenceManagerSetProviderCreationExpression.java",
"SetBindingExpression.java",
+ "SetFactoryCreationExpression.java",
"SimpleInvocationBindingExpression.java",
"SimpleMethodBindingExpression.java",
"SubcomponentBuilderBindingExpression.java",
+ "SubcomponentBuilderProviderCreationExpression.java",
"SubcomponentNames.java",
"SubcomponentWriter.java",
"UnwrappedMapKeyGenerator.java",
diff --git a/java/dagger/internal/codegen/CodeBlocks.java b/java/dagger/internal/codegen/CodeBlocks.java
index ea3058e..ab4d90f 100644
--- a/java/dagger/internal/codegen/CodeBlocks.java
+++ b/java/dagger/internal/codegen/CodeBlocks.java
@@ -106,6 +106,11 @@
.build());
}
+ /** Returns {@code expression} cast to a type. */
+ static CodeBlock cast(CodeBlock expression, Class<?> castTo) {
+ return CodeBlock.of("($T) $L", castTo, expression);
+ }
+
private static final class CodeBlockJoiner {
private final String delimiter;
private final CodeBlock.Builder builder;
diff --git a/java/dagger/internal/codegen/ComponentBindingExpressions.java b/java/dagger/internal/codegen/ComponentBindingExpressions.java
index 861e2e4..7aa8541 100644
--- a/java/dagger/internal/codegen/ComponentBindingExpressions.java
+++ b/java/dagger/internal/codegen/ComponentBindingExpressions.java
@@ -18,23 +18,37 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.Accessibility.isRawTypeAccessible;
import static dagger.internal.codegen.Accessibility.isTypeAccessibleFrom;
+import static dagger.internal.codegen.BindingType.MEMBERS_INJECTION;
+import static dagger.internal.codegen.CodeBlocks.makeParametersCodeBlock;
import static dagger.internal.codegen.ContributionBinding.Kind.INJECTION;
import static dagger.internal.codegen.ContributionBinding.Kind.PROVISION;
import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_MULTIBOUND_MAP;
import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_MULTIBOUND_SET;
+import static dagger.internal.codegen.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.MemberSelect.staticMemberSelect;
+import static dagger.internal.codegen.SourceFiles.membersInjectorNameForType;
+import static dagger.internal.codegen.TypeNames.DOUBLE_CHECK;
+import static dagger.internal.codegen.TypeNames.REFERENCE_RELEASING_PROVIDER;
+import static dagger.internal.codegen.TypeNames.SINGLE_CHECK;
+import com.google.auto.common.MoreTypes;
import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Table;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
+import dagger.internal.InstanceFactory;
+import dagger.internal.MembersInjectors;
import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
import dagger.model.DependencyRequest;
import dagger.model.Key;
import dagger.model.RequestKind;
+import dagger.model.Scope;
import java.util.EnumSet;
import java.util.Optional;
import javax.lang.model.type.TypeMirror;
@@ -162,6 +176,18 @@
}
/**
+ * Returns the expressions for each of the given {@linkplain FrameworkDependency framework
+ * dependencies}.
+ */
+ ImmutableList<CodeBlock> getDependencyExpressions(
+ ImmutableList<FrameworkDependency> frameworkDependencies, ClassName requestingClass) {
+ return frameworkDependencies
+ .stream()
+ .map(dependency -> getDependencyExpression(dependency, requestingClass).codeBlock())
+ .collect(toImmutableList());
+ }
+
+ /**
* Returns an expression that evaluates to the value of a dependency request, for passing to a
* binding method, an {@code @Inject}-annotated constructor or member, or a proxy for one.
*
@@ -286,13 +312,18 @@
}
/**
- * Returns a binding expression that uses a {@link javax.inject.Provider} for provision
- * bindings, a {@link dagger.producers.Producer} for production bindings, or a {@link
- * dagger.MembersInjector} for members injection bindings.
+ * Returns a binding expression that uses a {@link javax.inject.Provider} for provision bindings
+ * or a {@link dagger.producers.Producer} for production bindings.
*/
private FrameworkInstanceBindingExpression frameworkInstanceBindingExpression(
ResolvedBindings resolvedBindings, RequestKind requestKind) {
Optional<MemberSelect> staticMethod = staticMemberSelect(resolvedBindings);
+ FrameworkInstanceCreationExpression frameworkInstanceCreationExpression =
+ resolvedBindings.scope().isPresent()
+ ? scope(
+ resolvedBindings.scope().get(),
+ frameworkInstanceCreationExpression(resolvedBindings))
+ : frameworkInstanceCreationExpression(resolvedBindings);
return new FrameworkInstanceBindingExpression(
resolvedBindings,
requestKind,
@@ -300,32 +331,136 @@
resolvedBindings.bindingType().frameworkType(),
staticMethod.isPresent()
? staticMethod::get
- : frameworkFieldInitializer(resolvedBindings),
+ : new FrameworkFieldInitializer(
+ generatedComponentModel, resolvedBindings, frameworkInstanceCreationExpression),
types,
elements);
}
+ private FrameworkInstanceCreationExpression scope(
+ Scope scope, FrameworkInstanceCreationExpression unscoped) {
+ if (referenceReleasingManagerFields.requiresReleasableReferences(scope)) {
+ return () ->
+ CodeBlock.of(
+ "$T.create($L, $L)",
+ REFERENCE_RELEASING_PROVIDER,
+ unscoped.creationExpression(),
+ referenceReleasingManagerFields.getExpression(
+ scope, generatedComponentModel.name()));
+ } else {
+ return () ->
+ CodeBlock.of(
+ "$T.provider($L)",
+ scope.isReusable() ? SINGLE_CHECK : DOUBLE_CHECK,
+ unscoped.creationExpression());
+ }
+ }
+
/**
- * Returns an initializer for a {@link javax.inject.Provider} field for provision bindings, a
- * {@link dagger.producers.Producer} field for production bindings, or a {@link
- * dagger.MembersInjector} field for members injection bindings.
+ * Returns a creation expression for a {@link javax.inject.Provider} for provision bindings or a
+ * {@link dagger.producers.Producer} for production bindings.
*/
- private FrameworkFieldInitializer frameworkFieldInitializer(ResolvedBindings resolvedBindings) {
- switch (resolvedBindings.bindingType()) {
- case PRODUCTION:
+ private FrameworkInstanceCreationExpression frameworkInstanceCreationExpression(
+ ResolvedBindings resolvedBindings) {
+ checkArgument(!resolvedBindings.bindingType().equals(MEMBERS_INJECTION));
+ ContributionBinding binding = resolvedBindings.contributionBinding();
+ switch (binding.bindingKind()) {
+ case COMPONENT:
+ // The type parameter can be removed when we drop java 7 source support
+ return () ->
+ CodeBlock.of("$T.<$T>create(this)", InstanceFactory.class, binding.key().type());
+
+ case BOUND_INSTANCE:
+ case COMPONENT_DEPENDENCY:
+ return new ComponentRequirementProviderCreationExpression(
+ binding, generatedComponentModel, componentRequirementFields);
+
+ case COMPONENT_PROVISION:
+ return new DependencyMethodProviderCreationExpression(
+ binding, generatedComponentModel, componentRequirementFields, compilerOptions, graph);
+
+ case SUBCOMPONENT_BUILDER:
+ return new SubcomponentBuilderProviderCreationExpression(
+ binding.key().type(), subcomponentNames.get(binding.key()));
+
+ case INJECTION:
case PROVISION:
- return new ProviderOrProducerFieldInitializer(
- resolvedBindings,
- subcomponentNames,
+ return new InjectionOrProvisionProviderCreationExpression(
+ binding,
generatedComponentModel,
componentBindingExpressions,
- componentRequirementFields,
- referenceReleasingManagerFields,
- compilerOptions,
- graph,
- optionalFactories);
+ componentRequirementFields);
+
+ case COMPONENT_PRODUCTION:
+ return new DependencyMethodProducerCreationExpression(
+ binding, generatedComponentModel, componentRequirementFields, graph);
+
+ case PRODUCTION:
+ return new ProducerCreationExpression(
+ binding,
+ generatedComponentModel,
+ componentBindingExpressions,
+ componentRequirementFields);
+
+ case SYNTHETIC_MULTIBOUND_SET:
+ return new SetFactoryCreationExpression(
+ binding, generatedComponentModel, componentBindingExpressions, graph);
+
+ case SYNTHETIC_MULTIBOUND_MAP:
+ return new MapFactoryCreationExpression(
+ binding, generatedComponentModel, componentBindingExpressions, graph);
+
+ case SYNTHETIC_RELEASABLE_REFERENCE_MANAGER:
+ return new ReleasableReferenceManagerProviderCreationExpression(
+ binding, generatedComponentModel, referenceReleasingManagerFields);
+
+ case SYNTHETIC_RELEASABLE_REFERENCE_MANAGERS:
+ return new ReleasableReferenceManagerSetProviderCreationExpression(
+ binding, generatedComponentModel, referenceReleasingManagerFields, graph);
+
+ case SYNTHETIC_DELEGATE_BINDING:
+ return new DelegatingFrameworkInstanceCreationExpression(
+ binding, generatedComponentModel, componentBindingExpressions);
+
+ case SYNTHETIC_OPTIONAL_BINDING:
+ if (binding.explicitDependencies().isEmpty()) {
+ return () -> optionalFactories.absentOptionalProvider(binding);
+ } else {
+ return () ->
+ optionalFactories.presentOptionalFactory(
+ binding,
+ componentBindingExpressions
+ .getDependencyExpression(
+ getOnlyElement(binding.frameworkDependencies()),
+ generatedComponentModel.name())
+ .codeBlock());
+ }
+
+ case MEMBERS_INJECTOR:
+ TypeMirror membersInjectedType =
+ getOnlyElement(MoreTypes.asDeclared(binding.key().type()).getTypeArguments());
+
+ if (((ProvisionBinding) binding).injectionSites().isEmpty()) {
+ return () ->
+ // The type parameter can be removed when we drop Java 7 source support.
+ CodeBlock.of(
+ "$T.create($T.<$T>noOp())",
+ InstanceFactory.class,
+ MembersInjectors.class,
+ membersInjectedType);
+ } else {
+ return () ->
+ CodeBlock.of(
+ "$T.create($T.create($L))",
+ InstanceFactory.class,
+ membersInjectorNameForType(MoreTypes.asTypeElement(membersInjectedType)),
+ makeParametersCodeBlock(
+ componentBindingExpressions.getDependencyExpressions(
+ binding.frameworkDependencies(), generatedComponentModel.name())));
+ }
+
default:
- throw new AssertionError(resolvedBindings);
+ throw new AssertionError(binding);
}
}
@@ -366,8 +501,13 @@
requestKind,
componentBindingExpressions,
FrameworkType.PRODUCER,
- new ProducerFromProviderFieldInitializer(
- resolvedBindings, generatedComponentModel, componentBindingExpressions),
+ new FrameworkFieldInitializer(
+ generatedComponentModel,
+ resolvedBindings,
+ new ProducerFromProviderCreationExpression(
+ resolvedBindings.contributionBinding(),
+ generatedComponentModel,
+ componentBindingExpressions)),
types,
elements);
}
diff --git a/java/dagger/internal/codegen/ComponentRequirementProviderCreationExpression.java b/java/dagger/internal/codegen/ComponentRequirementProviderCreationExpression.java
new file mode 100644
index 0000000..bc2bf17
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentRequirementProviderCreationExpression.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.InstanceFactory;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+
+/**
+ * A {@link javax.inject.Provider} creation expression for a {@linkplain
+ * dagger.Component#dependencies() component dependency} or an instance passed to a {@link
+ * dagger.BindsInstance @BindsInstance} builder method.
+ */
+final class ComponentRequirementProviderCreationExpression
+ implements FrameworkInstanceCreationExpression {
+
+ private final ContributionBinding binding;
+ private final GeneratedComponentModel generatedComponentModel;
+ private final ComponentRequirementFields componentRequirementFields;
+
+ ComponentRequirementProviderCreationExpression(
+ ContributionBinding binding,
+ GeneratedComponentModel generatedComponentModel,
+ ComponentRequirementFields componentRequirementFields) {
+ this.binding = checkNotNull(binding);
+ this.generatedComponentModel = checkNotNull(generatedComponentModel);
+ this.componentRequirementFields = checkNotNull(componentRequirementFields);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ return CodeBlock.of(
+ "$T.$L($L)",
+ InstanceFactory.class,
+ binding.nullableType().isPresent() ? "createNullable" : "create",
+ componentRequirementFields.getExpressionDuringInitialization(
+ componentRequirement(), generatedComponentModel.name()));
+ }
+
+ private ComponentRequirement componentRequirement() {
+ switch (binding.bindingKind()) {
+ case COMPONENT_DEPENDENCY:
+ return ComponentRequirement.forDependency(binding.key().type());
+
+ case BOUND_INSTANCE:
+ return ComponentRequirement.forBoundInstance(binding);
+
+ default:
+ throw new IllegalArgumentException(
+ "binding must be for a bound instance or a dependency: " + binding);
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/DelegatingFrameworkInstanceCreationExpression.java b/java/dagger/internal/codegen/DelegatingFrameworkInstanceCreationExpression.java
new file mode 100644
index 0000000..09fd1f9
--- /dev/null
+++ b/java/dagger/internal/codegen/DelegatingFrameworkInstanceCreationExpression.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.getOnlyElement;
+
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+
+/** A framework instance creation expression for a {@link dagger.Binds @Binds} binding. */
+final class DelegatingFrameworkInstanceCreationExpression
+ implements FrameworkInstanceCreationExpression {
+
+ private final ContributionBinding binding;
+ private final GeneratedComponentModel generatedComponentModel;
+ private final ComponentBindingExpressions componentBindingExpressions;
+
+ DelegatingFrameworkInstanceCreationExpression(
+ ContributionBinding binding,
+ GeneratedComponentModel generatedComponentModel,
+ ComponentBindingExpressions componentBindingExpressions) {
+ this.binding = checkNotNull(binding);
+ this.generatedComponentModel = checkNotNull(generatedComponentModel);
+ this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ FrameworkDependency frameworkDependency = getOnlyElement(binding.frameworkDependencies());
+ return CodeBlocks.cast(
+ componentBindingExpressions
+ .getDependencyExpression(frameworkDependency, generatedComponentModel.name())
+ .codeBlock(),
+ binding.bindingType().frameworkClass());
+ }
+}
diff --git a/java/dagger/internal/codegen/DependencyMethodProducerCreationExpression.java b/java/dagger/internal/codegen/DependencyMethodProducerCreationExpression.java
new file mode 100644
index 0000000..6efe4c7
--- /dev/null
+++ b/java/dagger/internal/codegen/DependencyMethodProducerCreationExpression.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static com.squareup.javapoet.TypeSpec.anonymousClassBuilder;
+import static dagger.internal.codegen.TypeNames.listenableFutureOf;
+import static dagger.internal.codegen.TypeNames.producerOf;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+
+/**
+ * A {@link dagger.producers.Producer} creation expression for a production method on a production
+ * component's {@linkplain dagger.producers.ProductionComponent#dependencies()} dependency} that
+ * returns a {@link com.google.common.util.concurrent.ListenableFuture}.
+ */
+// TODO(dpb): Resolve with DependencyMethodProviderCreationExpression.
+final class DependencyMethodProducerCreationExpression
+ implements FrameworkInstanceCreationExpression {
+ private final ContributionBinding binding;
+ private final GeneratedComponentModel generatedComponentModel;
+ private final ComponentRequirementFields componentRequirementFields;
+ private final BindingGraph graph;
+
+ DependencyMethodProducerCreationExpression(
+ ContributionBinding binding,
+ GeneratedComponentModel generatedComponentModel,
+ ComponentRequirementFields componentRequirementFields,
+ BindingGraph graph) {
+ this.binding = checkNotNull(binding);
+ this.generatedComponentModel = checkNotNull(generatedComponentModel);
+ this.componentRequirementFields = checkNotNull(componentRequirementFields);
+ this.graph = checkNotNull(graph);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ ComponentRequirement dependency =
+ graph
+ .componentDescriptor()
+ .dependenciesByDependencyMethod()
+ .get(binding.bindingElement().get());
+ FieldSpec dependencyField =
+ FieldSpec.builder(
+ ClassName.get(dependency.typeElement()), dependency.variableName(), PRIVATE, FINAL)
+ .initializer(
+ componentRequirementFields.getExpressionDuringInitialization(
+ dependency, generatedComponentModel.name()))
+ .build();
+ // TODO(b/70395982): Explore using a private static type instead of an anonymous class.
+ TypeName keyType = TypeName.get(binding.key().type());
+ return CodeBlock.of(
+ "$L",
+ anonymousClassBuilder("")
+ .superclass(producerOf(keyType))
+ .addField(dependencyField)
+ .addMethod(
+ methodBuilder("get")
+ .addAnnotation(Override.class)
+ .addModifiers(PUBLIC)
+ .returns(listenableFutureOf(keyType))
+ .addStatement(
+ "return $N.$L()",
+ dependencyField,
+ binding.bindingElement().get().getSimpleName())
+ .build())
+ .build());
+ }
+}
diff --git a/java/dagger/internal/codegen/DependencyMethodProviderCreationExpression.java b/java/dagger/internal/codegen/DependencyMethodProviderCreationExpression.java
new file mode 100644
index 0000000..e76400a
--- /dev/null
+++ b/java/dagger/internal/codegen/DependencyMethodProviderCreationExpression.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.squareup.javapoet.MethodSpec.constructorBuilder;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static dagger.internal.codegen.GeneratedComponentModel.TypeSpecKind.COMPONENT_PROVISION_FACTORY;
+import static dagger.internal.codegen.TypeNames.providerOf;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+
+import com.google.auto.common.MoreTypes;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import java.util.Optional;
+import javax.lang.model.element.Element;
+
+/**
+ * A {@link javax.inject.Provider} creation expression for a provision method on a component's
+ * {@linkplain dagger.Component#dependencies()} dependency}.
+ */
+// TODO(dpb): Resolve with DependencyMethodProducerCreationExpression.
+final class DependencyMethodProviderCreationExpression
+ implements FrameworkInstanceCreationExpression {
+
+ private final GeneratedComponentModel generatedComponentModel;
+ private final ComponentRequirementFields componentRequirementFields;
+ private final CompilerOptions compilerOptions;
+ private final BindingGraph graph;
+ private final ContributionBinding binding;
+
+ DependencyMethodProviderCreationExpression(
+ ContributionBinding binding,
+ GeneratedComponentModel generatedComponentModel,
+ ComponentRequirementFields componentRequirementFields,
+ CompilerOptions compilerOptions,
+ BindingGraph graph) {
+ this.binding = checkNotNull(binding);
+ this.generatedComponentModel = checkNotNull(generatedComponentModel);
+ this.componentRequirementFields = checkNotNull(componentRequirementFields);
+ this.compilerOptions = checkNotNull(compilerOptions);
+ this.graph = checkNotNull(graph);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ // TODO(sameb): The Provider.get() throws a very vague NPE. The stack trace doesn't
+ // help to figure out what the method or return type is. If we include a string
+ // of the return type or method name in the error message, that can defeat obfuscation.
+ // We can easily include the raw type (no generics) + annotation type (no values),
+ // using .class & String.format -- but that wouldn't be the whole story.
+ // What should we do?
+ CodeBlock invocation =
+ ComponentProvisionBindingExpression.maybeCheckForNull(
+ (ProvisionBinding) binding,
+ compilerOptions,
+ CodeBlock.of(
+ "$N.$N()", dependency().variableName(), provisionMethod().getSimpleName()));
+ ClassName dependencyClassName = ClassName.get(dependency().typeElement());
+ TypeName keyType = TypeName.get(binding.key().type());
+ MethodSpec.Builder getMethod =
+ methodBuilder("get")
+ .addAnnotation(Override.class)
+ .addModifiers(PUBLIC)
+ .returns(keyType)
+ .addStatement("return $L", invocation);
+ if (binding.nullableType().isPresent()) {
+ getMethod.addAnnotation(ClassName.get(MoreTypes.asTypeElement(binding.nullableType().get())));
+ }
+ generatedComponentModel.addType(
+ COMPONENT_PROVISION_FACTORY,
+ classBuilder(factoryClassName())
+ .addSuperinterface(providerOf(keyType))
+ .addModifiers(PRIVATE, STATIC)
+ .addField(dependencyClassName, dependency().variableName(), PRIVATE, FINAL)
+ .addMethod(
+ constructorBuilder()
+ .addParameter(dependencyClassName, dependency().variableName())
+ .addStatement("this.$1L = $1L", dependency().variableName())
+ .build())
+ .addMethod(getMethod.build())
+ .build());
+ return CodeBlock.of(
+ "new $T($L)",
+ factoryClassName(),
+ componentRequirementFields.getExpressionDuringInitialization(
+ dependency(), generatedComponentModel.name()));
+ }
+
+ private ClassName factoryClassName() {
+ String factoryName =
+ ClassName.get(dependency().typeElement()).toString().replace('.', '_')
+ + "_"
+ + binding.bindingElement().get().getSimpleName();
+ return generatedComponentModel.name().nestedClass(factoryName);
+ }
+
+ private ComponentRequirement dependency() {
+ return graph.componentDescriptor().dependenciesByDependencyMethod().get(provisionMethod());
+ }
+
+ private Element provisionMethod() {
+ return binding.bindingElement().get();
+ }
+
+ @Override
+ public Optional<TypeName> specificType() {
+ return Optional.of(factoryClassName());
+ }
+}
diff --git a/java/dagger/internal/codegen/FrameworkFieldInitializer.java b/java/dagger/internal/codegen/FrameworkFieldInitializer.java
index 1f5752d..ca444ea 100644
--- a/java/dagger/internal/codegen/FrameworkFieldInitializer.java
+++ b/java/dagger/internal/codegen/FrameworkFieldInitializer.java
@@ -17,13 +17,10 @@
package dagger.internal.codegen;
import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.Accessibility.isTypeAccessibleFrom;
import static dagger.internal.codegen.AnnotationSpecs.Suppression.RAWTYPES;
-import static dagger.internal.codegen.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.GeneratedComponentModel.FieldSpecKind.FRAMEWORK_FIELD;
import static javax.lang.model.element.Modifier.PRIVATE;
-import com.google.common.collect.ImmutableList;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
@@ -35,28 +32,46 @@
* An object that can initialize a framework-type component field for a binding. An instance should
* be created for each field.
*/
-abstract class FrameworkFieldInitializer implements FrameworkFieldSupplier {
+class FrameworkFieldInitializer implements FrameworkInstanceSupplier {
- protected final GeneratedComponentModel generatedComponentModel;
- private final ComponentBindingExpressions componentBindingExpressions;
+ /**
+ * An object that can determine the expression to use to assign to the component field for a
+ * binding.
+ */
+ interface FrameworkInstanceCreationExpression {
+ /** Returns the expression to use to assign to the component field for the binding. */
+ CodeBlock creationExpression();
+
+ /**
+ * Returns the type of the creation expression when it is a specific factory type. This
+ * implementation returns {@link Optional#empty()}.
+ */
+ default Optional<TypeName> specificType() {
+ return Optional.empty();
+ }
+
+ /**
+ * Returns the framework class to use for the field, if different from the one implied by the
+ * binding. This implementation returns {@link Optional#empty()}.
+ */
+ default Optional<ClassName> alternativeFrameworkClass() {
+ return Optional.empty();
+ }
+ }
+
+ private final GeneratedComponentModel generatedComponentModel;
private final ResolvedBindings resolvedBindings;
+ private final FrameworkInstanceCreationExpression frameworkInstanceCreationExpression;
private FieldSpec fieldSpec;
private InitializationState fieldInitializationState = InitializationState.UNINITIALIZED;
- /**
- * Indicates the type of the initializer when has been replaced with a more-specific factory type.
- * This is used by {@code FrameworkInstanceBindingExpression} to create fields with the
- * most-specific type available. This allows javac to complete much faster for large components.
- */
- private Optional<TypeName> fieldTypeReplacement = Optional.empty();
-
- protected FrameworkFieldInitializer(
+ FrameworkFieldInitializer(
GeneratedComponentModel generatedComponentModel,
- ComponentBindingExpressions componentBindingExpressions,
- ResolvedBindings resolvedBindings) {
+ ResolvedBindings resolvedBindings,
+ FrameworkInstanceCreationExpression frameworkInstanceCreationExpression) {
this.generatedComponentModel = checkNotNull(generatedComponentModel);
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
this.resolvedBindings = checkNotNull(resolvedBindings);
+ this.frameworkInstanceCreationExpression = checkNotNull(frameworkInstanceCreationExpression);
}
/**
@@ -76,7 +91,7 @@
// Change our state in case we are recursively invoked via initializeBindingExpression
fieldInitializationState = InitializationState.INITIALIZING;
CodeBlock.Builder codeBuilder = CodeBlock.builder();
- CodeBlock fieldInitialization = getFieldInitialization();
+ CodeBlock fieldInitialization = frameworkInstanceCreationExpression.creationExpression();
CodeBlock initCode = CodeBlock.of("this.$N = $L;", getOrCreateField(), fieldInitialization);
if (fieldInitializationState == InitializationState.DELEGATED) {
@@ -97,9 +112,9 @@
case INITIALIZING:
// We were recursively invoked, so create a delegate factory instead
+ fieldInitializationState = InitializationState.DELEGATED;
generatedComponentModel.addInitialization(
CodeBlock.of("this.$N = new $T<>();", getOrCreateField(), DelegateFactory.class));
- fieldInitializationState = InitializationState.DELEGATED;
break;
case DELEGATED:
@@ -119,17 +134,17 @@
if (fieldSpec != null) {
return fieldSpec;
}
- boolean useRawType =
- !isTypeAccessibleFrom(
- resolvedBindings.key().type(), generatedComponentModel.name().packageName());
+ boolean useRawType = !generatedComponentModel.isTypeAccessible(resolvedBindings.key().type());
FrameworkField contributionBindingField =
- FrameworkField.forResolvedBindings(resolvedBindings, alternativeFrameworkClass());
+ FrameworkField.forResolvedBindings(
+ resolvedBindings, frameworkInstanceCreationExpression.alternativeFrameworkClass());
TypeName fieldType;
- if (fieldTypeReplacement.isPresent()) {
+ if (!fieldInitializationState.equals(InitializationState.DELEGATED)
+ && specificType().isPresent()) {
// For some larger components, this causes javac to compile much faster by getting the
// field type to exactly match the type of the expression being assigned to it.
- fieldType = fieldTypeReplacement.get();
+ fieldType = specificType().get();
} else if (useRawType) {
fieldType = contributionBindingField.type().rawType;
} else {
@@ -141,7 +156,7 @@
fieldType,
generatedComponentModel.getUniqueFieldName(contributionBindingField.name()));
contributionField.addModifiers(PRIVATE);
- if (useRawType && !fieldTypeReplacement.isPresent()) {
+ if (useRawType && !specificType().isPresent()) {
contributionField.addAnnotation(AnnotationSpecs.suppressWarnings(RAWTYPES));
}
fieldSpec = contributionField.build();
@@ -150,37 +165,10 @@
return fieldSpec;
}
+ /** Returns the type of the instance when it is a specific factory type. */
@Override
- public boolean fieldTypeReplaced() {
- return fieldTypeReplacement.isPresent();
- }
-
- /**
- * Returns the framework class to use for the field, if different from the one implied by the
- * binding. This implementation returns {@link Optional#empty()}.
- */
- protected Optional<ClassName> alternativeFrameworkClass() {
- return Optional.empty();
- }
-
- /** Returns the expression to use to initialize the field. */
- protected abstract CodeBlock getFieldInitialization();
-
- /** Returns a list of code blocks for referencing all of the given binding's dependencies. */
- protected final ImmutableList<CodeBlock> getBindingDependencyExpressions(Binding binding) {
- ImmutableList<FrameworkDependency> dependencies = binding.frameworkDependencies();
- return dependencies.stream().map(this::getDependencyExpression).collect(toImmutableList());
- }
-
- /** Returns a code block referencing the given dependency. */
- protected final CodeBlock getDependencyExpression(FrameworkDependency frameworkDependency) {
- return componentBindingExpressions
- .getDependencyExpression(frameworkDependency, generatedComponentModel.name())
- .codeBlock();
- }
-
- protected final void setFieldTypeReplacement(TypeName typeName) {
- this.fieldTypeReplacement = Optional.of(typeName);
+ public Optional<TypeName> specificType() {
+ return frameworkInstanceCreationExpression.specificType();
}
/** Initialization state for a factory field. */
diff --git a/java/dagger/internal/codegen/FrameworkInstanceBindingExpression.java b/java/dagger/internal/codegen/FrameworkInstanceBindingExpression.java
index 20a5f47..b9ddb1d 100644
--- a/java/dagger/internal/codegen/FrameworkInstanceBindingExpression.java
+++ b/java/dagger/internal/codegen/FrameworkInstanceBindingExpression.java
@@ -30,7 +30,7 @@
/** A binding expression that uses an instance of a {@link FrameworkType}. */
final class FrameworkInstanceBindingExpression extends BindingExpression {
private final ComponentBindingExpressions componentBindingExpressions;
- private final FrameworkFieldSupplier frameworkFieldSupplier;
+ private final FrameworkInstanceSupplier frameworkInstanceSupplier;
private final FrameworkType frameworkType;
private final DaggerTypes types;
private final Elements elements;
@@ -40,13 +40,13 @@
RequestKind requestKind,
ComponentBindingExpressions componentBindingExpressions,
FrameworkType frameworkType,
- FrameworkFieldSupplier frameworkFieldSupplier,
+ FrameworkInstanceSupplier frameworkInstanceSupplier,
DaggerTypes types,
Elements elements) {
super(resolvedBindings, requestKind);
this.componentBindingExpressions = componentBindingExpressions;
this.frameworkType = frameworkType;
- this.frameworkFieldSupplier = frameworkFieldSupplier;
+ this.frameworkInstanceSupplier = frameworkInstanceSupplier;
this.types = types;
this.elements = elements;
}
@@ -60,11 +60,11 @@
@Override
Expression getDependencyExpression(ClassName requestingClass) {
if (requestKind().equals(frameworkRequestKind())) {
- MemberSelect memberSelect = frameworkFieldSupplier.memberSelect();
+ MemberSelect memberSelect = frameworkInstanceSupplier.memberSelect();
TypeMirror expressionType =
- isTypeAccessibleFrom(instanceType(), requestingClass.packageName())
+ frameworkInstanceSupplier.specificType().isPresent()
+ || isTypeAccessibleFrom(instanceType(), requestingClass.packageName())
|| isInlinedFactoryCreation(memberSelect)
- || frameworkFieldSupplier.fieldTypeReplaced()
? types.wrapType(instanceType(), resolvedBindings().frameworkClass())
: rawFrameworkType();
return Expression.create(expressionType, memberSelect.getExpressionFor(requestingClass));
diff --git a/java/dagger/internal/codegen/FrameworkFieldSupplier.java b/java/dagger/internal/codegen/FrameworkInstanceSupplier.java
similarity index 76%
rename from java/dagger/internal/codegen/FrameworkFieldSupplier.java
rename to java/dagger/internal/codegen/FrameworkInstanceSupplier.java
index 80dcf0f..d7392a6 100644
--- a/java/dagger/internal/codegen/FrameworkFieldSupplier.java
+++ b/java/dagger/internal/codegen/FrameworkInstanceSupplier.java
@@ -16,16 +16,16 @@
package dagger.internal.codegen;
-/** An object that supplies a {@link MemberSelect} for a framework field. */
-interface FrameworkFieldSupplier {
+import com.squareup.javapoet.TypeName;
+import java.util.Optional;
+
+/** An object that supplies a {@link MemberSelect} for a framework instance. */
+interface FrameworkInstanceSupplier {
/** Returns a {@link MemberSelect}, with possible side effects on the first call. */
MemberSelect memberSelect();
- /**
- * If true, signals that a publicly-visible concrete type was used to replace the original type
- * of the field being initialized.
- */
- default boolean fieldTypeReplaced() {
- return false;
+ /** The framework instance is of this specific subtype. */
+ default Optional<TypeName> specificType() {
+ return Optional.empty();
}
}
diff --git a/java/dagger/internal/codegen/GeneratedComponentModel.java b/java/dagger/internal/codegen/GeneratedComponentModel.java
index b0c27c0..32ad46e 100644
--- a/java/dagger/internal/codegen/GeneratedComponentModel.java
+++ b/java/dagger/internal/codegen/GeneratedComponentModel.java
@@ -17,6 +17,7 @@
package dagger.internal.codegen;
import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static dagger.internal.codegen.Accessibility.isTypeAccessibleFrom;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PUBLIC;
@@ -35,6 +36,7 @@
import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
/** The model of the component being generated. */
final class GeneratedComponentModel {
@@ -133,6 +135,11 @@
return name;
}
+ /** Returns {@code true} if {@code type} is accessible from the generated component. */
+ boolean isTypeAccessible(TypeMirror type) {
+ return isTypeAccessibleFrom(type, name.packageName());
+ }
+
/** Adds the given super type to the component. */
void addSupertype(TypeElement supertype) {
TypeSpecs.addSupertype(component, supertype);
diff --git a/java/dagger/internal/codegen/InjectionOrProvisionProviderCreationExpression.java b/java/dagger/internal/codegen/InjectionOrProvisionProviderCreationExpression.java
new file mode 100644
index 0000000..eb8cf7c
--- /dev/null
+++ b/java/dagger/internal/codegen/InjectionOrProvisionProviderCreationExpression.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.CodeBlocks.makeParametersCodeBlock;
+import static dagger.internal.codegen.ContributionBinding.Kind.INJECTION;
+import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding;
+
+import com.google.common.collect.Lists;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * A {@link javax.inject.Provider} creation expression for an {@link
+ * javax.inject.Inject @Inject}-constructed class or a {@link dagger.Provides @Provides}-annotated
+ * module method.
+ */
+// TODO(dpb): Resolve with ProducerCreationExpression.
+final class InjectionOrProvisionProviderCreationExpression
+ implements FrameworkInstanceCreationExpression {
+
+ private final ContributionBinding binding;
+ private final GeneratedComponentModel generatedComponentModel;
+ private final ComponentBindingExpressions componentBindingExpressions;
+ private final ComponentRequirementFields componentRequirementFields;
+
+ InjectionOrProvisionProviderCreationExpression(
+ ContributionBinding binding,
+ GeneratedComponentModel generatedComponentModel,
+ ComponentBindingExpressions componentBindingExpressions,
+ ComponentRequirementFields componentRequirementFields) {
+ this.binding = checkNotNull(binding);
+ this.generatedComponentModel = checkNotNull(generatedComponentModel);
+ this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ this.componentRequirementFields = checkNotNull(componentRequirementFields);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ List<CodeBlock> arguments =
+ Lists.newArrayListWithCapacity(binding.explicitDependencies().size() + 1);
+ if (binding.requiresModuleInstance()) {
+ arguments.add(
+ componentRequirementFields.getExpressionDuringInitialization(
+ ComponentRequirement.forModule(binding.contributingModule().get().asType()),
+ generatedComponentModel.name()));
+ }
+ arguments.addAll(
+ componentBindingExpressions.getDependencyExpressions(
+ binding.frameworkDependencies(), generatedComponentModel.name()));
+
+ CodeBlock createFactory =
+ CodeBlock.of(
+ "$T.create($L)",
+ generatedClassNameForBinding(binding),
+ makeParametersCodeBlock(arguments));
+
+ // When scoping a parameterized factory for an @Inject class, Java 7 cannot always infer the
+ // type properly, so cast to a raw framework type before scoping.
+ if (binding.bindingKind().equals(INJECTION)
+ && binding.unresolved().isPresent()
+ && binding.scope().isPresent()) {
+ return CodeBlocks.cast(createFactory, binding.bindingType().frameworkClass());
+ } else {
+ return createFactory;
+ }
+ }
+
+ @Override
+ public Optional<TypeName> specificType() {
+ return Optional.of(generatedClassNameForBinding(binding));
+ }
+}
diff --git a/java/dagger/internal/codegen/MapFactoryCreationExpression.java b/java/dagger/internal/codegen/MapFactoryCreationExpression.java
new file mode 100644
index 0000000..4bc3921
--- /dev/null
+++ b/java/dagger/internal/codegen/MapFactoryCreationExpression.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.MapKeys.getMapKeyExpression;
+import static dagger.internal.codegen.SourceFiles.mapFactoryClassName;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import javax.inject.Provider;
+import javax.lang.model.type.TypeMirror;
+
+/** A factory creation expression for a multibound map. */
+// TODO(dpb): Resolve with SetFactoryCreationExpression.
+final class MapFactoryCreationExpression implements FrameworkInstanceCreationExpression {
+
+ private final GeneratedComponentModel generatedComponentModel;
+ private final ComponentBindingExpressions componentBindingExpressions;
+ private final BindingGraph graph;
+ private final ContributionBinding binding;
+
+ MapFactoryCreationExpression(
+ ContributionBinding binding,
+ GeneratedComponentModel generatedComponentModel,
+ ComponentBindingExpressions componentBindingExpressions,
+ BindingGraph graph) {
+ this.binding = checkNotNull(binding);
+ this.generatedComponentModel = checkNotNull(generatedComponentModel);
+ this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ this.graph = checkNotNull(graph);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ CodeBlock.Builder builder = CodeBlock.builder().add("$T.", mapFactoryClassName(binding));
+ boolean useRawType = !generatedComponentModel.isTypeAccessible(binding.key().type());
+ if (!useRawType) {
+ MapType mapType = MapType.from(binding.key().type());
+ // TODO(ronshapiro): either inline this into mapFactoryClassName, or add a
+ // mapType.unwrappedValueType() method that doesn't require a framework type
+ TypeMirror valueType = mapType.valueType();
+ for (Class<?> frameworkClass :
+ ImmutableSet.of(Provider.class, Producer.class, Produced.class)) {
+ if (mapType.valuesAreTypeOf(frameworkClass)) {
+ valueType = mapType.unwrappedValueType(frameworkClass);
+ break;
+ }
+ }
+ builder.add("<$T, $T>", mapType.keyType(), valueType);
+ }
+
+ ImmutableList<FrameworkDependency> frameworkDependencies = binding.frameworkDependencies();
+ if (binding.bindingType().equals(BindingType.PROVISION)) {
+ builder.add("builder($L)", frameworkDependencies.size());
+ } else {
+ builder.add("builder()");
+ }
+
+ for (FrameworkDependency frameworkDependency : frameworkDependencies) {
+ ContributionBinding contributionBinding =
+ graph.contributionBindings().get(frameworkDependency.key()).contributionBinding();
+ CodeBlock value =
+ componentBindingExpressions
+ .getDependencyExpression(frameworkDependency, generatedComponentModel.name())
+ .codeBlock();
+ builder.add(
+ ".put($L, $L)",
+ getMapKeyExpression(contributionBinding, generatedComponentModel.name()),
+ useRawType ? CodeBlocks.cast(value, frameworkDependency.frameworkClass()) : value);
+ }
+ builder.add(".build()");
+
+ return builder.build();
+ }
+}
diff --git a/java/dagger/internal/codegen/MembersInjectorProviderCreationExpression.java b/java/dagger/internal/codegen/MembersInjectorProviderCreationExpression.java
new file mode 100644
index 0000000..5939052
--- /dev/null
+++ b/java/dagger/internal/codegen/MembersInjectorProviderCreationExpression.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.CodeBlocks.makeParametersCodeBlock;
+import static dagger.internal.codegen.SourceFiles.membersInjectorNameForType;
+import static dagger.internal.codegen.TypeNames.INSTANCE_FACTORY;
+import static dagger.internal.codegen.TypeNames.MEMBERS_INJECTORS;
+
+import com.google.auto.common.MoreTypes;
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import javax.lang.model.type.TypeMirror;
+
+/** A {@code Provider<MembersInjector<Foo>>} creation expression. */
+final class MembersInjectorProviderCreationExpression
+ implements FrameworkInstanceCreationExpression {
+
+ private final GeneratedComponentModel generatedComponentModel;
+ private final ComponentBindingExpressions componentBindingExpressions;
+ private final ContributionBinding binding;
+
+ MembersInjectorProviderCreationExpression(
+ ContributionBinding binding,
+ GeneratedComponentModel generatedComponentModel,
+ ComponentBindingExpressions componentBindingExpressions) {
+ this.binding = checkNotNull(binding);
+ this.generatedComponentModel = checkNotNull(generatedComponentModel);
+ this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ TypeMirror membersInjectedType =
+ getOnlyElement(MoreTypes.asDeclared(binding.key().type()).getTypeArguments());
+
+ CodeBlock membersInjector =
+ ((ProvisionBinding) binding).injectionSites().isEmpty()
+ ? CodeBlock.of("$T.<$T>noOp()", MEMBERS_INJECTORS, membersInjectedType)
+ : CodeBlock.of(
+ "$T.create($L)",
+ membersInjectorNameForType(MoreTypes.asTypeElement(membersInjectedType)),
+ makeParametersCodeBlock(
+ componentBindingExpressions.getDependencyExpressions(
+ binding.frameworkDependencies(), generatedComponentModel.name())));
+
+ // TODO(ronshapiro): consider adding a MembersInjectorBindingExpression to return this directly
+ // (as it's rarely requested as a Provider).
+ return CodeBlock.of("$T.create($L)", INSTANCE_FACTORY, membersInjector);
+ }
+}
diff --git a/java/dagger/internal/codegen/OptionalFactories.java b/java/dagger/internal/codegen/OptionalFactories.java
index 1406677..498ec35 100644
--- a/java/dagger/internal/codegen/OptionalFactories.java
+++ b/java/dagger/internal/codegen/OptionalFactories.java
@@ -18,6 +18,7 @@
import static com.google.common.base.CaseFormat.UPPER_CAMEL;
import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
+import static com.google.common.base.Verify.verify;
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.squareup.javapoet.MethodSpec.constructorBuilder;
import static com.squareup.javapoet.MethodSpec.methodBuilder;
@@ -96,6 +97,10 @@
* for absent optional bindings.
*/
CodeBlock absentOptionalProvider(ContributionBinding binding) {
+ verify(
+ binding.bindingType().equals(BindingType.PROVISION),
+ "Absent optional bindings should be provisions: %s",
+ binding);
OptionalKind optionalKind = OptionalType.from(binding.key()).kind();
return CodeBlock.of(
"$N()",
diff --git a/java/dagger/internal/codegen/ProducerCreationExpression.java b/java/dagger/internal/codegen/ProducerCreationExpression.java
new file mode 100644
index 0000000..696f6d6
--- /dev/null
+++ b/java/dagger/internal/codegen/ProducerCreationExpression.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.CodeBlocks.makeParametersCodeBlock;
+import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding;
+
+import com.google.common.collect.Lists;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * A {@link dagger.producers.Producer} creation expression for a {@link
+ * dagger.producers.Produces @Produces}-annotated module method.
+ */
+// TODO(dpb): Resolve with InjectionOrProvisionProviderCreationExpression.
+final class ProducerCreationExpression implements FrameworkInstanceCreationExpression {
+
+ private final GeneratedComponentModel generatedComponentModel;
+ private final ComponentBindingExpressions componentBindingExpressions;
+ private final ComponentRequirementFields componentRequirementFields;
+ private final ContributionBinding binding;
+
+ ProducerCreationExpression(
+ ContributionBinding binding,
+ GeneratedComponentModel generatedComponentModel,
+ ComponentBindingExpressions componentBindingExpressions,
+ ComponentRequirementFields componentRequirementFields) {
+ this.binding = checkNotNull(binding);
+ this.generatedComponentModel = checkNotNull(generatedComponentModel);
+ this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ this.componentRequirementFields = checkNotNull(componentRequirementFields);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ List<CodeBlock> arguments = Lists.newArrayListWithCapacity(binding.dependencies().size() + 2);
+ if (binding.requiresModuleInstance()) {
+ arguments.add(
+ componentRequirementFields.getExpressionDuringInitialization(
+ ComponentRequirement.forModule(binding.contributingModule().get().asType()),
+ generatedComponentModel.name()));
+ }
+ arguments.addAll(
+ componentBindingExpressions.getDependencyExpressions(
+ binding.frameworkDependencies(), generatedComponentModel.name()));
+
+ return CodeBlock.of(
+ "new $T($L)", generatedClassNameForBinding(binding), makeParametersCodeBlock(arguments));
+ }
+
+ @Override
+ public Optional<TypeName> specificType() {
+ return Optional.of(generatedClassNameForBinding(binding));
+ }
+}
diff --git a/java/dagger/internal/codegen/ProducerFromProviderFieldInitializer.java b/java/dagger/internal/codegen/ProducerFromProviderCreationExpression.java
similarity index 65%
rename from java/dagger/internal/codegen/ProducerFromProviderFieldInitializer.java
rename to java/dagger/internal/codegen/ProducerFromProviderCreationExpression.java
index 61e122d..05a0e41 100644
--- a/java/dagger/internal/codegen/ProducerFromProviderFieldInitializer.java
+++ b/java/dagger/internal/codegen/ProducerFromProviderCreationExpression.java
@@ -21,38 +21,39 @@
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
-import dagger.model.Key;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
import dagger.model.RequestKind;
import dagger.producers.Producer;
import java.util.Optional;
-/** An initializer for {@link Producer} fields that are adaptations of provision bindings. */
-final class ProducerFromProviderFieldInitializer extends FrameworkFieldInitializer {
-
+/** An {@link Producer} creation expression for provision bindings. */
+final class ProducerFromProviderCreationExpression implements FrameworkInstanceCreationExpression {
+ private final ContributionBinding binding;
+ private final GeneratedComponentModel generatedComponentModel;
private final ComponentBindingExpressions componentBindingExpressions;
- private final Key key;
- ProducerFromProviderFieldInitializer(
- ResolvedBindings resolvedBindings,
+ ProducerFromProviderCreationExpression(
+ ContributionBinding binding,
GeneratedComponentModel generatedComponentModel,
ComponentBindingExpressions componentBindingExpressions) {
- super(generatedComponentModel, componentBindingExpressions, resolvedBindings);
+ this.binding = checkNotNull(binding);
+ this.generatedComponentModel = checkNotNull(generatedComponentModel);
this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
- this.key = resolvedBindings.key();
}
@Override
- protected CodeBlock getFieldInitialization() {
+ public CodeBlock creationExpression() {
return FrameworkType.PROVIDER.to(
RequestKind.PRODUCER,
componentBindingExpressions
.getDependencyExpression(
- FrameworkDependency.create(key, PROVISION), generatedComponentModel.name())
+ FrameworkDependency.create(binding.key(), PROVISION),
+ generatedComponentModel.name())
.codeBlock());
}
@Override
- protected Optional<ClassName> alternativeFrameworkClass() {
+ public Optional<ClassName> alternativeFrameworkClass() {
return Optional.of(ClassName.get(Producer.class));
}
}
diff --git a/java/dagger/internal/codegen/ProviderOrProducerFieldInitializer.java b/java/dagger/internal/codegen/ProviderOrProducerFieldInitializer.java
deleted file mode 100644
index 0c048fa..0000000
--- a/java/dagger/internal/codegen/ProviderOrProducerFieldInitializer.java
+++ /dev/null
@@ -1,592 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.base.Verify.verify;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static com.squareup.javapoet.MethodSpec.constructorBuilder;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static com.squareup.javapoet.TypeSpec.anonymousClassBuilder;
-import static dagger.internal.codegen.Accessibility.isTypeAccessibleFrom;
-import static dagger.internal.codegen.CodeBlocks.anonymousProvider;
-import static dagger.internal.codegen.CodeBlocks.makeParametersCodeBlock;
-import static dagger.internal.codegen.ContributionBinding.Kind.INJECTION;
-import static dagger.internal.codegen.GeneratedComponentModel.TypeSpecKind.COMPONENT_PROVISION_FACTORY;
-import static dagger.internal.codegen.MapKeys.getMapKeyExpression;
-import static dagger.internal.codegen.MoreAnnotationMirrors.getTypeValue;
-import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding;
-import static dagger.internal.codegen.SourceFiles.mapFactoryClassName;
-import static dagger.internal.codegen.SourceFiles.membersInjectorNameForType;
-import static dagger.internal.codegen.SourceFiles.setFactoryClassName;
-import static dagger.internal.codegen.TypeNames.DOUBLE_CHECK;
-import static dagger.internal.codegen.TypeNames.INSTANCE_FACTORY;
-import static dagger.internal.codegen.TypeNames.MEMBERS_INJECTORS;
-import static dagger.internal.codegen.TypeNames.REFERENCE_RELEASING_PROVIDER;
-import static dagger.internal.codegen.TypeNames.SINGLE_CHECK;
-import static dagger.internal.codegen.TypeNames.TYPED_RELEASABLE_REFERENCE_MANAGER_DECORATOR;
-import static dagger.internal.codegen.TypeNames.listenableFutureOf;
-import static dagger.internal.codegen.TypeNames.producerOf;
-import static dagger.internal.codegen.TypeNames.providerOf;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.PUBLIC;
-import static javax.lang.model.element.Modifier.STATIC;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.TypeName;
-import com.squareup.javapoet.TypeSpec;
-import dagger.internal.InstanceFactory;
-import dagger.internal.TypedReleasableReferenceManagerDecorator;
-import dagger.model.Key;
-import dagger.model.Scope;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import dagger.releasablereferences.ForReleasableReferences;
-import dagger.releasablereferences.ReleasableReferenceManager;
-import dagger.releasablereferences.TypedReleasableReferenceManager;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Optional;
-import javax.inject.Provider;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * An initializer for {@link Provider} or {@link Producer} fields other than {@link Producer} fields
- * that {@linkplain ProducerFromProviderFieldInitializer adapt provision bindings}.
- */
-// TODO(dpb): Split this up by binding kind.
-final class ProviderOrProducerFieldInitializer extends FrameworkFieldInitializer {
- private final SubcomponentNames subcomponentNames;
- private final ComponentRequirementFields componentRequirementFields;
- private final ResolvedBindings resolvedBindings;
- private final CompilerOptions compilerOptions;
- private final BindingGraph graph;
- private final OptionalFactories optionalFactories;
- private final ReferenceReleasingManagerFields referenceReleasingManagerFields;
-
- ProviderOrProducerFieldInitializer(
- ResolvedBindings resolvedBindings,
- SubcomponentNames subcomponentNames,
- GeneratedComponentModel generatedComponentModel,
- ComponentBindingExpressions componentBindingExpressions,
- ComponentRequirementFields componentRequirementFields,
- ReferenceReleasingManagerFields referenceReleasingManagerFields,
- CompilerOptions compilerOptions,
- BindingGraph graph,
- OptionalFactories optionalFactories) {
- super(generatedComponentModel, componentBindingExpressions, resolvedBindings);
- checkArgument(resolvedBindings.contributionBindings().size() == 1);
- this.subcomponentNames = checkNotNull(subcomponentNames);
- this.componentRequirementFields = checkNotNull(componentRequirementFields);
- this.referenceReleasingManagerFields = checkNotNull(referenceReleasingManagerFields);
- this.resolvedBindings = checkNotNull(resolvedBindings);
- this.compilerOptions = checkNotNull(compilerOptions);
- this.graph = checkNotNull(graph);
- this.optionalFactories = checkNotNull(optionalFactories);
- }
-
- @Override
- protected CodeBlock getFieldInitialization() {
- ContributionBinding contributionBinding = resolvedBindings.contributionBinding();
- switch (contributionBinding.factoryCreationStrategy()) {
- case DELEGATE:
- CodeBlock delegatingCodeBlock =
- CodeBlock.of(
- "($T) $L",
- contributionBinding.bindingType().frameworkClass(),
- getDependencyExpression(
- getOnlyElement(contributionBinding.frameworkDependencies())));
- return decorateForScope(delegatingCodeBlock, contributionBinding.scope());
- case SINGLETON_INSTANCE:
- checkState(contributionBinding.scope().isPresent());
- // fall through
- case CLASS_CONSTRUCTOR:
- return factoryForContributionBindingInitialization(contributionBinding);
-
- default:
- throw new AssertionError();
- }
- }
-
- private CodeBlock factoryForContributionBindingInitialization(ContributionBinding binding) {
- TypeName bindingKeyTypeName = TypeName.get(binding.key().type());
- switch (binding.bindingKind()) {
- case COMPONENT:
- // This bindingKeyTypeName type parameter can be removed when we drop java 7 source support
- return CodeBlock.of("$T.<$T>create(this)", INSTANCE_FACTORY, bindingKeyTypeName);
-
- case COMPONENT_DEPENDENCY:
- return CodeBlock.of(
- "$T.create($L)",
- INSTANCE_FACTORY,
- componentRequirementFields.getExpressionDuringInitialization(
- ComponentRequirement.forDependency(binding.key().type()),
- generatedComponentModel.name()));
-
- case COMPONENT_PROVISION:
- {
- ComponentRequirement dependency = dependencyForBinding(binding);
- String componentMethod = binding.bindingElement().get().getSimpleName().toString();
- // TODO(sameb): The Provider.get() throws a very vague NPE. The stack trace doesn't
- // help to figure out what the method or return type is. If we include a string
- // of the return type or method name in the error message, that can defeat obfuscation.
- // We can easily include the raw type (no generics) + annotation type (no values),
- // using .class & String.format -- but that wouldn't be the whole story.
- // What should we do?
- CodeBlock invocation =
- ComponentProvisionBindingExpression.maybeCheckForNull(
- (ProvisionBinding) binding,
- compilerOptions,
- CodeBlock.of("$L.$L()", dependency.variableName(), componentMethod));
- ClassName dependencyClassName = ClassName.get(dependency.typeElement());
- String factoryName =
- dependencyClassName.toString().replace('.', '_') + "_" + componentMethod;
- MethodSpec.Builder getMethod =
- methodBuilder("get")
- .addAnnotation(Override.class)
- .addModifiers(PUBLIC)
- .returns(bindingKeyTypeName)
- .addStatement("return $L", invocation);
- if (binding.nullableType().isPresent()) {
- getMethod.addAnnotation(
- ClassName.get(MoreTypes.asTypeElement(binding.nullableType().get())));
- }
- generatedComponentModel.addType(
- COMPONENT_PROVISION_FACTORY,
- TypeSpec.classBuilder(factoryName)
- .addSuperinterface(providerOf(bindingKeyTypeName))
- .addModifiers(PRIVATE, STATIC)
- .addField(dependencyClassName, dependency.variableName(), PRIVATE, FINAL)
- .addMethod(
- constructorBuilder()
- .addParameter(dependencyClassName, dependency.variableName())
- .addStatement("this.$1L = $1L", dependency.variableName())
- .build())
- .addMethod(getMethod.build())
- .build());
- setFieldTypeReplacement(generatedComponentModel.name().nestedClass(factoryName));
- return CodeBlock.of(
- "new $L($L)",
- factoryName,
- componentRequirementFields.getExpressionDuringInitialization(
- dependency, generatedComponentModel.name()));
- }
-
- case SUBCOMPONENT_BUILDER:
- String subcomponentName =
- subcomponentNames.get(
- graph
- .componentDescriptor()
- .subcomponentsByBuilderType()
- .get(MoreTypes.asTypeElement(binding.key().type())));
- return anonymousProvider(
- bindingKeyTypeName, CodeBlock.of("return new $NBuilder();", subcomponentName));
-
- case BOUND_INSTANCE:
- return CodeBlock.of(
- "$T.$L($L)",
- InstanceFactory.class,
- binding.nullableType().isPresent() ? "createNullable" : "create",
- componentRequirementFields.getExpressionDuringInitialization(
- ComponentRequirement.forBoundInstance(binding), generatedComponentModel.name()));
-
- case INJECTION:
- case PROVISION:
- {
- List<CodeBlock> arguments =
- Lists.newArrayListWithCapacity(binding.explicitDependencies().size() + 1);
- if (binding.requiresModuleInstance()) {
- arguments.add(
- componentRequirementFields.getExpressionDuringInitialization(
- ComponentRequirement.forModule(binding.contributingModule().get().asType()),
- generatedComponentModel.name()));
- }
- arguments.addAll(getBindingDependencyExpressions(binding));
-
- CodeBlock factoryCreate =
- CodeBlock.of(
- "$T.create($L)",
- generatedClassNameForBinding(binding),
- makeParametersCodeBlock(arguments));
-
- // If scoping a parameterized factory for an @Inject class, Java 7 cannot always infer the
- // type properly, so cast to a raw framework type before scoping.
- if (binding.bindingKind().equals(INJECTION)
- && binding.unresolved().isPresent()
- && binding.scope().isPresent()) {
- factoryCreate =
- CodeBlock.of("($T) $L", binding.bindingType().frameworkClass(), factoryCreate);
- } else if (!binding.scope().isPresent()) {
- setFieldTypeReplacement(generatedClassNameForBinding(binding));
- }
- return decorateForScope(factoryCreate, binding.scope());
- }
-
- case COMPONENT_PRODUCTION:
- {
- ComponentRequirement dependency = dependencyForBinding(binding);
- FieldSpec dependencyField =
- FieldSpec.builder(
- ClassName.get(dependency.typeElement()),
- dependency.variableName(),
- PRIVATE,
- FINAL)
- .initializer(
- componentRequirementFields.getExpressionDuringInitialization(
- dependency, generatedComponentModel.name()))
- .build();
- // TODO(b/70395982): Explore using a private static type instead of an anonymous class.
- return CodeBlock.of(
- "$L",
- anonymousClassBuilder("")
- .superclass(producerOf(bindingKeyTypeName))
- .addField(dependencyField)
- .addMethod(
- methodBuilder("get")
- .addAnnotation(Override.class)
- .addModifiers(PUBLIC)
- .returns(listenableFutureOf(bindingKeyTypeName))
- .addStatement(
- "return $N.$L()",
- dependencyField,
- binding.bindingElement().get().getSimpleName())
- .build())
- .build());
- }
-
- case PRODUCTION:
- {
- List<CodeBlock> arguments =
- Lists.newArrayListWithCapacity(binding.dependencies().size() + 2);
- if (binding.requiresModuleInstance()) {
- arguments.add(
- componentRequirementFields.getExpressionDuringInitialization(
- ComponentRequirement.forModule(binding.contributingModule().get().asType()),
- generatedComponentModel.name()));
- }
- arguments.addAll(getBindingDependencyExpressions(binding));
-
- setFieldTypeReplacement(generatedClassNameForBinding(binding));
- return CodeBlock.of(
- "new $T($L)",
- generatedClassNameForBinding(binding),
- makeParametersCodeBlock(arguments));
- }
-
- case SYNTHETIC_MULTIBOUND_SET:
- return factoryForSetMultibindingInitialization(binding);
-
- case SYNTHETIC_MULTIBOUND_MAP:
- return factoryForMapMultibindingInitialization(binding);
-
- case SYNTHETIC_RELEASABLE_REFERENCE_MANAGER:
- return factoryForSyntheticReleasableReferenceManagerBindingInitialization(binding);
-
- case SYNTHETIC_RELEASABLE_REFERENCE_MANAGERS:
- return factoryForSyntheticSetOfReleasableReferenceManagersInitialization(binding);
-
- case SYNTHETIC_OPTIONAL_BINDING:
- return factoryForSyntheticOptionalBindingInitialization(binding);
-
- case MEMBERS_INJECTOR:
- return factoryForSyntheticMembersInjectorBinding(binding);
-
- default:
- throw new AssertionError(binding);
- }
- }
-
- /**
- * Maybe wraps the given creation code block in single/double check or reference releasing
- * providers.
- */
- private CodeBlock decorateForScope(CodeBlock factoryCreate, Optional<Scope> maybeScope) {
- if (!maybeScope.isPresent()) {
- return factoryCreate;
- }
- Scope scope = maybeScope.get();
- if (referenceReleasingManagerFields.requiresReleasableReferences(scope)) {
- return CodeBlock.of(
- "$T.create($L, $L)",
- REFERENCE_RELEASING_PROVIDER,
- factoryCreate,
- referenceReleasingManagerFields.getExpression(scope, generatedComponentModel.name()));
- } else {
- return CodeBlock.of(
- "$T.provider($L)", scope.isReusable() ? SINGLE_CHECK : DOUBLE_CHECK, factoryCreate);
- }
- }
-
- private ComponentRequirement dependencyForBinding(ContributionBinding binding) {
- return graph
- .componentDescriptor()
- .dependenciesByDependencyMethod()
- .get(binding.bindingElement().get());
- }
-
- private CodeBlock factoryForSetMultibindingInitialization(ContributionBinding binding) {
- CodeBlock.Builder builder = CodeBlock.builder().add("$T.", setFactoryClassName(binding));
- boolean useRawTypes = useRawType();
- if (!useRawTypes) {
- SetType setType = SetType.from(binding.key());
- builder.add(
- "<$T>",
- setType.elementsAreTypeOf(Produced.class)
- ? setType.unwrappedElementType(Produced.class)
- : setType.elementType());
- }
- int individualProviders = 0;
- int setProviders = 0;
- CodeBlock.Builder builderMethodCalls = CodeBlock.builder();
- for (FrameworkDependency frameworkDependency : binding.frameworkDependencies()) {
- ContributionType contributionType =
- graph.contributionBindings().get(frameworkDependency.key()).contributionType();
- String methodName;
- String methodNameSuffix = frameworkDependency.frameworkClass().getSimpleName();
- switch (contributionType) {
- case SET:
- individualProviders++;
- methodName = "add" + methodNameSuffix;
- break;
- case SET_VALUES:
- setProviders++;
- methodName = "addCollection" + methodNameSuffix;
- break;
- default:
- throw new AssertionError(frameworkDependency + " is not a set multibinding");
- }
-
- builderMethodCalls.add(
- ".$L($L)",
- methodName,
- potentiallyCast(
- useRawTypes,
- frameworkDependency.frameworkClass(),
- getDependencyExpression(frameworkDependency)));
- }
- builder.add("builder($L, $L)", individualProviders, setProviders);
- builder.add(builderMethodCalls.build());
- return builder.add(".build()").build();
- }
-
- private CodeBlock factoryForMapMultibindingInitialization(ContributionBinding binding) {
- ImmutableList<FrameworkDependency> frameworkDependencies = binding.frameworkDependencies();
-
- ImmutableList.Builder<CodeBlock> codeBlocks = ImmutableList.builder();
- MapType mapType = MapType.from(binding.key().type());
- CodeBlock.Builder builderCall = CodeBlock.builder().add("$T.", mapFactoryClassName(binding));
- boolean useRawTypes = useRawType();
- if (!useRawTypes) {
- // TODO(ronshapiro): either inline this into mapFactoryClassName, or add a
- // mapType.unwrappedValueType() method that doesn't require a framework type
- TypeMirror valueType = mapType.valueType();
- for (Class<?> frameworkClass :
- ImmutableSet.of(Provider.class, Producer.class, Produced.class)) {
- if (mapType.valuesAreTypeOf(frameworkClass)) {
- valueType = mapType.unwrappedValueType(frameworkClass);
- break;
- }
- }
- builderCall.add("<$T, $T>", mapType.keyType(), valueType);
- }
-
- if (binding.bindingType().equals(BindingType.PROVISION)) {
- builderCall.add("builder($L)", frameworkDependencies.size());
- } else {
- builderCall.add("builder()");
- }
- codeBlocks.add(builderCall.build());
-
- for (FrameworkDependency frameworkDependency : frameworkDependencies) {
- ContributionBinding contributionBinding =
- graph.contributionBindings().get(frameworkDependency.key()).contributionBinding();
- CodeBlock value =
- potentiallyCast(
- useRawTypes,
- frameworkDependency.frameworkClass(),
- getDependencyExpression(frameworkDependency));
- codeBlocks.add(
- CodeBlock.of(
- ".put($L, $L)",
- getMapKeyExpression(contributionBinding, generatedComponentModel.name()),
- value));
- }
- codeBlocks.add(CodeBlock.of(".build()"));
-
- return CodeBlocks.concat(codeBlocks.build());
- }
-
- // TODO(ronshapiro): Use functionality from Expression
- private CodeBlock potentiallyCast(boolean shouldCast, Class<?> classToCast, CodeBlock notCasted) {
- if (!shouldCast) {
- return notCasted;
- }
- return CodeBlock.of("($T) $L", classToCast, notCasted);
- }
-
- private boolean useRawType() {
-
- return !isTypeAccessibleFrom(
- resolvedBindings.key().type(), generatedComponentModel.name().packageName());
- }
-
- /**
- * Initializes the factory for a {@link
- * ContributionBinding.Kind#SYNTHETIC_RELEASABLE_REFERENCE_MANAGER} binding.
- *
- * <p>The {@code get()} method just returns the component field with the {@link
- * dagger.internal.ReferenceReleasingProviderManager} object.
- */
- private CodeBlock factoryForSyntheticReleasableReferenceManagerBindingInitialization(
- ContributionBinding binding) {
- // The scope is the value of the @ForReleasableReferences annotation.
- Scope scope = forReleasableReferencesAnnotationValue(binding.key().qualifier().get());
-
- CodeBlock managerExpression;
- if (MoreTypes.isTypeOf(TypedReleasableReferenceManager.class, binding.key().type())) {
- /* The key's type is TypedReleasableReferenceManager<M>, so return
- * new TypedReleasableReferenceManager(field, metadata). */
- TypeMirror metadataType =
- MoreTypes.asDeclared(binding.key().type()).getTypeArguments().get(0);
- managerExpression =
- typedReleasableReferenceManagerDecoratorExpression(
- referenceReleasingManagerFields.getExpression(scope, generatedComponentModel.name()),
- scope.releasableReferencesMetadata(metadataType).get());
- } else {
- // The key's type is ReleasableReferenceManager, so return the field as is.
- managerExpression =
- referenceReleasingManagerFields.getExpression(scope, generatedComponentModel.name());
- }
-
- return anonymousProvider(
- TypeName.get(binding.key().type()), CodeBlock.of("return $L;", managerExpression));
- }
-
- /**
- * Initializes the factory for a {@link
- * ContributionBinding.Kind#SYNTHETIC_RELEASABLE_REFERENCE_MANAGERS} binding.
- *
- * <p>A binding for {@code Set<ReleasableReferenceManager>} will include managers for all
- * reference-releasing scopes. A binding for {@code Set<TypedReleasableReferenceManager<M>>} will
- * include managers for all reference-releasing scopes whose metadata type is {@code M}.
- */
- private CodeBlock factoryForSyntheticSetOfReleasableReferenceManagersInitialization(
- ContributionBinding binding) {
- Key key = binding.key();
- SetType keyType = SetType.from(key);
- ImmutableList.Builder<CodeBlock> managerExpressions = ImmutableList.builder();
- for (Scope scope : graph.scopesRequiringReleasableReferenceManagers()) {
- CodeBlock releasableReferenceManagerExpression =
- referenceReleasingManagerFields.getExpression(scope, generatedComponentModel.name());
-
- if (keyType.elementsAreTypeOf(ReleasableReferenceManager.class)) {
- managerExpressions.add(releasableReferenceManagerExpression);
- } else if (keyType.elementsAreTypeOf(TypedReleasableReferenceManager.class)) {
- TypeMirror metadataType =
- keyType.unwrappedElementType(TypedReleasableReferenceManager.class);
- Optional<AnnotationMirror> metadata = scope.releasableReferencesMetadata(metadataType);
- if (metadata.isPresent()) {
- managerExpressions.add(
- typedReleasableReferenceManagerDecoratorExpression(
- releasableReferenceManagerExpression, metadata.get()));
- }
- } else {
- throw new IllegalArgumentException("inappropriate key: " + binding);
- }
- }
- TypeName keyTypeName = TypeName.get(key.type());
- CodeBlock body =
- CodeBlock.of(
- "return new $T($T.asList($L));",
- HashSet.class,
- Arrays.class,
- makeParametersCodeBlock(managerExpressions.build()));
- return anonymousProvider(keyTypeName, body);
- }
-
- /**
- * Returns an expression that evaluates to a {@link TypedReleasableReferenceManagerDecorator} that
- * decorates the {@code managerExpression} to supply {@code metadata}.
- */
- private CodeBlock typedReleasableReferenceManagerDecoratorExpression(
- CodeBlock managerExpression, AnnotationMirror metadata) {
- return CodeBlock.of(
- "new $T<$T>($L, $L)",
- TYPED_RELEASABLE_REFERENCE_MANAGER_DECORATOR,
- metadata.getAnnotationType(),
- managerExpression,
- new AnnotationExpression(metadata).getAnnotationInstanceExpression());
- }
-
- private Scope forReleasableReferencesAnnotationValue(AnnotationMirror annotation) {
- checkArgument(
- MoreTypes.isTypeOf(ForReleasableReferences.class, annotation.getAnnotationType()));
- return Scopes.scope(
- MoreElements.asType(MoreTypes.asDeclared(getTypeValue(annotation, "value")).asElement()));
- }
-
- /**
- * Returns an expression that initializes a {@link Provider} or {@link Producer} for an optional
- * binding.
- */
- private CodeBlock factoryForSyntheticOptionalBindingInitialization(ContributionBinding binding) {
- if (binding.explicitDependencies().isEmpty()) {
- verify(
- binding.bindingType().equals(BindingType.PROVISION),
- "Absent optional bindings should be provisions: %s",
- binding);
- return optionalFactories.absentOptionalProvider(binding);
- } else {
- return optionalFactories.presentOptionalFactory(
- binding, getDependencyExpression(getOnlyElement(binding.frameworkDependencies())));
- }
- }
-
- /**
- * Returns an expression that initializes a {@code Provider<MembersInjector<T>>} for a {@link
- * ContributionBinding.Kind#MEMBERS_INJECTOR} binding.
- */
- private CodeBlock factoryForSyntheticMembersInjectorBinding(ContributionBinding binding) {
- TypeMirror membersInjectedType =
- getOnlyElement(MoreTypes.asDeclared(binding.key().type()).getTypeArguments());
-
- CodeBlock membersInjector =
- ((ProvisionBinding) binding).injectionSites().isEmpty()
- ? CodeBlock.of("$T.<$T>noOp()", MEMBERS_INJECTORS, membersInjectedType)
- : CodeBlock.of(
- "$T.create($L)",
- membersInjectorNameForType(MoreTypes.asTypeElement(membersInjectedType)),
- makeParametersCodeBlock(getBindingDependencyExpressions(binding)));
-
- // TODO(ronshapiro): consider adding a MembersInjectorBindingExpression to return this directly
- // (as it's rarely requested as a Provider).
- return CodeBlock.of("$T.create($L)", INSTANCE_FACTORY, membersInjector);
- }
-}
diff --git a/java/dagger/internal/codegen/ReferenceReleasingManagerFields.java b/java/dagger/internal/codegen/ReferenceReleasingManagerFields.java
index d915a70..fe69621 100644
--- a/java/dagger/internal/codegen/ReferenceReleasingManagerFields.java
+++ b/java/dagger/internal/codegen/ReferenceReleasingManagerFields.java
@@ -23,6 +23,7 @@
import static dagger.internal.codegen.GeneratedComponentModel.FieldSpecKind.REFERENCE_RELEASING_MANAGER_FIELD;
import static dagger.internal.codegen.MemberSelect.localField;
import static dagger.internal.codegen.TypeNames.REFERENCE_RELEASING_PROVIDER_MANAGER;
+import static dagger.internal.codegen.TypeNames.TYPED_RELEASABLE_REFERENCE_MANAGER_DECORATOR;
import static dagger.internal.codegen.Util.reentrantComputeIfAbsent;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
@@ -30,9 +31,11 @@
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
+import dagger.internal.TypedReleasableReferenceManagerDecorator;
import dagger.model.Scope;
import java.util.HashMap;
import java.util.Map;
+import javax.lang.model.element.AnnotationMirror;
/**
* Manages the {@link dagger.internal.ReferenceReleasingProviderManager} fields and the logic for
@@ -60,6 +63,20 @@
}
/**
+ * Returns an expression that evaluates to a {@link TypedReleasableReferenceManagerDecorator} that
+ * decorates the {@code managerExpression} to supply {@code metadata}.
+ */
+ static CodeBlock typedReleasableReferenceManagerDecoratorExpression(
+ CodeBlock managerExpression, AnnotationMirror metadata) {
+ return CodeBlock.of(
+ "new $T<$T>($L, $L)",
+ TYPED_RELEASABLE_REFERENCE_MANAGER_DECORATOR,
+ metadata.getAnnotationType(),
+ managerExpression,
+ new AnnotationExpression(metadata).getAnnotationInstanceExpression());
+ }
+
+ /**
* Returns {@code true} if {@code scope} is in {@link
* BindingGraph#scopesRequiringReleasableReferenceManagers()} for the root graph.
*/
diff --git a/java/dagger/internal/codegen/ReleasableReferenceManagerProviderCreationExpression.java b/java/dagger/internal/codegen/ReleasableReferenceManagerProviderCreationExpression.java
new file mode 100644
index 0000000..083244c
--- /dev/null
+++ b/java/dagger/internal/codegen/ReleasableReferenceManagerProviderCreationExpression.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static com.squareup.javapoet.TypeSpec.anonymousClassBuilder;
+import static dagger.internal.codegen.MoreAnnotationMirrors.getTypeValue;
+import static dagger.internal.codegen.ReferenceReleasingManagerFields.typedReleasableReferenceManagerDecoratorExpression;
+import static dagger.internal.codegen.TypeNames.providerOf;
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import dagger.model.Scope;
+import dagger.releasablereferences.ForReleasableReferences;
+import dagger.releasablereferences.TypedReleasableReferenceManager;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * A {@link dagger.releasablereferences.ReleasableReferenceManager
+ * Provider<ReleasableReferenceManager>} creation expression.
+ *
+ * <p>The {@code get()} method just returns the component's {@link
+ * dagger.internal.ReferenceReleasingProviderManager} field.
+ */
+final class ReleasableReferenceManagerProviderCreationExpression
+ implements FrameworkInstanceCreationExpression {
+
+ private final ContributionBinding binding;
+ private final GeneratedComponentModel generatedComponentModel;
+ private final ReferenceReleasingManagerFields referenceReleasingManagerFields;
+
+ ReleasableReferenceManagerProviderCreationExpression(
+ ContributionBinding binding,
+ GeneratedComponentModel generatedComponentModel,
+ ReferenceReleasingManagerFields referenceReleasingManagerFields) {
+ this.binding = checkNotNull(binding);
+ this.generatedComponentModel = checkNotNull(generatedComponentModel);
+ this.referenceReleasingManagerFields = checkNotNull(referenceReleasingManagerFields);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ TypeName keyType = TypeName.get(binding.key().type());
+ return CodeBlock.of(
+ "$L",
+ anonymousClassBuilder("")
+ .addSuperinterface(providerOf(keyType))
+ .addMethod(
+ methodBuilder("get")
+ .addAnnotation(Override.class)
+ .addModifiers(PUBLIC)
+ .returns(keyType)
+ .addCode("return $L;", releasableReferenceManagerExpression())
+ .build())
+ .build());
+ }
+
+ private CodeBlock releasableReferenceManagerExpression() {
+ // The scope is the value of the @ForReleasableReferences annotation.
+ Scope scope = forReleasableReferencesAnnotationValue(binding.key().qualifier().get());
+
+ if (MoreTypes.isTypeOf(TypedReleasableReferenceManager.class, binding.key().type())) {
+ /* The key's type is TypedReleasableReferenceManager<M>, so return
+ * new TypedReleasableReferenceManager(field, metadata). */
+ TypeMirror metadataType =
+ MoreTypes.asDeclared(binding.key().type()).getTypeArguments().get(0);
+ return typedReleasableReferenceManagerDecoratorExpression(
+ referenceReleasingManagerFields.getExpression(scope, generatedComponentModel.name()),
+ scope.releasableReferencesMetadata(metadataType).get());
+ } else {
+ // The key's type is ReleasableReferenceManager, so return the field as is.
+ return referenceReleasingManagerFields.getExpression(scope, generatedComponentModel.name());
+ }
+ }
+
+ private Scope forReleasableReferencesAnnotationValue(AnnotationMirror annotation) {
+ checkArgument(
+ MoreTypes.isTypeOf(ForReleasableReferences.class, annotation.getAnnotationType()));
+ return Scopes.scope(
+ MoreElements.asType(MoreTypes.asDeclared(getTypeValue(annotation, "value")).asElement()));
+ }
+}
diff --git a/java/dagger/internal/codegen/ReleasableReferenceManagerSetProviderCreationExpression.java b/java/dagger/internal/codegen/ReleasableReferenceManagerSetProviderCreationExpression.java
new file mode 100644
index 0000000..078fd6b
--- /dev/null
+++ b/java/dagger/internal/codegen/ReleasableReferenceManagerSetProviderCreationExpression.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static com.squareup.javapoet.TypeSpec.anonymousClassBuilder;
+import static dagger.internal.codegen.CodeBlocks.makeParametersCodeBlock;
+import static dagger.internal.codegen.ReferenceReleasingManagerFields.typedReleasableReferenceManagerDecoratorExpression;
+import static dagger.internal.codegen.TypeNames.providerOf;
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+import com.google.common.collect.ImmutableList;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import dagger.model.Scope;
+import dagger.releasablereferences.ReleasableReferenceManager;
+import dagger.releasablereferences.TypedReleasableReferenceManager;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Optional;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * A {@link ReleasableReferenceManager Provider<Set<ReleasableReferenceManager>>} creation
+ * expression.
+ *
+ * <p>A binding for {@code Set<ReleasableReferenceManager>} will include managers for all
+ * reference-releasing scopes. A binding for {@code Set<TypedReleasableReferenceManager<M>>} will
+ * include managers for all reference-releasing scopes whose metadata type is {@code M}.
+ */
+final class ReleasableReferenceManagerSetProviderCreationExpression
+ implements FrameworkInstanceCreationExpression {
+ private final ContributionBinding binding;
+ private final BindingGraph graph;
+ private final GeneratedComponentModel generatedComponentModel;
+ private final ReferenceReleasingManagerFields referenceReleasingManagerFields;
+
+ ReleasableReferenceManagerSetProviderCreationExpression(
+ ContributionBinding binding,
+ GeneratedComponentModel generatedComponentModel,
+ ReferenceReleasingManagerFields referenceReleasingManagerFields,
+ BindingGraph graph) {
+ this.binding = checkNotNull(binding);
+ this.generatedComponentModel = checkNotNull(generatedComponentModel);
+ this.referenceReleasingManagerFields = checkNotNull(referenceReleasingManagerFields);
+ this.graph = checkNotNull(graph);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ TypeName keyType = TypeName.get(binding.key().type());
+ return CodeBlock.of(
+ "$L",
+ anonymousClassBuilder("")
+ .addSuperinterface(providerOf(keyType))
+ .addMethod(
+ methodBuilder("get")
+ .addAnnotation(Override.class)
+ .addModifiers(PUBLIC)
+ .returns(keyType)
+ .addCode(
+ "return new $T($T.asList($L));",
+ HashSet.class,
+ Arrays.class,
+ makeParametersCodeBlock(releasableReferenceManagerExpressions()))
+ .build())
+ .build());
+ }
+
+ private ImmutableList<CodeBlock> releasableReferenceManagerExpressions() {
+ SetType keyType = SetType.from(binding.key());
+ ImmutableList.Builder<CodeBlock> managerExpressions = ImmutableList.builder();
+ for (Scope scope : graph.scopesRequiringReleasableReferenceManagers()) {
+ CodeBlock releasableReferenceManagerExpression =
+ referenceReleasingManagerFields.getExpression(scope, generatedComponentModel.name());
+
+ if (keyType.elementsAreTypeOf(ReleasableReferenceManager.class)) {
+ managerExpressions.add(releasableReferenceManagerExpression);
+ } else if (keyType.elementsAreTypeOf(TypedReleasableReferenceManager.class)) {
+ TypeMirror metadataType =
+ keyType.unwrappedElementType(TypedReleasableReferenceManager.class);
+ Optional<AnnotationMirror> metadata = scope.releasableReferencesMetadata(metadataType);
+ if (metadata.isPresent()) {
+ managerExpressions.add(
+ typedReleasableReferenceManagerDecoratorExpression(
+ releasableReferenceManagerExpression, metadata.get()));
+ }
+ } else {
+ throw new IllegalArgumentException("inappropriate key: " + binding);
+ }
+ }
+ return managerExpressions.build();
+ }
+}
diff --git a/java/dagger/internal/codegen/SetFactoryCreationExpression.java b/java/dagger/internal/codegen/SetFactoryCreationExpression.java
new file mode 100644
index 0000000..e1a1618
--- /dev/null
+++ b/java/dagger/internal/codegen/SetFactoryCreationExpression.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.SourceFiles.setFactoryClassName;
+
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import dagger.producers.Produced;
+
+/** A factory creation expression for a multibound set. */
+// TODO(dpb): Resolve with MapFactoryCreationExpression.
+final class SetFactoryCreationExpression implements FrameworkInstanceCreationExpression {
+
+ private final GeneratedComponentModel generatedComponentModel;
+ private final ComponentBindingExpressions componentBindingExpressions;
+ private final BindingGraph graph;
+ private final ContributionBinding binding;
+
+ SetFactoryCreationExpression(
+ ContributionBinding binding,
+ GeneratedComponentModel generatedComponentModel,
+ ComponentBindingExpressions componentBindingExpressions,
+ BindingGraph graph) {
+ this.binding = checkNotNull(binding);
+ this.generatedComponentModel = checkNotNull(generatedComponentModel);
+ this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ this.graph = checkNotNull(graph);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ CodeBlock.Builder builder = CodeBlock.builder().add("$T.", setFactoryClassName(binding));
+ boolean useRawType = !generatedComponentModel.isTypeAccessible(binding.key().type());
+ if (!useRawType) {
+ SetType setType = SetType.from(binding.key());
+ builder.add(
+ "<$T>",
+ setType.elementsAreTypeOf(Produced.class)
+ ? setType.unwrappedElementType(Produced.class)
+ : setType.elementType());
+ }
+ int individualProviders = 0;
+ int setProviders = 0;
+ CodeBlock.Builder builderMethodCalls = CodeBlock.builder();
+ for (FrameworkDependency frameworkDependency : binding.frameworkDependencies()) {
+ ContributionType contributionType =
+ graph.contributionBindings().get(frameworkDependency.key()).contributionType();
+ String methodName;
+ String methodNameSuffix = frameworkDependency.frameworkClass().getSimpleName();
+ switch (contributionType) {
+ case SET:
+ individualProviders++;
+ methodName = "add" + methodNameSuffix;
+ break;
+ case SET_VALUES:
+ setProviders++;
+ methodName = "addCollection" + methodNameSuffix;
+ break;
+ default:
+ throw new AssertionError(frameworkDependency + " is not a set multibinding");
+ }
+
+ CodeBlock argument =
+ componentBindingExpressions
+ .getDependencyExpression(frameworkDependency, generatedComponentModel.name())
+ .codeBlock();
+ builderMethodCalls.add(
+ ".$L($L)",
+ methodName,
+ useRawType ? CodeBlocks.cast(argument, frameworkDependency.frameworkClass()) : argument);
+ }
+ builder.add("builder($L, $L)", individualProviders, setProviders);
+ builder.add(builderMethodCalls.build());
+ return builder.add(".build()").build();
+ }
+}
diff --git a/java/dagger/internal/codegen/SubcomponentBuilderProviderCreationExpression.java b/java/dagger/internal/codegen/SubcomponentBuilderProviderCreationExpression.java
new file mode 100644
index 0000000..90b9cdf
--- /dev/null
+++ b/java/dagger/internal/codegen/SubcomponentBuilderProviderCreationExpression.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static dagger.internal.codegen.CodeBlocks.anonymousProvider;
+
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import javax.lang.model.type.TypeMirror;
+
+/** A {@link javax.inject.Provider} creation expression for a subcomponent builder.. */
+final class SubcomponentBuilderProviderCreationExpression
+ implements FrameworkInstanceCreationExpression {
+ private final String subcomponentName;
+ private final TypeMirror subcomponentBuilderType;
+
+ SubcomponentBuilderProviderCreationExpression(
+ TypeMirror subcomponentBuilderType, String subcomponentName) {
+ this.subcomponentName = subcomponentName;
+ this.subcomponentBuilderType = subcomponentBuilderType;
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ return anonymousProvider(
+ TypeName.get(subcomponentBuilderType),
+ CodeBlock.of("return new $LBuilder();", subcomponentName));
+ }
+}