Skip to content

Commit 5fdb459

Browse files
committed
registry: Add support for java.lang.reflect.Type
registry: Allow to bind List/Set/Map - fix #3659 - fix #3660
1 parent 9d94422 commit 5fdb459

File tree

22 files changed

+581
-74
lines changed

22 files changed

+581
-74
lines changed

docs/asciidoc/dependency-injection.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
== Dependency Injection
1+
=== Dependency Injection
22

33
include::modules/avaje-inject.adoc[]
44

docs/asciidoc/di-dagger.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
=== Dagger
1+
==== Dagger
22

33
1) Add Dagger to your project
44

@@ -95,7 +95,7 @@ fun main(args: Array<String>) {
9595
Check out the https://dagger.dev/tutorial[Dagger tutorial] to learn more.
9696
====
9797

98-
==== MVC routes
98+
===== MVC routes
9999

100100
Integration of MVC routes with Dagger is as simple as:
101101

docs/asciidoc/extension.adoc

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public class MyExtension implements Extension {
2121
DataSource dataSource = createDataSource(); <1>
2222
2323
ServiceRegistry registry = application.getServices(); <2>
24-
registry.put(DataSource.class, dataSource); <3>
24+
registry.put(MyDataSource.class, dataSource); <3>
2525
2626
application.onStop(dataSource::close) <4>
2727
}
@@ -38,15 +38,15 @@ class MyExtension: Extension {
3838
val dataSource = createDataSource() <1>
3939
4040
val registry = application.services <2>
41-
registry.put(DataSource::class, dataSource) <3>
41+
registry.put(MyDataSource::class, dataSource) <3>
4242
application.onStop(dataSource::close) <4>
4343
}
4444
}
4545
----
4646

47-
<1> Create the service
48-
<2> Access to service registry
49-
<3> Add it to the service registry
47+
<1> Create the service (DataSource)
48+
<2> Access to the service registry
49+
<3> Save into the service registry
5050
<4> Close/release service on application stop
5151

