Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ISSUES-4 factory use mockBuilder #15

Merged
merged 3 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ TypeSpec generate(BuilderElement builder, MockBuilder mockBuilder) {
}

private TypeSpec generateMock(BuilderElement builder, MockBuilder mockBuilder) {
TypeMirror builderType = builder.element().asType();
TypeSpec.Builder spec = TypeSpec.classBuilder(builder.generatedClass());
FieldSpec mockBuilderField = FieldSpec.builder(mockBuilder.getClassName(), "mockBuilder", FINAL).build();
spec.addField(mockBuilderField);
Expand Down Expand Up @@ -80,7 +79,7 @@ private TypeSpec generateMock(BuilderElement builder, MockBuilder mockBuilder) {
spec.addFields(fields());
spec.addMethods(setterMethods(builder));
spec.addModifiers(PRIVATE, STATIC, FINAL);
spec.addSuperinterface(builderType);
spec.addSuperinterface(builder.element().asType());
buildMethod.addAnnotation(Override.class);
buildMethod.addModifiers(builder.buildMethod().getModifiers().stream()
.filter(m -> m == PUBLIC || m == PROTECTED).collect(Collectors.toList()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ TypeSpec generate() {
}
component.factoryElement().ifPresent(factory -> {
spec.addMethod(generateFactoryMethod(factory));
spec.addType(factoryImpl.generate(factory));
spec.addType(factoryImpl.generate(factory, mockBuilder));
});
component.builderElement().ifPresent(builder -> {
spec.addMethod(generateBuilderMethod(builder));
Expand All @@ -99,12 +99,16 @@ TypeSpec generate() {
}

private MethodSpec generateFactoryMethod(FactoryElement factory) {
return MethodSpec.methodBuilder(FACTORY_METHOD)
MethodSpec.Builder spec = MethodSpec.methodBuilder(FACTORY_METHOD)
.addModifiers(STATIC)
.addModifiers(modifiers)
.returns(TypeName.get(factory.element().asType()))
.addStatement("return new $T()", factory.generatedClass())
.build();
.returns(TypeName.get(factory.element().asType()));
if (component.omitMockBuilder()) {
spec.addStatement("return new $T()", factory.generatedClass());
} else {
spec.addStatement("return new $T(null)", factory.generatedClass());
}
return spec.build();
}

private MethodSpec generateBuilderMethod(BuilderElement builder) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.jbock.simple.processor.writing;

import io.jbock.javapoet.CodeBlock;
import io.jbock.javapoet.FieldSpec;
import io.jbock.javapoet.MethodSpec;
import io.jbock.javapoet.ParameterSpec;
import io.jbock.javapoet.TypeName;
Expand Down Expand Up @@ -40,7 +41,56 @@ private FactoryImpl(
this.names = names;
}

TypeSpec generate(FactoryElement factory) {
TypeSpec generate(FactoryElement factory, MockBuilder mockBuilder) {
if (component.omitMockBuilder()) {
return generateNoMock(factory);
} else {
return generateMock(factory, mockBuilder);
}
}

private TypeSpec generateMock(FactoryElement factory, MockBuilder mockBuilder) {
TypeSpec.Builder spec = TypeSpec.classBuilder(factory.generatedClass());
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());
ExecutableElement abstractMethod = factory.singleAbstractMethod();
MethodSpec.Builder method = MethodSpec.methodBuilder(abstractMethod.getSimpleName().toString());
method.addAnnotation(Override.class);
method.addModifiers(abstractMethod.getModifiers().stream()
.filter(m -> m == PUBLIC || m == PROTECTED).collect(Collectors.toList()));
method.returns(TypeName.get(component.element().asType()));
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 (!key.typeName().isPrimitive()) {
method.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();
method.addStatement("$1T $2N = this.$3N != null && this.$3N.$4N ? this.$3N.$2N : $5L",
key.typeName(), param, mockBuilderField, auxField, invocation);
}
}
method.addParameters(parameters());
spec.addModifiers(PRIVATE, STATIC, FINAL);
spec.addSuperinterface(factory.element().asType());
method.addStatement("return new $T($L)", component.generatedClass(), constructorParameters().stream()
.collect(CodeBlock.joining(", ")));
spec.addMethod(method.build());
return spec.build();
}

private TypeSpec generateNoMock(FactoryElement factory) {
TypeSpec.Builder spec = TypeSpec.classBuilder(factory.generatedClass());
spec.addModifiers(PRIVATE, STATIC, FINAL);
spec.addSuperinterface(factory.element().asType());
Expand All @@ -50,27 +100,47 @@ TypeSpec generate(FactoryElement factory) {
method.addModifiers(abstractMethod.getModifiers().stream()
.filter(m -> m == PUBLIC || m == PROTECTED).collect(Collectors.toList()));
method.returns(TypeName.get(component.element().asType()));
List<CodeBlock> constructorParameters = new ArrayList<>();
for (NamedBinding namedBinding : sorted.values()) {
Binding b = namedBinding.binding();
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) {
method.addParameter(names.apply(b.key()));
} else {
if (!(b instanceof ParameterBinding)) {
method.addStatement("$T $N = $L", key.typeName(), param, invocation);
}
}
method.addStatement("return new $T($L)", component.generatedClass(), constructorParameters.stream()
method.addParameters(parameters());
method.addStatement("return new $T($L)", component.generatedClass(), constructorParameters().stream()
.collect(CodeBlock.joining(", ")));
spec.addMethod(method.build());
return spec.build();
}


private List<CodeBlock> constructorParameters() {
List<CodeBlock> 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;
}

private List<ParameterSpec> parameters() {
List<ParameterSpec> result = new ArrayList<>();
for (NamedBinding namedBinding : sorted.values()) {
Binding b = namedBinding.binding();
Key key = b.key();
if (b instanceof ParameterBinding) {
result.add(names.apply(key));
}
}
return result;
}

public static final class Factory {
private final ComponentElement component;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,32 +62,39 @@ ClassName getClassName() {
}

private MethodSpec buildMethod() {
List<CodeBlock> constructorParameters = new ArrayList<>();
MethodSpec.Builder method = MethodSpec.methodBuilder("build");
for (NamedBinding namedBinding : sorted.values()) {
Binding b = namedBinding.binding();
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) {
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);
} else {
FieldSpec auxField = FieldSpec.builder(TypeName.BOOLEAN, namedBinding.auxName(), PRIVATE).build();
method.addStatement("$1T $2N = this.$3N ? this.$2N : $4L", key.typeName(), param, auxField, invocation);
method.addModifiers(modifiers);
component.factoryElement().ifPresent(factory -> {
method.returns(TypeName.get(factory.element().asType()));
method.addStatement("return new $T(this)", factory.generatedClass());
});
component.builderElement().ifPresent(builder -> {
method.returns(TypeName.get(builder.element().asType()));
method.addStatement("return new $T(this)", builder.generatedClass());
});
if (component.factoryElement().isEmpty() && component.builderElement().isEmpty()) {
method.returns(TypeName.get(component.element().asType()));
List<CodeBlock> constructorParameters = new ArrayList<>();
for (NamedBinding namedBinding : sorted.values()) {
Binding b = namedBinding.binding();
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 (!key.typeName().isPrimitive()) {
method.addStatement("$1T $2N = this.$2N != null ? this.$2N : $3L", key.typeName(), param, invocation);
} else {
FieldSpec auxField = FieldSpec.builder(TypeName.BOOLEAN, namedBinding.auxName(), PRIVATE).build();
method.addStatement("$1T $2N = this.$3N ? this.$2N : $4L", key.typeName(), param, auxField, invocation);
}
}
method.addStatement("return new $T($L)",
component.generatedClass(),
constructorParameters.stream().collect(CodeBlock.joining(", ")));
}
return method
.addModifiers(modifiers)
.returns(TypeName.get(component.element().asType()))
.addStatement("return new $T($L)",
component.generatedClass(),
constructorParameters.stream().collect(CodeBlock.joining(", ")))
.build();
return method.build();
}

private List<FieldSpec> getFields() {
Expand Down
16 changes: 11 additions & 5 deletions compiler/src/test/java/io/jbock/simple/processor/FactoryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ void noParameters() {
" }",
"",
" static TestClass.AComponent.Factory factory() {",
" return new Factory_Impl();",
" return new Factory_Impl(null);",
" }",
"",
" private static final class Factory_Impl implements TestClass.AComponent.Factory {",
" @Override",
" public TestClass.AComponent create() {",
" 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);",
" }",
" }",
Expand Down Expand Up @@ -106,7 +106,7 @@ void factoryParameterIdentity() {
" }",
"",
" public static TestClass.AComponent.Factory factory() {",
" return new Factory_Impl();",
" return new Factory_Impl(null);",
" }",
"",
" private static final class Factory_Impl implements TestClass.AComponent.Factory {",
Expand Down Expand Up @@ -161,13 +161,19 @@ void factoryParameter() {
" }",
"",
" static TestClass.AComponent.Factory factory() {",
" return new Factory_Impl();",
" return new Factory_Impl(null);",
" }",
"",
" private static final class Factory_Impl implements TestClass.AComponent.Factory {",
" final MockBuilder mockBuilder;",
"",
" Factory_Impl(MockBuilder mockBuilder) {",
" this.mockBuilder = mockBuilder;",
" }",
"",
" @Override",
" public TestClass.AComponent create(String s) {",
" 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);",
" }",
" }",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ void qualifiedIdentity() {
" }",
"",
" static TestClass.AComponent.Factory factory() {",
" return new Factory_Impl();",
" return new Factory_Impl(null);",
" }",
"",
" private static final class Factory_Impl implements TestClass.AComponent.Factory {",
Expand All @@ -62,8 +62,8 @@ void qualifiedIdentity() {
" }",
"",
" static final class MockBuilder {",
" TestClass.AComponent build(String a, String b) {",
" return new TestClass_AComponent_Impl(a);",
" TestClass.AComponent.Factory build() {",
" return new Factory_Impl(this);",
" }",
" }",
"}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ void qualifiedIdentity() {
" }",
"",
" static TestClass.AComponent.Factory factory() {",
" return new Factory_Impl();",
" return new Factory_Impl(null);",
" }",
"",
" private static final class Factory_Impl implements TestClass.AComponent.Factory {",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,14 @@ void providesPrimitive() {
" }",
"",
" static TestClass.AComponent.Factory factory() {",
" return new Factory_Impl();",
" return new Factory_Impl(null);",
" }",
"",
" private static final class Factory_Impl implements TestClass.AComponent.Factory {",
" @Override",
" public TestClass.AComponent create(int i) {",
" int b = TestClass.AComponent.getB(i);",
" TestClass.A a = new TestClass.A(b);",
" int b = this.mockBuilder != null && this.mockBuilder.b_isSet ? this.mockBuilder.b : TestClass.AComponent.getB(i);",
" TestClass.A a = this.mockBuilder != null && this.mockBuilder.a != null ? this.mockBuilder.a : new TestClass.A(b);",
" return new TestClass_AComponent_Impl(a);",
" }",
" }",
Expand All @@ -104,10 +104,8 @@ void providesPrimitive() {
" private boolean b_isSet;",
" private TestClass.A a;",
"",
" TestClass.AComponent build(int i) {",
" int b = this.b_isSet ? this.b : TestClass.AComponent.getB(i);",
" TestClass.A a = this.a != null ? this.a : new TestClass.A(b);",
" return new TestClass_AComponent_Impl(a);",
" TestClass.AComponent.Factory build() {",
" return new Factory_Impl(this);",
" }",
"",
" void b(int b) {",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ void qualifiedIdentity() {
" }",
"",
" static TestClass.AComponent.Factory factory() {",
" return new Factory_Impl();",
" return new Factory_Impl(null);",
" }",
"",
" private static final class Factory_Impl implements TestClass.AComponent.Factory {",
Expand Down