Skip to content

Commit 6a8a375

Browse files
committed
integrate configuration with dependency injection
1 parent f0191ad commit 6a8a375

File tree

8 files changed

+323
-20
lines changed

8 files changed

+323
-20
lines changed

docs/asciidoc/dependency-injection.adoc

Lines changed: 114 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,41 @@ fun main(args: Array<String>) {
239239
<1> Install Guice extension
240240
<2> The javadoc:Jooby[require, java.lang.Class] call is now resolved by Guice
241241

242-
[discrete]
242+
==== Property Injection
243+
244+
Configuration properties can be injected using the `@Named` annotation:
245+
246+
.application.conf
247+
[source, bash]
248+
----
249+
currency = USD
250+
----
251+
252+
.Java
253+
[source,java,role="primary"]
254+
----
255+
256+
import javax.injext.Named;
257+
import javax.injext.Inject;
258+
259+
public class BillingService {
260+
261+
@Inject
262+
public BillingService(@Named("currency") String currency) {
263+
...
264+
}
265+
266+
}
267+
----
268+
269+
.Kotlin
270+
[source,kotlin,role="secondary"]
271+
----
272+
class BillingService @Inject constructor(@Named("currency") currency: String) {
273+
...
274+
}
275+
----
276+
243277
==== MVC routes
244278

245279
Guice will also provisioning MVC routes
@@ -299,15 +333,15 @@ The lifecycle of `MyController` is now managed by Guice. Also:
299333
.Installing Spring
300334
[source, java, role = "primary"]
301335
----
302-
package myapp; <1>
336+
package myapp; <1>
303337
304338
import static io.jooby.Jooby.runApp;
305-
import io.jooby.di.Spring;
339+
import io.jooby.di.Springby;
306340
307341
public class App extends Jooby {
308342
309343
{
310-
install(new Spring()); <2>
344+
install(new Springby()); <2>
311345
312346
get("/", ctx -> {
313347
MyService service = require(MyService.class); <3>
@@ -327,12 +361,12 @@ public class App extends Jooby {
327361
package myapp <1>
328362
329363
import io.jooby.runApp
330-
import io.jooby.di.Spring
364+
import io.jooby.di.Springby
331365
332366
fun main(args: Array<String>) {
333367
runApp(args) {
334368
335-
install(new Spring()) <2>
369+
install(new Springby()) <2>
336370
337371
get ("/") { ctx ->
338372
val service = require(MyService::class) <3>
@@ -352,7 +386,43 @@ Spring uses the application package and sub-packages to scan. If you need extra
352386
install(new Spring("foo", "bar"));
353387
----
354388

355-
[discrete]
389+
==== Property Injection
390+
391+
Configuration properties can be injected using the `@Value` annotation:
392+
393+
.application.conf
394+
[source, bash]
395+
----
396+
currency = USD
397+
----
398+
399+
.Java
400+
[source,java,role="primary"]
401+
----
402+
import javax.injext.Inject;
403+
import org.springframework.beans.factory.annotation.Value;
404+
405+
public class BillingService {
406+
407+
@Inject
408+
public BillingService(@Value("currency") String currency) {
409+
...
410+
}
411+
412+
}
413+
----
414+
415+
.Kotlin
416+
[source,kotlin,role="secondary"]
417+
----
418+
import javax.injext.Inject
419+
import org.springframework.beans.factory.annotation.Value
420+
421+
class BillingService @Inject constructor(@Value("${currency}") currency: String) {
422+
...
423+
}
424+
----
425+
356426
==== MVC routes
357427

358428
The Spring extension does a bit more in relation to MVC routes:
@@ -445,7 +515,43 @@ fun main(args: Array<String>) {
445515
<1> Install Weld
446516
<2> The javadoc:Jooby[require, java.lang.Class] call is now resolved by Weld
447517

448-
[discrete]
518+
==== Property Injection
519+
520+
Configuration properties can be injected using the `@Named` annotation:
521+
522+
.application.conf
523+
[source, bash]
524+
----
525+
currency = USD
526+
----
527+
528+
.Java
529+
[source,java,role="primary"]
530+
----
531+
import javax.injext.Inject;
532+
import javax.injext.Named;
533+
534+
public class BillingService {
535+
536+
@Inject
537+
public BillingService(@Named("currency") String currency) {
538+
...
539+
}
540+
541+
}
542+
----
543+
544+
.Kotlin
545+
[source,kotlin,role="secondary"]
546+
----
547+
import javax.injext.Inject
548+
import javax.injext.Named
549+
550+
class BillingService @Inject constructor(@Named("currency") currency: String) {
551+
...
552+
}
553+
----
554+
449555
==== MVC routes
450556

451557
The Weld extension does a bit more in relation to MVC routes:
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*
14+
* Copyright 2014 Edgar Espina
15+
*/
16+
package io.jooby.di;
17+
18+
import com.google.inject.Binder;
19+
import com.google.inject.Key;
20+
import com.google.inject.Module;
21+
import com.google.inject.name.Named;
22+
import com.google.inject.name.Names;
23+
import com.google.inject.util.Types;
24+
import com.typesafe.config.Config;
25+
import com.typesafe.config.ConfigValue;
26+
import io.jooby.Environment;
27+
28+
import javax.annotation.Nonnull;
29+
import java.lang.reflect.Type;
30+
import java.util.List;
31+
import java.util.Map;
32+
import java.util.stream.Collectors;
33+
34+
public class GuiceEnvironment implements Module {
35+
private Environment env;
36+
37+
public GuiceEnvironment(@Nonnull Environment env) {
38+
this.env = env;
39+
}
40+
41+
@Override public void configure(Binder binder) {
42+
Config config = env.getConfig();
43+
// terminal nodes
44+
for (Map.Entry<String, ConfigValue> entry : config.entrySet()) {
45+
String name = entry.getKey();
46+
Named named = Names.named(name);
47+
Object value = entry.getValue().unwrapped();
48+
if (value instanceof List) {
49+
List values = (List) value;
50+
Type listType = Types.listOf(values.iterator().next().getClass());
51+
Key key = Key.get(listType, Names.named(name));
52+
binder.bind(key).toInstance(values);
53+
value = values.stream().map(Object::toString).collect(Collectors.joining(","));
54+
}
55+
binder.bindConstant().annotatedWith(named).to(value.toString());
56+
}
57+
binder.bind(Config.class).toInstance(config);
58+
binder.bind(Environment.class).toInstance(env);
59+
}
60+
}

modules/jooby-guice/src/main/java/io/jooby/di/Guiceby.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,27 @@
2424
import io.jooby.Jooby;
2525

2626
import javax.annotation.Nonnull;
27+
import java.util.ArrayList;
28+
import java.util.List;
29+
import java.util.stream.Stream;
2730

2831
public class Guiceby implements Extension {
2932

3033
private Injector injector;
31-
private Module[] modules;
34+
private List<Module> modules = new ArrayList<>();
3235

3336
public Guiceby(@Nonnull Injector injector) {
3437
this.injector = injector;
3538
}
3639

3740
public Guiceby(@Nonnull Module... modules) {
38-
this.modules = modules;
41+
Stream.of(modules).forEach(this.modules::add);
3942
}
4043

4144
@Override public void install(@Nonnull Jooby application) {
4245
if (injector == null) {
4346
Environment env = application.getEnvironment();
47+
modules.add(new GuiceEnvironment(env));
4448
Stage stage = env.isActive("dev", "test") ? Stage.DEVELOPMENT : Stage.PRODUCTION;
4549
injector = Guice.createInjector(stage, modules);
4650
}

modules/jooby-spring/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
<version>${jooby.version}</version>
2626
</dependency>
2727

28-
<!-- Spring -->
28+
<!-- Springby -->
2929
<dependency>
3030
<groupId>org.springframework</groupId>
3131
<artifactId>spring-context</artifactId>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*
14+
* Copyright 2014 Edgar Espina
15+
*/
16+
package io.jooby.di;
17+
18+
import com.typesafe.config.Config;
19+
import org.springframework.core.env.PropertySource;
20+
21+
public class ConfigPropertySource extends PropertySource<Config> {
22+
public ConfigPropertySource(String name, Config source) {
23+
super(name, source);
24+
}
25+
26+
@Override public Object getProperty(String key) {
27+
if (source.hasPath(key)) {
28+
return source.getAnyRef(key);
29+
}
30+
return null;
31+
}
32+
}

modules/jooby-spring/src/main/java/io/jooby/di/Spring.java renamed to modules/jooby-spring/src/main/java/io/jooby/di/Springby.java

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,20 @@
1515
*/
1616
package io.jooby.di;
1717

18+
import com.typesafe.config.Config;
19+
import io.jooby.Environment;
1820
import io.jooby.Extension;
1921
import io.jooby.Jooby;
2022
import org.springframework.beans.factory.config.BeanDefinition;
23+
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
2124
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
25+
import org.springframework.core.env.ConfigurableEnvironment;
26+
import org.springframework.core.env.MutablePropertySources;
2227
import org.springframework.stereotype.Controller;
2328

2429
import javax.annotation.Nonnull;
2530

26-
public class Spring implements Extension {
31+
public class Springby implements Extension {
2732

2833
private AnnotationConfigApplicationContext applicationContext;
2934

@@ -33,25 +38,25 @@ public class Spring implements Extension {
3338

3439
private String[] packages;
3540

36-
public Spring(@Nonnull AnnotationConfigApplicationContext applicationContext) {
41+
public Springby(@Nonnull AnnotationConfigApplicationContext applicationContext) {
3742
this.applicationContext = applicationContext;
3843
}
3944

40-
public Spring() {
45+
public Springby() {
4146
this.applicationContext = null;
4247
}
4348

44-
public Spring(String... packages) {
49+
public Springby(String... packages) {
4550
this.applicationContext = null;
4651
this.packages = packages;
4752
}
4853

49-
public Spring noRefresh() {
54+
public Springby noRefresh() {
5055
this.refresh = false;
5156
return this;
5257
}
5358

54-
public Spring noMvcRoutes() {
59+
public Springby noMvcRoutes() {
5560
this.registerMvcRoutes = false;
5661
return this;
5762
}
@@ -63,12 +68,27 @@ public Spring noMvcRoutes() {
6368
String basePackage = application.getBasePackage();
6469
if (basePackage == null) {
6570
throw new IllegalArgumentException(
66-
"Spring application context requires at least one package to scan.");
71+
"Springby application context requires at least one package to scan.");
6772
}
6873
packages = new String[]{basePackage};
6974
}
75+
Environment environment = application.getEnvironment();
76+
7077
applicationContext = defaultApplicationContext(packages);
7178

79+
ConfigurableEnvironment configurableEnvironment = applicationContext.getEnvironment();
80+
String[] profiles = environment.getActiveNames().toArray(new String[0]);
81+
configurableEnvironment.setActiveProfiles(profiles);
82+
configurableEnvironment.setDefaultProfiles(profiles);
83+
84+
Config config = environment.getConfig();
85+
MutablePropertySources propertySources = configurableEnvironment.getPropertySources();
86+
propertySources.addFirst(new ConfigPropertySource("application", config));
87+
88+
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
89+
beanFactory.registerSingleton("config", config);
90+
beanFactory.registerSingleton("environment", environment);
91+
7292
application.onStop(applicationContext);
7393
}
7494
if (refresh) {

0 commit comments

Comments
 (0)