5252
Let's install the extension and use the service!!
@@ -86,12 +86,67 @@ class App: Kooby({
8686
<1> Install the extension
8787
<2> Use the service
8888

89-
Services are accessible via javadoc:Registry[require, java.lang.Class].
89+
=== Collection of Services
90+
91+
Adding a collection to the service registry is supported too.
92+
93+
.List/Set
94+
[source,java]
95+
----
96+
import io.jooby.Extension;import io.jooby.Reified;
97+
98+
public class Cats implements Extension {
99+
100+
public void install(Jooby application) {
101+
ServiceRegistry registry = application.getServices();
102+
// as list
103+
registry.listOf(Animal.class).add(new Cat());
104+
// as set
105+
registry.setOf(Animal.class).add(new Cat());
106+
// as map
107+
registry.mapOf(String.class, Animal.class).put("cat", new Cat());
108+
}
109+
}
110+
111+
public class Dogs implements Extension {
112+
113+
public void install(Jooby application) {
114+
ServiceRegistry registry = application.getServices();
115+
// as list
116+
registry.listOf(Animal.class).add(new Dog());
117+
// as set
118+
registry.setOf(Animal.class).add(new Dog());
119+
// as map
120+
registry.mapOf(String.class, Animal.class).put("dog", new Dog());
121+
}
122+
}
123+
124+
{
125+
install(new Cats());
126+
install(new Dogs());
127+
// as list
128+
get("/list", ctx -> {
129+
return ctx.require(Reified.list(Animal.class));
130+
});
131+
// as set
132+
get("/set", ctx -> {
133+
return ctx.require(Reified.set(Animal.class));
134+
});
135+
// as map
136+
get("/map", ctx -> {
137+
return ctx.require(Reified.map(String.class, Animal.class));
138+
});
139+
}
140+
----
141+
142+
Services are accessible via javadoc:Registry[require, java.lang.Class] and integrated with
143+
dependency injection frameworks provided by Jooby like Guice and Avaje Inject. This mean they are
144+
accessible using the `jakarta.inject.Inject` annotation.
90145

91146
In addition to services, an extension module may provides infrastructure routes, body decoder/encoder,
92147
template engines, etc.
93148

94149
The extension mechanism is a simple way of reusing code and decoupling technical features from
95-
business logic.
150+
business logic.
96151

97-
More advanced techniques are describe in the <<Dependency Injection>> section.
152+
More advanced techniques are described in the next section.

docs/asciidoc/index.adoc

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -240,22 +240,22 @@ include::error-handler.adoc[]
240240

241241
include::problem-details.adoc[]
242242

243-
include::handlers.adoc[]
244-
245243
include::configuration.adoc[]
246244

245+
include::extension.adoc[]
246+
247+
include::dependency-injection.adoc[]
248+
247249
include::testing.adoc[]
248250

249251
include::dev-tools.adoc[]
250252

253+
include::handlers.adoc[]
254+
251255
include::packaging/packaging.adoc[]
252256

253257
include::servers.adoc[]
254258

255-
include::extension.adoc[]
256-
257-
include::dependency-injection.adoc[]
258-
259259
include::modules.adoc[]
260260

261261
== Appendix

docs/asciidoc/modules/avaje-inject.adoc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
=== Avaje Inject
1+
==== Avaje Inject
22

33
1) Add Avaje Inject to your project
44

@@ -89,7 +89,7 @@ fun main(args: Array<String>) {
8989
<1> Install Avaje Inject module
9090
<2> The javadoc:Jooby[require, java.lang.Class] call is now resolved by Avaje Inject
9191

92-
==== Property Injection
92+
===== Property Injection
9393

9494
Configuration properties can be injected using the `@Named` annotation. As Avaje checks beans at compile time, `@External` is required to prevent false-positive compilation errors:
9595

@@ -122,7 +122,7 @@ class BillingService @Inject constructor(@External @Named("currency") currency:
122122
}
123123
----
124124

125-
==== MVC routes
125+
===== MVC routes
126126

127127
Avaje Inject will also provisioning MVC routes
128128

docs/asciidoc/modules/guice.adoc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
=== Guice
1+
==== Guice
22

33
1) Add Guice dependency to your project:
44

@@ -52,7 +52,7 @@ fun main(args: Array<String>) {
5252
<1> Install Guice module
5353
<2> The javadoc:Jooby[require, java.lang.Class] call is now resolved by Guice
5454

55-
==== Property Injection
55+
===== Property Injection
5656

5757
Configuration properties can be injected using the `@Named` annotation:
5858

@@ -87,7 +87,7 @@ class BillingService @Inject constructor(@Named("currency") currency: String) {
8787
}
8888
----
8989

90-
==== MVC routes
90+
===== MVC routes
9191

9292
Guice will also provisioning MVC routes
9393

jooby/src/main/java/io/jooby/DefaultContext.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ default <T> T require(@NonNull Class<T> type) throws RegistryException {
5757
return getRouter().require(type);
5858
}
5959

60+
@NonNull @Override
61+
default <T> T require(@NonNull Reified<T> type) throws RegistryException {
62+
return getRouter().require(type);
63+
}
64+
65+
@NonNull @Override
66+
default <T> T require(@NonNull Reified<T> type, @NonNull String name) throws RegistryException {
67+
return getRouter().require(type, name);
68+
}
69+
6070
@NonNull @Override
6171
default <T> T require(@NonNull ServiceKey<T> key) throws RegistryException {
6272
return getRouter().require(key);

jooby/src/main/java/io/jooby/ForwardingContext.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1324,6 +1324,16 @@ public <T> T require(@NonNull Class<T> type, @NonNull String name) throws Regist
13241324
return ctx.require(type, name);
13251325
}
13261326

1327+
@NonNull @Override
1328+
public <T> T require(@NonNull Reified<T> type) throws RegistryException {
1329+
return ctx.require(type);
1330+
}
1331+
1332+
@NonNull @Override
1333+
public <T> T require(@NonNull Reified<T> type, @NonNull String name) throws RegistryException {
1334+
return ctx.require(type, name);
1335+
}
1336+
13271337
@NonNull @Override
13281338
public <T> T require(@NonNull ServiceKey<T> key) throws RegistryException {
13291339
return ctx.require(key);

jooby/src/main/java/io/jooby/Jooby.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,16 @@ public <T> T require(@NonNull Class<T> type) {
827827
return require(ServiceKey.key(type));
828828
}
829829

830+
@NonNull @Override
831+
public <T> T require(@NonNull Reified<T> type) throws RegistryException {
832+
return require(ServiceKey.key(type));
833+
}
834+
835+
@NonNull @Override
836+
public <T> T require(@NonNull Reified<T> type, @NonNull String name) throws RegistryException {
837+
return require(ServiceKey.key(type, name));
838+
}
839+
830840
@Override
831841
public @NonNull <T> T require(@NonNull ServiceKey<T> key) {
832842
ServiceRegistry services = getServices();
@@ -835,10 +845,7 @@ public <T> T require(@NonNull Class<T> type) {
835845
if (!registry.isSet()) {
836846
throw new RegistryException("Service not found: " + key);
837847
}
838-
String name = key.getName();
839-
return name == null
840-
? registry.get().require(key.getType())
841-
: registry.get().require(key.getType(), name);
848+
return registry.get().require(key);
842849
}
843850
return service;
844851
}

jooby/src/main/java/io/jooby/Registry.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,27 @@ public interface Registry {
3737
*/
3838
@NonNull <T> T require(@NonNull Class<T> type, @NonNull String name) throws RegistryException;
3939

40+
/**
41+
* Provides an instance of the given type.
42+
*
43+
* @param type Object type.
44+
* @param <T> Object type.
45+
* @return Instance of this type.
46+
* @throws RegistryException If there was a runtime failure while providing an instance.
47+
*/
48+
@NonNull <T> T require(@NonNull Reified<T> type) throws RegistryException;
49+
50+
/**
51+
* Provides an instance of the given type where name matches it.
52+
*
53+
* @param type Object type.
54+
* @param name Object name.
55+
* @param <T> Object type.
56+
* @return Instance of this type.
57+
* @throws RegistryException If there was a runtime failure while providing an instance.
58+
*/
59+
@NonNull <T> T require(@NonNull Reified<T> type, @NonNull String name) throws RegistryException;
60+
4061
/**
4162
* Provides an instance of the given type.
4263
*

0 commit comments

Comments
 (0)