Skip to content

Commit 771230c

Browse files
authored
ISSUES-17 add BindingRegistry (#18)
ISSUES-17 add BindingRegistry
1 parent 8b10d6a commit 771230c

File tree

11 files changed

+214
-66
lines changed

11 files changed

+214
-66
lines changed

compiler/src/main/java/io/jbock/simple/processor/ContextComponent.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.jbock.simple.processor;
22

33
import io.jbock.simple.Component;
4+
import io.jbock.simple.Inject;
45
import io.jbock.simple.processor.binding.ComponentElement;
56
import io.jbock.simple.processor.binding.InjectBindingFactory;
67
import io.jbock.simple.processor.binding.KeyFactory;
@@ -40,4 +41,29 @@ static ContextComponent create(
4041
Generator generator();
4142

4243
TopologicalSorter topologicalSorter();
44+
45+
final class Factory {
46+
private final TypeTool tool;
47+
private final InjectBindingFactory injectBindingFactory;
48+
private final KeyFactory keyFactory;
49+
50+
@Inject
51+
public Factory(
52+
TypeTool tool,
53+
InjectBindingFactory injectBindingFactory,
54+
KeyFactory keyFactory) {
55+
this.tool = tool;
56+
this.injectBindingFactory = injectBindingFactory;
57+
this.keyFactory = keyFactory;
58+
}
59+
60+
public ContextComponent create(ComponentElement component) {
61+
return ContextComponent_Impl.builder()
62+
.componentElement(component)
63+
.tool(tool)
64+
.injectBindingFactory(injectBindingFactory)
65+
.keyFactory(keyFactory)
66+
.build();
67+
}
68+
}
4369
}

compiler/src/main/java/io/jbock/simple/processor/binding/ComponentElement.java

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.jbock.javapoet.ClassName;
44
import io.jbock.simple.Component;
5+
import io.jbock.simple.Inject;
56
import io.jbock.simple.Provides;
67
import io.jbock.simple.processor.util.ValidationFailure;
78
import io.jbock.simple.processor.util.Visitors;
@@ -25,6 +26,7 @@ public final class ComponentElement {
2526

2627
private final TypeElement element;
2728
private final KeyFactory keyFactory;
29+
private final InjectBinding.Factory injectBindingFactory;
2830

2931
private final Supplier<ClassName> generatedClass = memoize(() -> {
3032
ClassName className = ClassName.get(element());
@@ -72,7 +74,7 @@ public final class ComponentElement {
7274
continue; // ignore
7375
}
7476
Key key = keyFactory().getKey(method);
75-
InjectBinding b = InjectBinding.create(keyFactory(), method);
77+
InjectBinding b = injectBindingFactory().create(method);
7678
result.put(key, b);
7779
}
7880
return result;
@@ -122,15 +124,11 @@ public final class ComponentElement {
122124

123125
private ComponentElement(
124126
TypeElement element,
125-
KeyFactory keyFactory) {
127+
KeyFactory keyFactory,
128+
InjectBinding.Factory injectBindingFactory) {
126129
this.element = element;
127130
this.keyFactory = keyFactory;
128-
}
129-
130-
public static ComponentElement create(
131-
TypeElement element,
132-
KeyFactory keyFactory) {
133-
return new ComponentElement(element, keyFactory);
131+
this.injectBindingFactory = injectBindingFactory;
134132
}
135133

136134
public TypeElement element() {
@@ -165,6 +163,10 @@ private KeyFactory keyFactory() {
165163
return keyFactory;
166164
}
167165

166+
private InjectBinding.Factory injectBindingFactory() {
167+
return injectBindingFactory;
168+
}
169+
168170
public Optional<Binding> parameterBinding(Key key) {
169171
return Optional.ofNullable(parameterBindings.get().get(key));
170172
}
@@ -188,4 +190,20 @@ public boolean omitMockBuilder() {
188190
}
189191
return annotation.omitMockBuilder();
190192
}
193+
194+
public static final class Factory {
195+
private final KeyFactory keyFactory;
196+
private final InjectBinding.Factory injectBindingFactory;
197+
198+
@Inject
199+
public Factory(KeyFactory keyFactory, InjectBinding.Factory injectBindingFactory) {
200+
this.keyFactory = keyFactory;
201+
this.injectBindingFactory = injectBindingFactory;
202+
}
203+
204+
public ComponentElement create(
205+
TypeElement element) {
206+
return new ComponentElement(element, keyFactory, injectBindingFactory);
207+
}
208+
}
191209
}

compiler/src/main/java/io/jbock/simple/processor/binding/InjectBinding.java

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import io.jbock.javapoet.ParameterSpec;
55
import io.jbock.javapoet.ParameterizedTypeName;
66
import io.jbock.javapoet.TypeName;
7+
import io.jbock.simple.Inject;
78
import io.jbock.simple.Provides;
89
import io.jbock.simple.processor.util.ValidationFailure;
910

@@ -94,18 +95,6 @@ private InjectBinding(
9495
this.keyFactory = keyFactory;
9596
}
9697

97-
static InjectBinding create(
98-
KeyFactory keyFactory,
99-
ExecutableElement m) {
100-
Key key = keyFactory.getKey(m);
101-
if (m.getKind() == ElementKind.CONSTRUCTOR) {
102-
if (key.qualifier().isPresent()) {
103-
throw new ValidationFailure("Constructors can't have qualifiers", m);
104-
}
105-
}
106-
return new InjectBinding(key, keyFactory, m);
107-
}
108-
10998
@Override
11099
public String suggestedVariableName() {
111100
return suggestedVariableName.get();
@@ -141,4 +130,23 @@ public String toString() {
141130
private KeyFactory keyFactory() {
142131
return keyFactory;
143132
}
133+
134+
public static final class Factory {
135+
private final KeyFactory keyFactory;
136+
137+
@Inject
138+
public Factory(KeyFactory keyFactory) {
139+
this.keyFactory = keyFactory;
140+
}
141+
142+
InjectBinding create(ExecutableElement m) {
143+
Key key = keyFactory.getKey(m);
144+
if (m.getKind() == ElementKind.CONSTRUCTOR) {
145+
if (key.qualifier().isPresent()) {
146+
throw new ValidationFailure("Constructors can't have qualifiers", m);
147+
}
148+
}
149+
return new InjectBinding(key, keyFactory, m);
150+
}
151+
}
144152
}

compiler/src/main/java/io/jbock/simple/processor/binding/InjectBindingFactory.java

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import io.jbock.simple.Inject;
44
import io.jbock.simple.processor.util.ClearableCache;
55
import io.jbock.simple.processor.util.TypeTool;
6-
import io.jbock.simple.processor.util.ValidationFailure;
76

87
import javax.lang.model.element.ExecutableElement;
98
import javax.lang.model.element.TypeElement;
@@ -15,8 +14,6 @@
1514
import java.util.Optional;
1615
import java.util.stream.Collectors;
1716

18-
import static io.jbock.simple.processor.util.Printing.INDENT;
19-
import static io.jbock.simple.processor.util.Printing.bindingElementToString;
2017
import static io.jbock.simple.processor.util.Visitors.EXECUTABLE_ELEMENT_VISITOR;
2118
import static io.jbock.simple.processor.util.Visitors.TYPE_ELEMENT_VISITOR;
2219

@@ -26,11 +23,16 @@ public final class InjectBindingFactory implements ClearableCache {
2623

2724
private final TypeTool tool;
2825
private final KeyFactory keyFactory;
26+
private final InjectBinding.Factory injectBindingFactory;
2927

3028
@Inject
31-
public InjectBindingFactory(TypeTool tool, KeyFactory keyFactory) {
29+
public InjectBindingFactory(
30+
TypeTool tool,
31+
KeyFactory keyFactory,
32+
InjectBinding.Factory injectBindingFactory) {
3233
this.tool = tool;
3334
this.keyFactory = keyFactory;
35+
this.injectBindingFactory = injectBindingFactory;
3436
}
3537

3638
public Map<Key, InjectBinding> injectBindings(TypeElement typeElement) {
@@ -47,18 +49,11 @@ public Map<Key, InjectBinding> injectBindings(TypeElement typeElement) {
4749
return Map.of();
4850
}
4951
result = new LinkedHashMap<>();
50-
for (ExecutableElement m : allMembers) {
51-
InjectBinding b = InjectBinding.create(keyFactory, m);
52-
InjectBinding previous = result.put(b.key(), b);
53-
if (previous != null) {
54-
throw new ValidationFailure("This binding clashes with:\n"
55-
+ INDENT
56-
+ bindingElementToString(previous.element())
57-
+ ".\n"
58-
+ "Consider a (different) qualifier", b.element());
59-
}
60-
injectBindingCache.put(typeElement, result);
52+
for (ExecutableElement method : allMembers) {
53+
InjectBinding b = injectBindingFactory.create(method);
54+
result.put(b.key(), b); // duplicates handled elsewhere
6155
}
56+
injectBindingCache.put(typeElement, result);
6257
return result;
6358
}
6459

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package io.jbock.simple.processor.step;
2+
3+
import io.jbock.simple.Inject;
4+
import io.jbock.simple.processor.binding.Key;
5+
import io.jbock.simple.processor.binding.KeyFactory;
6+
import io.jbock.simple.processor.util.ValidationFailure;
7+
8+
import javax.lang.model.element.Element;
9+
import javax.lang.model.element.ExecutableElement;
10+
import java.util.HashMap;
11+
import java.util.Map;
12+
13+
public class BindingRegistry {
14+
15+
private final Map<Key, Element> bindings = new HashMap<>();
16+
private final KeyFactory keyFactory;
17+
18+
@Inject
19+
public BindingRegistry(KeyFactory keyFactory) {
20+
this.keyFactory = keyFactory;
21+
}
22+
23+
void register(ExecutableElement method) {
24+
Key key = keyFactory.getKey(method);
25+
Element previous = bindings.put(key, method);
26+
if (previous != null && !previous.equals(method)) {
27+
throw new ValidationFailure("Duplicate binding for " + key, method);
28+
}
29+
}
30+
}

compiler/src/main/java/io/jbock/simple/processor/step/ComponentStep.java

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
import io.jbock.simple.processor.ContextComponent;
88
import io.jbock.simple.processor.binding.Binding;
99
import io.jbock.simple.processor.binding.ComponentElement;
10-
import io.jbock.simple.processor.binding.InjectBindingFactory;
11-
import io.jbock.simple.processor.binding.KeyFactory;
1210
import io.jbock.simple.processor.util.SpecWriter;
1311
import io.jbock.simple.processor.util.TypeTool;
1412
import io.jbock.simple.processor.util.ValidationFailure;
@@ -31,28 +29,28 @@ public class ComponentStep implements Step {
3129

3230
private final Messager messager;
3331
private final TypeTool tool;
34-
private final KeyFactory keyFactory;
3532
private final TypeElementValidator typeElementValidator;
3633
private final ExecutableElementValidator executableElementValidator;
3734
private final SpecWriter specWriter;
38-
private final InjectBindingFactory injectBindingFactory;
35+
private final ComponentElement.Factory componentElementFactory;
36+
private final ContextComponent.Factory contextComponentFactory;
3937

4038
@Inject
4139
public ComponentStep(
4240
Messager messager,
4341
TypeTool tool,
44-
KeyFactory keyFactory,
4542
TypeElementValidator typeElementValidator,
4643
ExecutableElementValidator executableElementValidator,
4744
SpecWriter specWriter,
48-
InjectBindingFactory injectBindingFactory) {
45+
ComponentElement.Factory componentElementFactory,
46+
ContextComponent.Factory contextComponentFactory) {
4947
this.messager = messager;
5048
this.tool = tool;
51-
this.keyFactory = keyFactory;
5249
this.typeElementValidator = typeElementValidator;
5350
this.executableElementValidator = executableElementValidator;
5451
this.specWriter = specWriter;
55-
this.injectBindingFactory = injectBindingFactory;
52+
this.componentElementFactory = componentElementFactory;
53+
this.contextComponentFactory = contextComponentFactory;
5654
}
5755

5856
@Override
@@ -76,7 +74,7 @@ public Set<? extends Element> process(Map<String, Set<Element>> elementsByAnnota
7674

7775
private void process(TypeElement typeElement) {
7876
typeElementValidator.validate(typeElement);
79-
ComponentElement component = ComponentElement.create(typeElement, keyFactory);
77+
ComponentElement component = componentElementFactory.create(typeElement);
8078
component.factoryElement().ifPresent(factory -> {
8179
ExecutableElement method = factory.singleAbstractMethod();
8280
if (!tool.types().isSameType(method.getReturnType(), typeElement.asType())) {
@@ -88,8 +86,7 @@ private void process(TypeElement typeElement) {
8886
executableElementValidator.validate(m);
8987
}
9088
}
91-
ContextComponent componentComponent = ContextComponent.create(
92-
component, tool, injectBindingFactory, keyFactory);
89+
ContextComponent componentComponent = contextComponentFactory.create(component);
9390
Generator generator = componentComponent.generator();
9491
List<Binding> bindings = componentComponent.topologicalSorter().sortedBindings();
9592
TypeSpec typeSpec = generator.generate(bindings);

compiler/src/main/java/io/jbock/simple/processor/step/InjectStep.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,18 @@ public class InjectStep implements Step {
2525
private final InjectBindingValidator validator;
2626
private final ExecutableElementValidator executableElementValidator;
2727
private final Messager messager;
28+
private final BindingRegistry bindingRegistry;
2829

2930
@Inject
3031
public InjectStep(
3132
InjectBindingValidator validator,
3233
ExecutableElementValidator executableElementValidator,
33-
Messager messager) {
34+
Messager messager,
35+
BindingRegistry bindingRegistry) {
3436
this.validator = validator;
3537
this.executableElementValidator = executableElementValidator;
3638
this.messager = messager;
39+
this.bindingRegistry = bindingRegistry;
3740
}
3841

3942
@Override
@@ -55,10 +58,12 @@ public Set<? extends Element> process(Map<String, Set<Element>> elementsByAnnota
5558
for (ExecutableElement constructor : constructors) {
5659
executableElementValidator.validate(constructor);
5760
validator.validateConstructor(constructor);
61+
bindingRegistry.register(constructor);
5862
}
5963
for (ExecutableElement method : methods) {
6064
executableElementValidator.validate(method);
6165
validator.validateStaticMethod(method);
66+
bindingRegistry.register(method);
6267
}
6368
checkFields(elements);
6469
} catch (ValidationFailure f) {

compiler/src/main/java/io/jbock/simple/processor/step/ProvidesStep.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@
2020
public class ProvidesStep implements Step {
2121

2222
private final Messager messager;
23+
private final BindingRegistry bindingRegistry;
2324

2425
@Inject
2526
public ProvidesStep(
26-
Messager messager) {
27+
Messager messager,
28+
BindingRegistry bindingRegistry) {
2729
this.messager = messager;
30+
this.bindingRegistry = bindingRegistry;
2831
}
2932

3033
@Override
@@ -50,6 +53,7 @@ public Set<? extends Element> process(Map<String, Set<Element>> elementsByAnnota
5053
if (enclosing.getAnnotation(Component.class) == null) {
5154
throw new ValidationFailure("The @Provides method must be nested inside a @Component", m);
5255
}
56+
bindingRegistry.register(m);
5357
}
5458
} catch (ValidationFailure f) {
5559
f.writeTo(messager);

0 commit comments

Comments
 (0)