Skip to content

Commit

Permalink
ISSUES-36 add MockBuilder2 (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
h908714124 authored Dec 10, 2023
1 parent 583dd0b commit 06be77a
Show file tree
Hide file tree
Showing 11 changed files with 345 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import io.jbock.javapoet.CodeBlock;
import io.jbock.javapoet.ParameterSpec;
import io.jbock.simple.processor.writing.NamedBinding;

import javax.lang.model.element.Element;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;

Expand Down Expand Up @@ -44,7 +46,14 @@ public final Key key() {

public abstract List<DependencyRequest> requests();

public abstract CodeBlock invocation(Function<Key, ParameterSpec> names);
public abstract CodeBlock invocation(
Function<Key, ParameterSpec> names,
boolean thisForParams,
Map<Key, NamedBinding> bindings);

public final CodeBlock invocation(Function<Key, ParameterSpec> names) {
return invocation(names, false, Map.of());
}

public abstract String suggestedVariableName();
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
import io.jbock.simple.Inject;
import io.jbock.simple.Provides;
import io.jbock.simple.processor.util.ValidationFailure;
import io.jbock.simple.processor.writing.NamedBinding;

import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -111,9 +113,19 @@ public List<DependencyRequest> requests() {
}

@Override
public CodeBlock invocation(Function<Key, ParameterSpec> names) {
public CodeBlock invocation(
Function<Key, ParameterSpec> names,
boolean thisForNames,
Map<Key, NamedBinding> bindings) {
CodeBlock params = requests().stream()
.map(d -> CodeBlock.of("$N", names.apply(d.key())))
.map(d -> {
NamedBinding namedBinding = bindings.get(d.key());
ParameterSpec param = names.apply(d.key());
boolean isParameterBinding = namedBinding != null && namedBinding.binding() instanceof ParameterBinding;
return (isParameterBinding && thisForNames) ?
CodeBlock.of("this.$N", param) :
CodeBlock.of("$N", param);
})
.collect(CodeBlock.joining(", "));
if (bindingElement.getKind() == ElementKind.CONSTRUCTOR) {
return CodeBlock.of("new $T($L)", bindingElement.getEnclosingElement().asType(), params);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

import io.jbock.javapoet.CodeBlock;
import io.jbock.javapoet.ParameterSpec;
import io.jbock.simple.processor.writing.NamedBinding;

import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.VariableElement;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

public final class ParameterBinding extends Binding {
Expand Down Expand Up @@ -35,8 +37,12 @@ public static ParameterBinding create(ExecutableElement setter, KeyFactory keyFa
}

@Override
public CodeBlock invocation(Function<Key, ParameterSpec> names) {
return CodeBlock.of("$N", names.apply(key()));
public CodeBlock invocation(
Function<Key, ParameterSpec> names,
boolean thisForNames,
Map<Key, NamedBinding> bindings) {
ParameterSpec param = names.apply(key());
return thisForNames ? CodeBlock.of("this.$N", param) : CodeBlock.of("$N", param);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import io.jbock.javapoet.CodeBlock;
import io.jbock.javapoet.ParameterSpec;
import io.jbock.simple.processor.util.ProviderType;
import io.jbock.simple.processor.writing.NamedBinding;

import javax.lang.model.element.Element;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

public class ProviderBinding extends Binding {
Expand Down Expand Up @@ -33,8 +35,11 @@ public List<DependencyRequest> requests() {
}

@Override
public CodeBlock invocation(Function<Key, ParameterSpec> names) {
return CodeBlock.of("() -> $L", sourceBinding.invocation(names));
public CodeBlock invocation(
Function<Key, ParameterSpec> names,
boolean thisForNames,
Map<Key, NamedBinding> bindings) {
return CodeBlock.of("() -> $L", sourceBinding.invocation(names, thisForNames, bindings));
}

public Binding sourceBinding() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ private BuilderImpl(
this.names = names;
}

TypeSpec generate(BuilderElement builder, MockBuilder mockBuilder) {
TypeSpec generate(BuilderElement builder, MockBuilder mockBuilder, MockBuilder2 mockBuilder2) {
if (component.mockBuilder()) {
return generateMock(builder, mockBuilder);
return generateMock(builder, mockBuilder, mockBuilder2);
} else {
return generateNoMock(builder);
}
}

private TypeSpec generateMock(BuilderElement builder, MockBuilder mockBuilder) {
private TypeSpec generateMock(BuilderElement builder, MockBuilder mockBuilder, MockBuilder2 mockBuilder2) {
TypeSpec.Builder spec = TypeSpec.classBuilder(builder.generatedClass());
FieldSpec mockBuilderField = FieldSpec.builder(mockBuilder.getClassName(), "mockBuilder", FINAL).build();
spec.addField(mockBuilderField);
Expand All @@ -58,14 +58,24 @@ private TypeSpec generateMock(BuilderElement builder, MockBuilder mockBuilder) {
.addParameter(mockBuilderParam)
.addStatement("this.$N = $N", mockBuilderField, mockBuilderParam)
.build());
spec.addMethod(generateBuildMethod(builder, mockBuilderField));
spec.addMethod(generateWithMocksMethod(mockBuilder2));
spec.addFields(fields());
spec.addMethods(setterMethods(builder));
spec.addModifiers(PUBLIC, STATIC, FINAL);
spec.addSuperinterface(builder.element().asType());
return spec.build();
}

private MethodSpec generateBuildMethod(BuilderElement builder, FieldSpec mockBuilderField) {
MethodSpec.Builder buildMethod = MethodSpec.methodBuilder(builder.buildMethod().getSimpleName().toString());
for (NamedBinding namedBinding : sorted.values()) {
Binding b = namedBinding.binding();
if (b instanceof ParameterBinding) {
continue;
}
Key key = b.key();
CodeBlock invocation = b.invocation(names);
CodeBlock invocation = b.invocation(names, true, sorted);
ParameterSpec param = names.apply(key);
if (!key.typeName().isPrimitive()) {
buildMethod.addStatement("$1T $2N = this.$3N != null && this.$3N.$2N != null ? this.$3N.$2N : $4L",
Expand All @@ -76,18 +86,33 @@ private TypeSpec generateMock(BuilderElement builder, MockBuilder mockBuilder) {
key.typeName(), param, mockBuilderField, auxField, invocation);
}
}
spec.addFields(fields());
spec.addMethods(setterMethods(builder));
spec.addModifiers(PRIVATE, STATIC, FINAL);
spec.addSuperinterface(builder.element().asType());
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();
return buildMethod.build();
}

private MethodSpec generateWithMocksMethod(MockBuilder2 mockBuilder2) {
MethodSpec.Builder method = MethodSpec.methodBuilder("withMocks");
List<CodeBlock> constructorParameters = new ArrayList<>();
for (NamedBinding namedBinding : sorted.values()) {
Binding b = namedBinding.binding();
if (!(b instanceof ParameterBinding)) {
continue;
}
ParameterSpec param = names.apply(b.key());
constructorParameters.add(CodeBlock.of("this.$N", param));
}
if (component.publicMockBuilder()) {
method.addModifiers(PUBLIC);
}
method.returns(mockBuilder2.getClassName());
method.addStatement("return new $T($L)", mockBuilder2.getClassName(),
constructorParameters.stream().collect(CodeBlock.joining(", ")));
return method.build();
}

private TypeSpec generateNoMock(BuilderElement builder) {
Expand All @@ -105,7 +130,7 @@ private TypeSpec generateNoMock(BuilderElement builder) {
}
spec.addFields(fields());
spec.addMethods(setterMethods(builder));
spec.addModifiers(PRIVATE, STATIC, FINAL);
spec.addModifiers(PUBLIC, STATIC, FINAL);
spec.addSuperinterface(builderType);
buildMethod.addAnnotation(Override.class);
buildMethod.addModifiers(builder.buildMethod().getModifiers().stream()
Expand All @@ -129,21 +154,21 @@ private List<FieldSpec> fields() {
}

private List<MethodSpec> setterMethods(BuilderElement builder) {
TypeMirror builderType = builder.element().asType();
List<MethodSpec> 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());
if (!(b instanceof ParameterBinding)) {
continue;
}
MethodSpec.Builder setterMethod = MethodSpec.methodBuilder(b.element().getSimpleName().toString());
setterMethod.addAnnotation(Override.class);
setterMethod.addParameter(names.apply(b.key()));
setterMethod.addStatement("this.$1N = $1N", names.apply(b.key()));
setterMethod.addStatement("return this");
setterMethod.returns(builder.generatedClass());
setterMethod.addModifiers(b.element().getModifiers().stream()
.filter(m -> m == PUBLIC || m == PROTECTED).collect(Collectors.toList()));
result.add(setterMethod.build());
}
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public class ComponentImpl {
private final Map<Key, NamedBinding> sorted;
private final Function<Key, ParameterSpec> names;
private final MockBuilder mockBuilder;
private final MockBuilder2 mockBuilder2;
private final BuilderImpl builderImpl;
private final FactoryImpl factoryImpl;
private final Modifier[] modifiers;
Expand All @@ -49,6 +50,7 @@ private ComponentImpl(
Map<Key, NamedBinding> sorted,
Function<Key, ParameterSpec> names,
MockBuilder mockBuilder,
MockBuilder2 mockBuilder2,
BuilderImpl builderImpl,
FactoryImpl factoryImpl) {
this.component = component;
Expand All @@ -57,6 +59,7 @@ private ComponentImpl(
this.mockBuilder = mockBuilder;
this.modifiers = component.element().getModifiers().stream()
.filter(m -> m == PUBLIC).toArray(Modifier[]::new);
this.mockBuilder2 = mockBuilder2;
this.builderImpl = builderImpl;
this.factoryImpl = factoryImpl;
}
Expand All @@ -81,14 +84,15 @@ TypeSpec generate() {
});
component.builderElement().ifPresent(builder -> {
spec.addMethod(generateBuilderMethod(builder));
spec.addType(builderImpl.generate(builder, mockBuilder));
spec.addType(builderImpl.generate(builder, mockBuilder, mockBuilder2));
});
if (component.factoryElement().isEmpty() && component.builderElement().isEmpty()) {
spec.addMethod(generateCreateMethod());
}
if (component.mockBuilder()) {
spec.addMethod(generateMockBuilderMethod());
spec.addType(mockBuilder.generate());
spec.addType(mockBuilder2.generate());
}
spec.addAnnotation(AnnotationSpec.builder(Generated.class)
.addMember("value", CodeBlock.of("$S", SimpleComponentProcessor.class.getCanonicalName()))
Expand Down Expand Up @@ -121,7 +125,7 @@ private MethodSpec generateBuilderMethod(BuilderElement builder) {
MethodSpec.Builder spec = MethodSpec.methodBuilder(BUILDER_METHOD)
.addModifiers(STATIC)
.addModifiers(modifiers)
.returns(TypeName.get(builder.element().asType()));
.returns(builder.generatedClass());
if (component.mockBuilder()) {
spec.addStatement("return new $T(null)", builder.generatedClass());
} else {
Expand Down Expand Up @@ -194,17 +198,20 @@ private MethodSpec generateAllParametersConstructor() {
public static final class Factory {
private final ComponentElement component;
private final MockBuilder.Factory mockBuilderFactory;
private final MockBuilder2.Factory mockBuilder2Factory;
private final BuilderImpl.Factory builderImplFactory;
private final FactoryImpl.Factory factoryImplFactory;

@Inject
public Factory(
ComponentElement component,
MockBuilder.Factory mockBuilderFactory,
MockBuilder2.Factory mockBuilder2Factory,
BuilderImpl.Factory builderImplFactory,
FactoryImpl.Factory factoryImplFactory) {
this.component = component;
this.mockBuilderFactory = mockBuilderFactory;
this.mockBuilder2Factory = mockBuilder2Factory;
this.builderImplFactory = builderImplFactory;
this.factoryImplFactory = factoryImplFactory;
}
Expand All @@ -217,6 +224,7 @@ ComponentImpl create(
sorted,
names,
mockBuilderFactory.create(sorted, names),
mockBuilder2Factory.create(sorted, names),
builderImplFactory.create(sorted, names),
factoryImplFactory.create(sorted, names));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public TypeSpec generate(List<Binding> bindings) {
private Map<Key, NamedBinding> addNames(List<Binding> bindings) {
UniqueNameSet uniqueNameSet = new UniqueNameSet();
uniqueNameSet.claim("mockBuilder");
uniqueNameSet.claim("withMocks");
uniqueNameSet.claim("build");
Map<Key, NamedBinding> result = new LinkedHashMap<>();
for (Binding b : bindings) {
Expand Down
Loading

0 comments on commit 06be77a

Please sign in to comment.