Adam Bien's Weblog

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.


NEW workshop: Building HTML 5 Applications Without Frameworks, Full week in December 2016: from Java EE 7 Bootstrap, Effective, Architectures over Testing to Microservices
On demand workshops: Java EE 7: Bootstrap, Effective, Testing and Microservices available for streaming.

Newsletter: airhacksnews.com

A book about rethinking Java EE Patterns

Comments:

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 #

Post a Comment:
  • HTML Syntax: NOT allowed
realworldpatterns.com
Online Workshops
...the last 150 posts
...the last 10 comments
License