Injecting Properties Into Java EE Applications
To make basic datatypes injectable into POJOs, like:
@Inject
private String greeting;
@Inject
private int intValue;
...you will have to expose them first. The name of field may act as the lookup key:
//...
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.Annotated;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.inject.Inject;
public class Configurator {
//...
@Inject
Instance<Map<String, String>> initialValues;
public void init() {
this.store = //...
for (Map<String, String> initial : initialValues) {
this.store.putAll(initial);
}
}
@Produces
public String getString(InjectionPoint ip) {
String className = ip.getMember().getDeclaringClass().getName();
String key = className + "." + ip.getMember().getName();
String fieldName = computeKeyName(ip.getAnnotated(), key);
return this.store.get(fieldName);
}
String computeKeyName(Annotated annotated, String key) {
Configurable annotation = annotated.getAnnotation(Configurable.class);
return annotation == null ? key : annotation.value();
}
@Produces
public long getLong(InjectionPoint ip) {
String stringValue = getString(ip);
if (stringValue == null) {
return 0;
}
return Long.parseLong(stringValue);
}
}
The conventional field name as lookup key can be overridden with an annotation:
@Inject
@Configurable("msg")
String message;
The annotation is expects a single string which is going to be used as a key:
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Configurable {
String value();
}
Now you only need to expose a datasource of your choice as Map<String, String>
,
like e.g. environment variables or System-properties to make them injectable:
import javax.enterprise.inject.Produces;
public class Initializer {
@Produces
public Map<String, String> getInitialConfiguration() {
//...fetch properties from wherever you like
}
}
"How to inject properties into Java EE apps" was one of the questions in the recent airhacks.tv.
The code above was taken from JCache Configurator for Java EE -- a one-class Java EE framework. See also the Java Magazine article Convention Over Configuration in Java EE 6.
See you at Java EE Workshops at Munich Airport, Terminal 2 or Virtual Dedicated Workshops / consulting. Is Munich's airport too far? Learn from home: airhacks.io.
But what if you need to configure a JPA Entity, where Injection is not available?
Posted by Alex on February 09, 2016 at 08:39 AM CET #
Wow, this is the most contrived way to use properties I have ever seen!
Posted by javaservant on February 09, 2016 at 01:39 PM CET #
I think that's a generic solution. Is there any faster, shorter, easier way to inject values in .properties files into POJOs? I need some convention over configuration like @Inject(from="application.properites", key="some.key") private String someKey; without any helper, producer ... classes. Then I need to change the .properties file for different environment. So maybe @Profile("local") @Inject(from="application.properties", key="some.key") will get the value from application-local.properties. Finally, this looks like Spring :-)
Posted by Thai on February 10, 2016 at 07:36 PM CET #
Thank you Adam. This is a fantastic, clean and concise solution. Our team are now using a database driven version of this example.
Our solution needed the annotation to have: @Nonbinding public String value();
Posted by Geoff Hayward on February 16, 2016 at 02:17 PM CET #
Seems like a good old singleton.
How about it like this:
@AplicationScoped
public class MySettings {
Map<String, Object> settings;
...
Object getSetting(String name) {...}
}
Much simpler. Still configurable, injectable, testable... Or not?
Posted by Matyas on February 18, 2016 at 03:42 PM CET #
If you need a tool to translate .properties files, check out the localization management platform https://poeditor.com
It's easy to set up and free to use up to 1000 strings.
Posted by Parov on June 08, 2016 at 03:30 PM CEST #