Skip to content

Commit b01b35f

Browse files
committed
Javadoc improvements
1 parent 6bf30f0 commit b01b35f

File tree

5 files changed

+144
-65
lines changed

5 files changed

+144
-65
lines changed

inject/src/main/java/io/avaje/inject/BeanEntry.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
/**
66
* A bean entry with priority and optional name.
7+
*
8+
* @see BeanScope#all()
79
*/
810
public interface BeanEntry {
911

inject/src/main/java/io/avaje/inject/BeanScope.java

Lines changed: 61 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
*
1313
* <h3>Create a BeanScope</h3>
1414
* <p>
15-
* We can programmatically create a BeanScope via BeanScopeBuilder.
15+
* We can programmatically create a BeanScope via {@code BeanScope.newBuilder()}.
1616
* </p>
1717
* <pre>{@code
1818
*
@@ -26,35 +26,75 @@
2626
* }
2727
*
2828
* }</pre>
29+
*
30+
* <h3>External dependencies</h3>
31+
* <p>
32+
* We can supporting external dependencies when creating the BeanScope. We need to do 2 things.
33+
* we need to specify these via
34+
* </p>
35+
* <ul>
36+
* <li>
37+
* 1. Specify the external dependency via {@code @InjectModule(requires=...)}.
38+
* Otherwise at compile time the annotation processor detects it as a missing dependency and we can't compile.
39+
* </li>
40+
* <li>
41+
* 2. Provide the dependency when creating the BeanScope
42+
* </li>
43+
* </ul>
44+
* <p>
45+
* For example, given we have Pump as an externally provided dependency.
46+
*
47+
* <pre>{@code
48+
*
49+
* // tell the annotation processor Pump is provided externally
50+
* // otherwise it thinks we have a missing dependency
51+
*
52+
* @InjectModule(requires=Pump.class)
53+
*
54+
* }</pre>
55+
* <p>
56+
* When we build the BeanScope provide the dependency via {@link BeanScopeBuilder#withBean(Class, Object)}.
57+
*
58+
* <pre>{@code
59+
*
60+
* // provide external dependencies ...
61+
* Pump pump = ...
62+
*
63+
* try (BeanScope scope = BeanScope.newBuilder()
64+
* .withBean(Pump.class, pump)
65+
* .build()) {
66+
*
67+
* CoffeeMaker coffeeMaker = context.get(CoffeeMaker.class);
68+
* coffeeMaker.makeIt()
69+
* }
70+
*
71+
* }</pre>
2972
*/
3073
public interface BeanScope extends AutoCloseable {
3174

3275
/**
33-
* Build a bean scope with options for shutdown hook and supplying test doubles.
76+
* Build a bean scope with options for shutdown hook and supplying external dependencies.
3477
* <p>
35-
* We would choose to use BeanScopeBuilder in test code (for component testing)
36-
* as it gives us the ability to inject test doubles, mocks, spy's etc.
37-
* </p>
78+
* We can optionally:
79+
* <ul>
80+
* <li>Provide external dependencies</li>
81+
* <li>Specify a parent BeanScope</li>
82+
* <li>Specify specific modules to wire</li>
83+
* <li>Specify to include a shutdown hook (to fire preDestroy lifecycle methods)</li>
84+
* <li>Use {@code forTesting()} to specify mocks and spies to use when wiring tests</li>
85+
* </ul>
3886
*
3987
* <pre>{@code
4088
*
41-
* @Test
42-
* public void someComponentTest() {
43-
*
44-
* MyRedisApi mockRedis = mock(MyRedisApi.class);
45-
* MyDbApi mockDatabase = mock(MyDbApi.class);
46-
*
47-
* try (BeanScope scope = BeanScope.newBuilder()
48-
* .withBeans(mockRedis, mockDatabase)
49-
* .build()) {
89+
* // create a BeanScope ...
5090
*
51-
* // built with test doubles injected ...
52-
* CoffeeMaker coffeeMaker = scope.get(CoffeeMaker.class);
53-
* coffeeMaker.makeIt();
91+
* try (BeanScope scope = BeanScope.newBuilder()
92+
* .build()) {
5493
*
55-
* assertThat(...
56-
* }
94+
* CoffeeMaker coffeeMaker = context.get(CoffeeMaker.class);
95+
* coffeeMaker.makeIt()
5796
* }
97+
*
5898
* }</pre>
5999
*/
60100
static BeanScopeBuilder newBuilder() {
@@ -102,10 +142,6 @@ static BeanScopeBuilder newBuilder() {
102142
*
103143
* }</pre>
104144
*
105-
* <p>
106-
* The classic use case for this is registering controllers or routes to
107-
* web frameworks like Sparkjava, Javlin, Rapidoid etc.
108-
*
109145
* @param annotation An annotation class.
110146
*/
111147
List<Object> listByAnnotation(Class<?> annotation);
@@ -144,15 +180,14 @@ static BeanScopeBuilder newBuilder() {
144180
/**
145181
* Return all the bean entries from the scope.
146182
* <p>
147-
* The bean entries include
148-
* This includes entries from the parent scope if it has one.
183+
* The bean entries include entries from the parent scope if it has one.
149184
*
150185
* @return All bean entries from the scope.
151186
*/
152187
List<BeanEntry> all();
153188

154189
/**
155-
* Close the scope firing any <code>@PreDestroy</code> methods.
190+
* Close the scope firing any <code>@PreDestroy</code> lifecycle methods.
156191
*/
157192
void close();
158193
}

inject/src/main/java/io/avaje/inject/BeanScopeBuilder.java

Lines changed: 24 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -15,33 +15,33 @@
1515
* // external dependencies
1616
* Pump pump = ...
1717
*
18-
* try (BeanScope scope = BeanScope.newBuilder()
18+
* BeanScope scope = BeanScope.newBuilder()
1919
* .withBean(pump)
20-
* .build()) {
20+
* .build();
21+
*
22+
* CoffeeMaker coffeeMaker = scope.get(CoffeeMaker.class);
23+
* coffeeMaker.makeIt();
2124
*
22-
* CoffeeMaker coffeeMaker = scope.get(CoffeeMaker.class);
23-
* coffeeMaker.makeIt();
24-
* }
2525
* }</pre>
2626
*/
2727
public interface BeanScopeBuilder {
2828

2929
/**
3030
* Create the bean scope registering a shutdown hook (defaults to false, no shutdown hook).
3131
* <p>
32-
* The expectation is that the BeanScopeBuilder is closed via code or via using
33-
* try with resources.
32+
* With {@code withShutdownHook(true)} a shutdown hook will be registered with the Runtime
33+
* and executed when the JVM initiates a shutdown. This then will run the {@code preDestroy}
34+
* lifecycle methods.
3435
* </p>
3536
* <pre>{@code
3637
*
3738
* // automatically closed via try with resources
3839
*
39-
* try (BeanScope scope = BeanScope.newBuilder()
40+
* BeanScope scope = BeanScope.newBuilder()
4041
* .withShutdownHook(true)
41-
* .build()) {
42+
* .build());
4243
*
43-
* String makeIt = scope.get(CoffeeMaker.class).makeIt();
44-
* }
44+
* // on JVM shutdown the preDestroy lifecycle methods are executed
4545
*
4646
* }</pre>
4747
*
@@ -59,15 +59,12 @@ public interface BeanScopeBuilder {
5959
*
6060
* <pre>{@code
6161
*
62-
* try (BeanScope scope = BeanScope.newBuilder()
62+
* BeanScope scope = BeanScope.newBuilder()
6363
* .withModules(new CustomModule())
64-
* .build()) {
64+
* .build());
6565
*
66-
* // built with test doubles injected ...
67-
* CoffeeMaker coffeeMaker = scope.get(CoffeeMaker.class);
68-
* coffeeMaker.makeIt();
69-
*
70-
* }
66+
* CoffeeMaker coffeeMaker = scope.get(CoffeeMaker.class);
67+
* coffeeMaker.makeIt();
7168
*
7269
* }</pre>
7370
*
@@ -90,19 +87,12 @@ public interface BeanScopeBuilder {
9087
* Pump pump = ...
9188
* Grinder grinder = ...
9289
*
93-
* try (BeanScope scope = BeanScope.newBuilder()
90+
* BeanScope scope = BeanScope.newBuilder()
9491
* .withBeans(pump, grinder)
95-
* .build()) {
92+
* .build();
9693
*
97-
* CoffeeMaker coffeeMaker = scope.get(CoffeeMaker.class);
98-
* coffeeMaker.makeIt();
99-
*
100-
* Pump pump1 = scope.get(Pump.class);
101-
* Grinder grinder1 = scope.get(Grinder.class);
102-
*
103-
* assertThat(pump1).isSameAs(pump);
104-
* assertThat(grinder1).isSameAs(grinder);
105-
* }
94+
* CoffeeMaker coffeeMaker = scope.get(CoffeeMaker.class);
95+
* coffeeMaker.makeIt();
10696
*
10797
* }</pre>
10898
*
@@ -112,10 +102,7 @@ public interface BeanScopeBuilder {
112102
BeanScopeBuilder withBeans(Object... beans);
113103

114104
/**
115-
* Add a supplied bean instance with the given injection type.
116-
* <p>
117-
* This is typically a test double often created by Mockito or similar.
118-
* </p>
105+
* Add a supplied bean instance with the given injection type (typically an interface type).
119106
*
120107
* <pre>{@code
121108
*
@@ -168,7 +155,9 @@ public interface BeanScopeBuilder {
168155
* Build and return the bean scope.
169156
* <p>
170157
* The BeanScope is effectively immutable in that all components are created
171-
* eagerly (eager singletons).
158+
* and all PostConstruct lifecycle methods have been invoked.
159+
* <p>
160+
* The beanScope effectively contains eager singletons.
172161
*
173162
* @return The BeanScope
174163
*/
@@ -187,10 +176,7 @@ interface ForTesting extends BeanScopeBuilder {
187176
* try (BeanScope scope = BeanScope.newBuilder()
188177
* .forTesting()
189178
* .withMock(Pump.class)
190-
* .withMock(Grinder.class, grinder -> {
191-
* // setup the mock
192-
* when(grinder.grindBeans()).thenReturn("stub response");
193-
* })
179+
* .withMock(Grinder.class)
194180
* .build()) {
195181
*
196182
*

inject/src/main/java/io/avaje/inject/InjectModule.java

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,37 @@
22

33
/**
44
* Used to explicitly specify if it depends on externally provided beans or provides.
5+
*
6+
* <h3>External dependencies</h3>
57
* <p>
8+
* Use {@code requires} to specify dependencies that will be provided externally.
9+
*
10+
* <pre>{@code
11+
*
12+
* // tell the annotation processor Pump and Grinder are provided externally
13+
* // otherwise it will think we have missing dependencies at compile time
14+
*
15+
* @InjectModule(requires = {Pump.class, Grinder.class})
16+
*
17+
* }</pre>
18+
*
19+
* <h3>Custom scope depending on another scope</h3>
20+
* <p>
21+
* When using custom scopes we can have the case where we desire one scope to depend
22+
* on another. In this case we put the custom scope annotation in requires.
23+
* <p>
24+
* For example lets say we have a custom scope called {@code StoreComponent} and that
25+
* depends on {@code QueueComponent} custom scope.
26+
*
27+
* <pre>{@code
28+
*
29+
* @Scope
30+
* @InjectModule(requires = {QueueComponent.class})
31+
* public @interface StoreComponent {
32+
* }
33+
*
34+
*
35+
* }</pre>
636
*/
737
public @interface InjectModule {
838

@@ -14,13 +44,19 @@
1444
/**
1545
* Explicitly define features that are provided by this module and required by other modules.
1646
* <p>
17-
* This is used to order wiring across multiple modules.
47+
* This is used to order wiring across multiple modules. Modules that provide dependencies
48+
* should be wired before modules that require dependencies.
1849
*/
1950
Class<?>[] provides() default {};
2051

2152
/**
2253
* The dependencies that are provided externally or by other modules and that are required
2354
* when wiring this module.
55+
* <p>
56+
* This effectively tells the annotation processor that these types are expected to be
57+
* provided and to not treat them as missing dependencies. If we don't do this the annotation
58+
* processor thinks the dependency is missing and will error the compilation saying there is
59+
* a missing dependency.
2460
*/
2561
Class<?>[] requires() default {};
2662

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,24 @@
11
/**
22
* Avaje Inject API - see {@link io.avaje.inject.BeanScope}.
3+
* <p>
4+
* Create {@link io.avaje.inject.BeanScope} using a builder.
5+
* Obtain beans from the scope and use them.
6+
* <p>
7+
* We should ensure the BeanScope is closed in order to fire
8+
* preDestroy lifecycle methods. We can do this via a shutdown
9+
* hook, or try with resource block or explicitly via application code.
10+
*
11+
* <pre>{@code
12+
*
13+
* BeanScope scope = BeanScope.newBuilder()
14+
* .build();
15+
*
16+
* CoffeeMaker coffeeMaker = scope.get(CoffeeMaker.class);
17+
* coffeeMaker.makeIt();
18+
*
19+
* // fire preDestroy lifecycle methods
20+
* scope.close();
21+
*
22+
* }</pre>
323
*/
424
package io.avaje.inject;

0 commit comments

Comments
 (0)