From 4056f5d826b0ab3338ea66edba41aa0820ad5e46 Mon Sep 17 00:00:00 2001 From: jbock Date: Thu, 30 Nov 2023 14:13:56 +0100 Subject: [PATCH] ISSUES-4 builder build uses mock --- .../simple/processor/writing/BuilderImpl.java | 121 ++++++++++++++---- .../processor/writing/ComponentImpl.java | 11 +- .../simple/processor/writing/MockBuilder.java | 2 +- .../jbock/simple/processor/BuilderTest.java | 4 +- 4 files changed, 107 insertions(+), 31 deletions(-) diff --git a/compiler/src/main/java/io/jbock/simple/processor/writing/BuilderImpl.java b/compiler/src/main/java/io/jbock/simple/processor/writing/BuilderImpl.java index 9449240..e21dc34 100644 --- a/compiler/src/main/java/io/jbock/simple/processor/writing/BuilderImpl.java +++ b/compiler/src/main/java/io/jbock/simple/processor/writing/BuilderImpl.java @@ -42,54 +42,125 @@ private BuilderImpl( } TypeSpec generate(BuilderElement builder, MockBuilder mockBuilder) { + if (component.omitMockBuilder()) { + return generateNoMock(builder); + } else { + return generateMock(builder, mockBuilder); + } + } + + private TypeSpec generateMock(BuilderElement builder, MockBuilder mockBuilder) { TypeMirror builderType = builder.element().asType(); TypeSpec.Builder spec = TypeSpec.classBuilder(builder.generatedClass()); - if (!component.omitMockBuilder()) { - FieldSpec field = FieldSpec.builder(mockBuilder.getClassName(), "mockBuilder", FINAL).build(); - spec.addField(field); - ParameterSpec param = ParameterSpec.builder(mockBuilder.getClassName(), "mockBuilder").build(); - spec.addMethod(MethodSpec.constructorBuilder() - .addParameter(param) - .addStatement("this.$N = $N", field, param) - .build()); - } + FieldSpec mockBuilderField = FieldSpec.builder(mockBuilder.getClassName(), "mockBuilder", FINAL).build(); + spec.addField(mockBuilderField); + ParameterSpec mockBuilderParam = ParameterSpec.builder(mockBuilder.getClassName(), "mockBuilder").build(); + spec.addMethod(MethodSpec.constructorBuilder() + .addParameter(mockBuilderParam) + .addStatement("this.$N = $N", mockBuilderField, mockBuilderParam) + .build()); MethodSpec.Builder buildMethod = MethodSpec.methodBuilder(builder.buildMethod().getSimpleName().toString()); - List constructorParameters = new ArrayList<>(); for (NamedBinding namedBinding : sorted.values()) { Binding b = namedBinding.binding(); + if (b instanceof ParameterBinding) { + continue; + } Key key = b.key(); CodeBlock invocation = b.invocation(names); ParameterSpec param = names.apply(key); - if (namedBinding.isComponentRequest()) { - constructorParameters.add(CodeBlock.of("$N", names.apply(key))); - } - if (b instanceof ParameterBinding) { - spec.addField(FieldSpec.builder(b.key().typeName(), names.apply(b.key()).name).build()); - MethodSpec.Builder setterMethod = MethodSpec.methodBuilder(b.element().getSimpleName().toString()); - setterMethod.addAnnotation(Override.class); - setterMethod.addParameter(names.apply(b.key())); - setterMethod.addStatement("this.$N = $N", names.apply(b.key()), names.apply(b.key())); - setterMethod.addStatement("return this"); - setterMethod.returns(TypeName.get(builderType)); - setterMethod.addModifiers(b.element().getModifiers().stream() - .filter(m -> m == PUBLIC || m == PROTECTED).collect(Collectors.toList())); - spec.addMethod(setterMethod.build()); + if (!key.typeName().isPrimitive()) { + buildMethod.addStatement("$1T $2N = this.$3N != null && this.$3N.$2N != null ? this.$3N.$2N : $4L", + key.typeName(), param, mockBuilderField, invocation); } else { + FieldSpec auxField = FieldSpec.builder(TypeName.BOOLEAN, namedBinding.auxName(), PRIVATE).build(); + buildMethod.addStatement("$1T $2N = this.$3N != null && this.$3N.$4N ? this.$3N.$2N : $5L", + key.typeName(), param, mockBuilderField, auxField, invocation); + } + } + spec.addFields(fields()); + spec.addMethods(setterMethods(builder)); + spec.addModifiers(PRIVATE, STATIC, FINAL); + spec.addSuperinterface(builderType); + buildMethod.addAnnotation(Override.class); + buildMethod.addModifiers(builder.buildMethod().getModifiers().stream() + .filter(m -> m == PUBLIC || m == PROTECTED).collect(Collectors.toList())); + buildMethod.returns(TypeName.get(component.element().asType())); + buildMethod.addStatement("return new $T($L)", component.generatedClass(), constructorParameters().stream() + .collect(CodeBlock.joining(", "))); + spec.addMethod(buildMethod.build()); + return spec.build(); + } + + private TypeSpec generateNoMock(BuilderElement builder) { + TypeMirror builderType = builder.element().asType(); + TypeSpec.Builder spec = TypeSpec.classBuilder(builder.generatedClass()); + MethodSpec.Builder buildMethod = MethodSpec.methodBuilder(builder.buildMethod().getSimpleName().toString()); + for (NamedBinding namedBinding : sorted.values()) { + Binding b = namedBinding.binding(); + Key key = b.key(); + CodeBlock invocation = b.invocation(names); + ParameterSpec param = names.apply(key); + if (!(b instanceof ParameterBinding)) { buildMethod.addStatement("$T $N = $L", key.typeName(), param, invocation); } } + spec.addFields(fields()); + spec.addMethods(setterMethods(builder)); spec.addModifiers(PRIVATE, STATIC, FINAL); spec.addSuperinterface(builderType); buildMethod.addAnnotation(Override.class); buildMethod.addModifiers(builder.buildMethod().getModifiers().stream() .filter(m -> m == PUBLIC || m == PROTECTED).collect(Collectors.toList())); buildMethod.returns(TypeName.get(component.element().asType())); - buildMethod.addStatement("return new $T($L)", component.generatedClass(), constructorParameters.stream() + buildMethod.addStatement("return new $T($L)", component.generatedClass(), constructorParameters().stream() .collect(CodeBlock.joining(", "))); spec.addMethod(buildMethod.build()); return spec.build(); } + private List fields() { + List result = new ArrayList<>(); + for (NamedBinding namedBinding : sorted.values()) { + Binding b = namedBinding.binding(); + if (b instanceof ParameterBinding) { + result.add(FieldSpec.builder(b.key().typeName(), names.apply(b.key()).name).build()); + } + } + return result; + } + + private List setterMethods(BuilderElement builder) { + TypeMirror builderType = builder.element().asType(); + List result = new ArrayList<>(); + for (NamedBinding namedBinding : sorted.values()) { + Binding b = namedBinding.binding(); + if (b instanceof ParameterBinding) { + MethodSpec.Builder setterMethod = MethodSpec.methodBuilder(b.element().getSimpleName().toString()); + setterMethod.addAnnotation(Override.class); + setterMethod.addParameter(names.apply(b.key())); + setterMethod.addStatement("this.$N = $N", names.apply(b.key()), names.apply(b.key())); + setterMethod.addStatement("return this"); + setterMethod.returns(TypeName.get(builderType)); + setterMethod.addModifiers(b.element().getModifiers().stream() + .filter(m -> m == PUBLIC || m == PROTECTED).collect(Collectors.toList())); + result.add(setterMethod.build()); + } + } + return result; + } + + private List constructorParameters() { + List result = new ArrayList<>(); + for (NamedBinding namedBinding : sorted.values()) { + Binding b = namedBinding.binding(); + Key key = b.key(); + if (namedBinding.isComponentRequest()) { + result.add(CodeBlock.of("$N", names.apply(key))); + } + } + return result; + } + public static final class Factory { private final ComponentElement component; diff --git a/compiler/src/main/java/io/jbock/simple/processor/writing/ComponentImpl.java b/compiler/src/main/java/io/jbock/simple/processor/writing/ComponentImpl.java index 143bbf7..f59925b 100644 --- a/compiler/src/main/java/io/jbock/simple/processor/writing/ComponentImpl.java +++ b/compiler/src/main/java/io/jbock/simple/processor/writing/ComponentImpl.java @@ -108,11 +108,16 @@ private MethodSpec generateFactoryMethod(FactoryElement factory) { } private MethodSpec generateBuilderMethod(BuilderElement builder) { - return MethodSpec.methodBuilder(BUILDER_METHOD) + MethodSpec.Builder spec = MethodSpec.methodBuilder(BUILDER_METHOD) .addModifiers(STATIC) .addModifiers(modifiers) - .addStatement("return new $T(null)", builder.generatedClass()) - .returns(TypeName.get(builder.element().asType())).build(); + .returns(TypeName.get(builder.element().asType())); + if (component.omitMockBuilder()) { + spec.addStatement("return new $T()", builder.generatedClass()); + } else { + spec.addStatement("return new $T(null)", builder.generatedClass()); + } + return spec.build(); } private MethodSpec generateCreateMethod() { diff --git a/compiler/src/main/java/io/jbock/simple/processor/writing/MockBuilder.java b/compiler/src/main/java/io/jbock/simple/processor/writing/MockBuilder.java index c87da3e..c58d652 100644 --- a/compiler/src/main/java/io/jbock/simple/processor/writing/MockBuilder.java +++ b/compiler/src/main/java/io/jbock/simple/processor/writing/MockBuilder.java @@ -72,7 +72,7 @@ private MethodSpec buildMethod() { if (namedBinding.isComponentRequest()) { constructorParameters.add(CodeBlock.of("$N", names.apply(key))); } - if (namedBinding.binding() instanceof ParameterBinding) { + if (b instanceof ParameterBinding) { method.addParameter(names.apply(b.key())); } else if (!key.typeName().isPrimitive()) { method.addStatement("$1T $2N = this.$2N != null ? this.$2N : $3L", key.typeName(), param, invocation); diff --git a/compiler/src/test/java/io/jbock/simple/processor/BuilderTest.java b/compiler/src/test/java/io/jbock/simple/processor/BuilderTest.java index 327e500..3d51dce 100644 --- a/compiler/src/test/java/io/jbock/simple/processor/BuilderTest.java +++ b/compiler/src/test/java/io/jbock/simple/processor/BuilderTest.java @@ -60,7 +60,7 @@ void noParameters() { " private static final class Builder_Impl implements TestClass.AComponent.Builder {", " @Override", " public TestClass.AComponent build() {", - " TestClass.A a = new TestClass.A();", + " TestClass.A a = this.mockBuilder != null && this.mockBuilder.a != null ? this.mockBuilder.a : new TestClass.A();", " return new TestClass_AComponent_Impl(a);", " }", " }", @@ -186,7 +186,7 @@ void builderParameter() { "", " @Override", " public TestClass.AComponent build() {", - " TestClass.A a = new TestClass.A(s);", + " TestClass.A a = this.mockBuilder != null && this.mockBuilder.a != null ? this.mockBuilder.a : new TestClass.A(s);", " return new TestClass_AComponent_Impl(a);", " }", " }",