Skip to content

Commit

Permalink
ISSUES-4 add generatePublicMockBuilder (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
h908714124 authored Nov 29, 2023
1 parent 8a4a81a commit bbfabe4
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,20 @@ public Optional<Binding> parameterBinding(Key key) {
public Collection<ParameterBinding> parameterBindings() {
return parameterBindings.get().values();
}

public boolean generatePublicMockBuilder() {
Component annotation = element.getAnnotation(Component.class);
if (annotation == null) {
return false;
}
return annotation.generatePublicMockBuilder();
}

public boolean omitMockBuilder() {
Component annotation = element.getAnnotation(Component.class);
if (annotation == null) {
return false;
}
return annotation.omitMockBuilder();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@

public class ComponentImpl {

private static final String FACTORY_METHOD = "factory";
private static final String BUILDER_METHOD = "builder";
private static final String CREATE_METHOD = "create";
private static final String MOCK_BUILDER_METHOD = "mockBuilder";

private final ComponentElement component;
private final Map<Key, NamedBinding> sorted;
private final Function<Key, ParameterSpec> names;
Expand Down Expand Up @@ -68,7 +73,7 @@ TypeSpec generate() {
spec.addMethod(method.build());
}
component.factoryElement().ifPresent(factory -> {
spec.addMethod(MethodSpec.methodBuilder("factory")
spec.addMethod(MethodSpec.methodBuilder(FACTORY_METHOD)
.addModifiers(STATIC)
.addModifiers(modifiers)
.returns(TypeName.get(factory.element().asType()))
Expand All @@ -77,7 +82,7 @@ TypeSpec generate() {
spec.addType(createFactoryImpl(factory));
});
component.builderElement().ifPresent(builder -> {
spec.addMethod(MethodSpec.methodBuilder("builder")
spec.addMethod(MethodSpec.methodBuilder(BUILDER_METHOD)
.addModifiers(STATIC)
.addModifiers(modifiers)
.returns(TypeName.get(builder.element().asType()))
Expand All @@ -87,9 +92,11 @@ TypeSpec generate() {
});
if (component.factoryElement().isEmpty() && component.builderElement().isEmpty()) {
spec.addMethod(generateCreateMethod());
spec.addMethod(generateMockCreateMethod());
}
spec.addType(mockBuilder.generate());
if (!component.omitMockBuilder()) {
spec.addMethod(generateMockBuilderMethod());
spec.addType(mockBuilder.generate());
}
spec.addAnnotation(AnnotationSpec.builder(Generated.class)
.addMember("value", CodeBlock.of("$S", SimpleComponentProcessor.class.getCanonicalName()))
.addMember("comments", CodeBlock.of("$S", "https://github.com/jbock-java/simple-component"))
Expand All @@ -102,7 +109,7 @@ TypeSpec generate() {

private MethodSpec generateCreateMethod() {
List<CodeBlock> constructorParameters = new ArrayList<>();
MethodSpec.Builder method = MethodSpec.methodBuilder("create");
MethodSpec.Builder method = MethodSpec.methodBuilder(CREATE_METHOD);
for (NamedBinding namedBinding : sorted.values()) {
Binding b = namedBinding.binding();
Key key = b.key();
Expand All @@ -123,12 +130,15 @@ private MethodSpec generateCreateMethod() {
.build();
}

MethodSpec generateMockCreateMethod() {
MethodSpec.Builder method = MethodSpec.methodBuilder("mockBuilder");
MethodSpec generateMockBuilderMethod() {
MethodSpec.Builder method = MethodSpec.methodBuilder(MOCK_BUILDER_METHOD);
method.addJavadoc("Visible for testing. Do not call this method from production code.");
method.addStatement("return new $T()", mockBuilder.getClassName());
method.returns(mockBuilder.getClassName());
method.addModifiers(STATIC);
if (component.generatePublicMockBuilder()) {
method.addModifiers(modifiers);
}
return method.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void staticMethodBindings() {
" @Inject static D createD() { return null; }",
" }",
"",
" @Component",
" @Component(generatePublicMockBuilder = true)",
" public interface AComponent {",
" A getA();",
" }",
Expand Down Expand Up @@ -67,7 +67,7 @@ void staticMethodBindings() {
" return new TestClass_AComponent_Impl(a);",
" }",
"",
" static MockBuilder mockBuilder() {",
" public static MockBuilder mockBuilder() {",
" return new MockBuilder();",
" }",
"",
Expand Down
20 changes: 18 additions & 2 deletions simple-component/src/main/java/io/jbock/simple/Component.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
* have the name of the type annotated, appended with {@code _Impl}. For
* example, {@code @Component interface MyComponent {...}} will produce an implementation named
* {@code MyComponent_Impl}.
*
* <h2>Component methods</h2>
* <h2>Component methods
*
* <p>Every type annotated with {@code @Component} must contain at least one abstract component
* method. Component methods may have any name, but must have no parameters and return a bound type.
Expand Down Expand Up @@ -56,4 +55,21 @@
@Target(TYPE)
@interface Builder {
}

/**
* By default, the {@code mockBuilder} method is only package-private. This
* should make it less prone to accidental invocation from production code.
*
* <p>In test code, this restriction can be circumvented by placing a public delegate class
* in the component package.
*
* @return {@code true} if the {@code mockBuilder} method should have the same visibility
* as the component.
*/
boolean generatePublicMockBuilder() default false;

/**
* @return {@code true} if the {@code mockBuilder} method should not be generated.
*/
boolean omitMockBuilder() default false;
}

0 comments on commit bbfabe4

Please sign in to comment.