diff --git a/java/dagger/internal/codegen/AbstractComponentWriter.java b/java/dagger/internal/codegen/AbstractComponentWriter.java index dfbc86c644c..e6481b9accf 100644 --- a/java/dagger/internal/codegen/AbstractComponentWriter.java +++ b/java/dagger/internal/codegen/AbstractComponentWriter.java @@ -62,9 +62,7 @@ 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.providerOf; -import static dagger.internal.codegen.TypeSpecs.addSupertype; import static dagger.internal.codegen.Util.toImmutableList; -import static javax.lang.model.element.Modifier.ABSTRACT; import static javax.lang.model.element.Modifier.FINAL; import static javax.lang.model.element.Modifier.PRIVATE; import static javax.lang.model.element.Modifier.PUBLIC; @@ -78,7 +76,6 @@ import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -96,8 +93,6 @@ import dagger.internal.InstanceFactory; import dagger.internal.Preconditions; import dagger.internal.TypedReleasableReferenceManagerDecorator; -import dagger.internal.codegen.ComponentDescriptor.BuilderRequirementMethod; -import dagger.internal.codegen.ComponentDescriptor.BuilderSpec; import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor; import dagger.producers.Produced; import dagger.producers.Producer; @@ -122,7 +117,6 @@ import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.ExecutableType; -import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; @@ -130,10 +124,6 @@ /** Creates the implementation class for a component or subcomponent. */ abstract class AbstractComponentWriter implements HasBindingMembers { - private static final String NOOP_BUILDER_METHOD_JAVADOC = - "This module is declared, but an instance is not used in the component. This method is a " - + "no-op. For more, see https://google.github.io/dagger/unused-modules.\n"; - // TODO(dpb): Make all these fields private after refactoring is complete. protected final Elements elements; protected final Types types; @@ -149,8 +139,8 @@ abstract class AbstractComponentWriter implements HasBindingMembers { private final Map producerFromProviderMemberSelects = new HashMap<>(); private final RequestFulfillmentRegistry requestFulfillmentRegistry; protected final MethodSpec.Builder constructor = constructorBuilder().addModifiers(PRIVATE); - protected Optional builderName = Optional.empty(); private final OptionalFactories optionalFactories; + private ComponentBuilder builder; private boolean done; /** @@ -315,7 +305,9 @@ protected CodeBlock getReferenceReleasingProviderManagerExpression(Scope scope) final TypeSpec.Builder write() { checkState(!done, "ComponentWriter has already been generated."); decorateComponent(); - addBuilder(); + if (hasBuilder()) { + addBuilder(); + } addFactoryMethods(); addReferenceReleasingProviderManagerFields(); addFrameworkFields(); @@ -336,30 +328,21 @@ final TypeSpec.Builder write() { */ protected abstract void decorateComponent(); + private boolean hasBuilder() { + ComponentDescriptor component = graph.componentDescriptor(); + return component.kind().isTopLevel() || component.builderSpec().isPresent(); + } + /** * Adds a builder type. */ - protected void addBuilder() { - builderName = Optional.of(builderName()); - TypeSpec.Builder componentBuilder = - createBuilder(builderName.get().simpleName()).addModifiers(FINAL); - - Optional builderSpec = graph.componentDescriptor().builderSpec(); - if (builderSpec.isPresent()) { - componentBuilder.addModifiers(PRIVATE); - addSupertype(componentBuilder, builderSpec.get().builderDefinitionType()); - } else { - componentBuilder - .addModifiers(PUBLIC) - .addMethod(constructorBuilder().addModifiers(PRIVATE).build()); - } + private void addBuilder() { + builder = ComponentBuilder.create(name, graph, subcomponentNames, elements, types); + builderFields = builder.builderFields(); - builderFields = addBuilderFields(componentBuilder); - addBuildMethod(componentBuilder, builderSpec); - addBuilderMethods(componentBuilder, builderSpec); - addBuilderClass(componentBuilder.build()); + addBuilderClass(builder.typeSpec()); - constructor.addParameter(builderName.get(), "builder"); + constructor.addParameter(builderName(), "builder"); constructor.addStatement("assert builder != null"); } @@ -369,173 +352,10 @@ protected void addBuilder() { */ protected abstract void addBuilderClass(TypeSpec builder); - /** - * Adds fields for each of the {@linkplain BindingGraph#componentRequirements component - * requirements}. Regardless of builder spec, there is always one field per requirement. - */ - private ImmutableMap addBuilderFields( - TypeSpec.Builder componentBuilder) { - UniqueNameSet builderFieldNames = new UniqueNameSet(); - ImmutableMap.Builder builderFields = ImmutableMap.builder(); - for (ComponentRequirement componentRequirement : graph.componentRequirements()) { - String contributionName = - builderFieldNames.getUniqueName(componentRequirement.variableName()); - FieldSpec builderField = - FieldSpec.builder(TypeName.get(componentRequirement.type()), contributionName, PRIVATE) - .build(); - componentBuilder.addField(builderField); - builderFields.put(componentRequirement, builderField); - } - return builderFields.build(); - } - - /** Adds the build method to the builder. */ - private void addBuildMethod( - TypeSpec.Builder componentBuilder, Optional builderSpec) { - MethodSpec.Builder buildMethod; - if (builderSpec.isPresent()) { - ExecutableElement specBuildMethod = builderSpec.get().buildMethod(); - // Note: we don't use the specBuildMethod.getReturnType() as the return type - // because it might be a type variable. We make use of covariant returns to allow - // us to return the component type, which will always be valid. - buildMethod = - methodBuilder(specBuildMethod.getSimpleName().toString()).addAnnotation(Override.class); - } else { - buildMethod = methodBuilder("build"); - } - buildMethod.returns(componentDefinitionTypeName()).addModifiers(PUBLIC); - - for (Map.Entry builderFieldEntry : builderFields.entrySet()) { - FieldSpec builderField = builderFieldEntry.getValue(); - switch (builderFieldEntry.getKey().nullPolicy(elements, types)) { - case NEW: - buildMethod.addCode( - "if ($1N == null) { this.$1N = new $2T(); }", builderField, builderField.type); - break; - case THROW: - buildMethod.addCode( - "if ($N == null) { throw new $T($T.class.getCanonicalName() + $S); }", - builderField, - IllegalStateException.class, - TypeNames.rawTypeName(builderField.type), - " must be set"); - break; - case ALLOW: - break; - default: - throw new AssertionError(builderFieldEntry.getKey()); - } - } - buildMethod.addStatement("return new $T(this)", name); - componentBuilder.addMethod(buildMethod.build()); - } - - /** - * Adds the methods that set each of parameters on the builder. If the {@link BuilderSpec} is - * present, it will tailor the methods to match the spec. - */ - private void addBuilderMethods( - TypeSpec.Builder componentBuilder, Optional builderSpec) { - ImmutableSet componentRequirements = graph.componentRequirements(); - if (builderSpec.isPresent()) { - UniqueNameSet parameterNames = new UniqueNameSet(); - for (BuilderRequirementMethod requirementMethod : builderSpec.get().requirementMethods()) { - ComponentRequirement builderRequirement = requirementMethod.requirement(); - ExecutableElement specMethod = requirementMethod.method(); - MethodSpec.Builder builderMethod = addBuilderMethodFromSpec(specMethod); - VariableElement parameterElement = Iterables.getOnlyElement(specMethod.getParameters()); - String parameterName = parameterNames.getUniqueName(parameterElement.getSimpleName()); - - TypeName argType = - parameterElement.asType().getKind().isPrimitive() - // Primitives need to use the original (unresolved) type to avoid boxing. - ? TypeName.get(parameterElement.asType()) - // Otherwise we use the full resolved type. - : TypeName.get(builderRequirement.type()); - - builderMethod.addParameter(argType, parameterName); - if (componentRequirements.contains(builderRequirement)) { - // required type - builderMethod.addStatement( - "this.$N = $L", - builderFields.get(builderRequirement), - builderRequirement - .nullPolicy(elements, types) - .equals(ComponentRequirement.NullPolicy.ALLOW) - ? parameterName - : CodeBlock.of("$T.checkNotNull($L)", Preconditions.class, parameterName)); - addBuilderMethodReturnStatementForSpec(specMethod, builderMethod); - } else if (graph.ownedModuleTypes().contains(builderRequirement.typeElement())) { - // owned, but not required - builderMethod.addJavadoc(NOOP_BUILDER_METHOD_JAVADOC); - addBuilderMethodReturnStatementForSpec(specMethod, builderMethod); - } else { - // neither owned nor required, so it must be an inherited module - builderMethod.addStatement( - "throw new $T($T.format($S, $T.class.getCanonicalName()))", - UnsupportedOperationException.class, - String.class, - "%s cannot be set because it is inherited from the enclosing component", - TypeNames.rawTypeName(TypeName.get(builderRequirement.type()))); - } - componentBuilder.addMethod(builderMethod.build()); - } - } else { - for (ComponentRequirement componentRequirement : graph.availableDependencies()) { - String componentRequirementName = simpleVariableName(componentRequirement.typeElement()); - MethodSpec.Builder builderMethod = - methodBuilder(componentRequirementName) - .returns(builderName.get()) - .addModifiers(PUBLIC) - .addParameter(ClassName.get(componentRequirement.type()), componentRequirementName); - if (componentRequirements.contains(componentRequirement)) { - builderMethod.addStatement( - "this.$N = $T.checkNotNull($L)", - builderFields.get(componentRequirement), - Preconditions.class, - componentRequirementName); - } else { - builderMethod.addStatement("$T.checkNotNull($L)", - Preconditions.class, - componentRequirementName); - builderMethod.addJavadoc("@deprecated " + NOOP_BUILDER_METHOD_JAVADOC); - builderMethod.addAnnotation(Deprecated.class); - } - builderMethod.addStatement("return this"); - componentBuilder.addMethod(builderMethod.build()); - } - } - } - - private void addBuilderMethodReturnStatementForSpec( - ExecutableElement specMethod, MethodSpec.Builder builderMethod) { - if (!specMethod.getReturnType().getKind().equals(VOID)) { - builderMethod.addStatement("return this"); - } - } - - private MethodSpec.Builder addBuilderMethodFromSpec(ExecutableElement method) { - TypeMirror returnType = method.getReturnType(); - MethodSpec.Builder builderMethod = - methodBuilder(method.getSimpleName().toString()) - .addAnnotation(Override.class) - .addModifiers(Sets.difference(method.getModifiers(), ImmutableSet.of(ABSTRACT))); - // If the return type is void, we add a method with the void return type. - // Otherwise we use the generated builder name and take advantage of covariant returns - // (so that we don't have to worry about setter methods that return type variables). - if (!returnType.getKind().equals(TypeKind.VOID)) { - builderMethod.returns(builderName.get()); - } - return builderMethod; + protected final ClassName builderName() { + return builder.name(); } - /** - * Creates the builder class. - */ - protected abstract TypeSpec.Builder createBuilder(String builderName); - - protected abstract ClassName builderName(); - /** * Adds component factory methods. */ @@ -838,8 +658,8 @@ private void initializeFrameworkTypes() { * separate fields and initilization as we do now. */ .addAnnotation(AnnotationSpecs.suppressWarnings(UNCHECKED)) .addCode(CodeBlocks.concat(partition)); - if (builderName.isPresent()) { - initializeMethod.addParameter(builderName.get(), "builder", FINAL); + if (hasBuilder()) { + initializeMethod.addParameter(builderName(), "builder", FINAL); constructor.addStatement("$L(builder)", methodName); } else { constructor.addStatement("$L()", methodName); diff --git a/java/dagger/internal/codegen/ComponentBuilder.java b/java/dagger/internal/codegen/ComponentBuilder.java new file mode 100644 index 00000000000..c818891af27 --- /dev/null +++ b/java/dagger/internal/codegen/ComponentBuilder.java @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2017 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.squareup.javapoet.MethodSpec.constructorBuilder; +import static com.squareup.javapoet.MethodSpec.methodBuilder; +import static com.squareup.javapoet.TypeSpec.classBuilder; +import static dagger.internal.codegen.SourceFiles.simpleVariableName; +import static dagger.internal.codegen.TypeSpecs.addSupertype; +import static javax.lang.model.element.Modifier.ABSTRACT; +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 static javax.lang.model.type.TypeKind.VOID; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; +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.Preconditions; +import dagger.internal.codegen.ComponentDescriptor.BuilderRequirementMethod; +import dagger.internal.codegen.ComponentDescriptor.BuilderSpec; +import java.util.Optional; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; + +/** Models the generated code for a component builder. */ +final class ComponentBuilder { + private final TypeSpec typeSpec; + private final ClassName name; + private final ImmutableMap builderFields; + + private ComponentBuilder( + TypeSpec typeSpec, + ClassName name, + ImmutableMap builderFields) { + this.typeSpec = typeSpec; + this.name = name; + this.builderFields = builderFields; + } + + TypeSpec typeSpec() { + return typeSpec; + } + + ClassName name() { + return name; + } + + ImmutableMap builderFields() { + return builderFields; + } + + static ComponentBuilder create( + ClassName componentName, + BindingGraph graph, + ImmutableMap subcomponentNames, + Elements elements, + Types types) { + return new Creator(componentName, graph, subcomponentNames, elements, types).create(); + } + + private static final class Creator { + private static final String NOOP_BUILDER_METHOD_JAVADOC = + "This module is declared, but an instance is not used in the component. This method is a " + + "no-op. For more, see https://google.github.io/dagger/unused-modules.\n"; + private final BindingGraph graph; + private final TypeSpec.Builder builder; + private final ClassName componentName; + private final ClassName builderName; + private final Elements elements; + private final Types types; + private ImmutableMap builderFields; + + Creator( + ClassName componentName, + BindingGraph graph, + ImmutableMap subcomponentNames, + Elements elements, + Types types) { + this.componentName = componentName; + if (graph.componentDescriptor().kind().isTopLevel()) { + builderName = componentName.nestedClass("Builder"); + builder = classBuilder(builderName).addModifiers(STATIC); + } else { + builderName = + componentName.peerClass(subcomponentNames.get(graph.componentDescriptor()) + "Builder"); + builder = classBuilder(builderName); + } + this.graph = graph; + this.elements = elements; + this.types = types; + } + + ComponentBuilder create() { + if (builderSpec().isPresent()) { + builder.addModifiers(PRIVATE); + addSupertype(builder, builderSpec().get().builderDefinitionType()); + } else { + builder.addModifiers(PUBLIC).addMethod(constructorBuilder().addModifiers(PRIVATE).build()); + } + + builderFields = builderFields(graph); + + builder + .addModifiers(FINAL) + .addFields(builderFields.values()) + .addMethod(buildMethod()) + // TODO(ronshapiro): this should be switched with buildMethod(), but that currently breaks + // compile-testing tests that rely on the order of the methods + .addMethods(builderMethods()); + + return new ComponentBuilder(builder.build(), builderName, builderFields); + } + + /** + * Computes fields for each of the {@linkplain BindingGraph#componentRequirements component + * requirements}. Regardless of builder spec, there is always one field per requirement. + */ + private static ImmutableMap builderFields(BindingGraph graph) { + UniqueNameSet fieldNames = new UniqueNameSet(); + ImmutableMap.Builder builderFields = ImmutableMap.builder(); + for (ComponentRequirement componentRequirement : graph.componentRequirements()) { + String name = fieldNames.getUniqueName(componentRequirement.variableName()); + builderFields.put( + componentRequirement, + FieldSpec.builder(TypeName.get(componentRequirement.type()), name, PRIVATE).build()); + } + return builderFields.build(); + } + + private MethodSpec buildMethod() { + MethodSpec.Builder buildMethod; + if (builderSpec().isPresent()) { + ExecutableElement specBuildMethod = builderSpec().get().buildMethod(); + // Note: we don't use the specBuildMethod.getReturnType() as the return type + // because it might be a type variable. We make use of covariant returns to allow + // us to return the component type, which will always be valid. + buildMethod = + methodBuilder(specBuildMethod.getSimpleName().toString()).addAnnotation(Override.class); + } else { + buildMethod = methodBuilder("build"); + } + buildMethod.returns(ClassName.get(graph.componentType())).addModifiers(PUBLIC); + + builderFields.forEach( + (requirement, builderField) -> { + switch (requirement.nullPolicy(elements, types)) { + case NEW: + buildMethod.addCode( + "if ($1N == null) { this.$1N = new $2T(); }", builderField, builderField.type); + break; + case THROW: + buildMethod.addCode( + "if ($N == null) { throw new $T($T.class.getCanonicalName() + $S); }", + builderField, + IllegalStateException.class, + TypeNames.rawTypeName(builderField.type), + " must be set"); + break; + case ALLOW: + break; + default: + throw new AssertionError(requirement); + } + }); + buildMethod.addStatement("return new $T(this)", componentName); + return buildMethod.build(); + } + + /** + * Computes the methods that set each of parameters on the builder. If the {@link BuilderSpec} + * is present, it will tailor the methods to match the spec. + */ + private ImmutableSet builderMethods() { + ImmutableSet componentRequirements = graph.componentRequirements(); + ImmutableSet.Builder methods = ImmutableSet.builder(); + if (builderSpec().isPresent()) { + UniqueNameSet parameterNames = new UniqueNameSet(); + for (BuilderRequirementMethod requirementMethod : + builderSpec().get().requirementMethods()) { + ComponentRequirement builderRequirement = requirementMethod.requirement(); + ExecutableElement specMethod = requirementMethod.method(); + MethodSpec.Builder builderMethod = addBuilderMethodFromSpec(specMethod); + VariableElement parameterElement = Iterables.getOnlyElement(specMethod.getParameters()); + String parameterName = parameterNames.getUniqueName(parameterElement.getSimpleName()); + + TypeName argType = + parameterElement.asType().getKind().isPrimitive() + // Primitives need to use the original (unresolved) type to avoid boxing. + ? TypeName.get(parameterElement.asType()) + // Otherwise we use the full resolved type. + : TypeName.get(builderRequirement.type()); + + builderMethod.addParameter(argType, parameterName); + if (componentRequirements.contains(builderRequirement)) { + // required type + builderMethod.addStatement( + "this.$N = $L", + builderFields.get(builderRequirement), + builderRequirement + .nullPolicy(elements, types) + .equals(ComponentRequirement.NullPolicy.ALLOW) + ? parameterName + : CodeBlock.of("$T.checkNotNull($L)", Preconditions.class, parameterName)); + addBuilderMethodReturnStatementForSpec(specMethod, builderMethod); + } else if (graph.ownedModuleTypes().contains(builderRequirement.typeElement())) { + // owned, but not required + builderMethod.addJavadoc(NOOP_BUILDER_METHOD_JAVADOC); + addBuilderMethodReturnStatementForSpec(specMethod, builderMethod); + } else { + // neither owned nor required, so it must be an inherited module + builderMethod.addStatement( + "throw new $T($T.format($S, $T.class.getCanonicalName()))", + UnsupportedOperationException.class, + String.class, + "%s cannot be set because it is inherited from the enclosing component", + TypeNames.rawTypeName(TypeName.get(builderRequirement.type()))); + } + methods.add(builderMethod.build()); + } + } else { + for (ComponentRequirement componentRequirement : graph.availableDependencies()) { + String componentRequirementName = simpleVariableName(componentRequirement.typeElement()); + MethodSpec.Builder builderMethod = + methodBuilder(componentRequirementName) + .returns(builderName) + .addModifiers(PUBLIC) + .addParameter( + ClassName.get(componentRequirement.type()), componentRequirementName); + if (componentRequirements.contains(componentRequirement)) { + builderMethod.addStatement( + "this.$N = $T.checkNotNull($L)", + builderFields.get(componentRequirement), + Preconditions.class, + componentRequirementName); + } else { + builderMethod.addStatement( + "$T.checkNotNull($L)", Preconditions.class, componentRequirementName); + builderMethod.addJavadoc("@deprecated " + NOOP_BUILDER_METHOD_JAVADOC); + builderMethod.addAnnotation(Deprecated.class); + } + builderMethod.addStatement("return this"); + methods.add(builderMethod.build()); + } + } + return methods.build(); + } + + private MethodSpec.Builder addBuilderMethodFromSpec(ExecutableElement method) { + TypeMirror returnType = method.getReturnType(); + MethodSpec.Builder builderMethod = + methodBuilder(method.getSimpleName().toString()) + .addAnnotation(Override.class) + .addModifiers(Sets.difference(method.getModifiers(), ImmutableSet.of(ABSTRACT))); + // If the return type is void, we add a method with the void return type. + // Otherwise we use the generated builder name and take advantage of covariant returns + // (so that we don't have to worry about setter methods that return type variables). + if (!returnType.getKind().equals(VOID)) { + builderMethod.returns(builderName); + } + return builderMethod; + } + + private static void addBuilderMethodReturnStatementForSpec( + ExecutableElement specMethod, MethodSpec.Builder builderMethod) { + if (!specMethod.getReturnType().getKind().equals(VOID)) { + builderMethod.addStatement("return this"); + } + } + + private Optional builderSpec() { + return graph.componentDescriptor().builderSpec(); + } + } +} diff --git a/java/dagger/internal/codegen/ComponentWriter.java b/java/dagger/internal/codegen/ComponentWriter.java index f1c8b9b0f50..54ce2c174c1 100644 --- a/java/dagger/internal/codegen/ComponentWriter.java +++ b/java/dagger/internal/codegen/ComponentWriter.java @@ -17,7 +17,6 @@ package dagger.internal.codegen; import static com.squareup.javapoet.MethodSpec.methodBuilder; -import static com.squareup.javapoet.TypeSpec.classBuilder; import static dagger.internal.codegen.TypeSpecs.addSupertype; import static java.lang.Character.isUpperCase; import static java.lang.String.format; @@ -186,15 +185,7 @@ protected void decorateComponent() { addSupertype(component, graph.componentType()); } - @Override - protected ClassName builderName() { - return name.nestedClass("Builder"); - } - - @Override - protected TypeSpec.Builder createBuilder(String builderSimpleName) { - TypeSpec.Builder builder = classBuilder(builderSimpleName).addModifiers(STATIC); - + private void addBuilderFactoryMethod() { // Only top-level components have the factory builder() method. // Mirror the user's builder API type if they had one. MethodSpec builderFactoryMethod = @@ -203,12 +194,11 @@ protected TypeSpec.Builder createBuilder(String builderSimpleName) { .returns( graph.componentDescriptor().builderSpec().isPresent() ? ClassName.get( - graph.componentDescriptor().builderSpec().get().builderDefinitionType()) - : builderName.get()) - .addStatement("return new $T()", builderName.get()) + graph.componentDescriptor().builderSpec().get().builderDefinitionType()) + : builderName()) + .addStatement("return new $T()", builderName()) .build(); component.addMethod(builderFactoryMethod); - return builder; } @Override @@ -218,6 +208,7 @@ protected void addBuilderClass(TypeSpec builder) { @Override protected void addFactoryMethods() { + addBuilderFactoryMethod(); if (canInstantiateAllRequirements()) { CharSequence buildMethodName = graph.componentDescriptor().builderSpec().isPresent() diff --git a/java/dagger/internal/codegen/SubcomponentWriter.java b/java/dagger/internal/codegen/SubcomponentWriter.java index 8f143819c10..4bfdb72ecc5 100644 --- a/java/dagger/internal/codegen/SubcomponentWriter.java +++ b/java/dagger/internal/codegen/SubcomponentWriter.java @@ -18,10 +18,8 @@ import static com.google.common.base.CaseFormat.LOWER_CAMEL; import static com.google.common.base.Preconditions.checkState; -import static com.google.common.base.Verify.verify; import static com.google.common.collect.Sets.difference; import static com.squareup.javapoet.MethodSpec.methodBuilder; -import static com.squareup.javapoet.TypeSpec.classBuilder; import static dagger.internal.codegen.AbstractComponentWriter.InitializationState.UNINITIALIZED; import static dagger.internal.codegen.CodeBlocks.makeParametersCodeBlock; import static dagger.internal.codegen.MemberSelect.localField; @@ -128,26 +126,6 @@ protected void decorateComponent() { : resolvedSubcomponentFactoryMethod().getReturnType())); } - @Override - protected void addBuilder() { - // Only write subcomponent builders if there is a spec. - if (graph.componentDescriptor().builderSpec().isPresent()) { - super.addBuilder(); - } - } - - @Override - protected ClassName builderName() { - return name.peerClass(subcomponentNames.get(graph.componentDescriptor()) + "Builder"); - } - - @Override - protected TypeSpec.Builder createBuilder(String builderSimpleName) { - // Only write subcomponent builders if there is a spec. - verify(graph.componentDescriptor().builderSpec().isPresent()); - return classBuilder(builderSimpleName); - } - @Override protected void addBuilderClass(TypeSpec builder) { parent.component.addType(builder);