Adam Bien's Weblog

Wednesday Sep 07, 2011

How To Configure Java EE 6+ Applications ...Without XML

Primitives can be directly injected to EJBs and CDI managed beans with @Inject:


@Singleton
@Startup
public class HitsFlushTimer {

    @Inject
    private int hitsFlushRate;

 }


The injected values are returned by a method with matching return type and denoted with the @Produces annotation. Usually a dedicated component (EJB 3.1, CDI managed bean, or usual Java class) manages the configuration:

@Startup
@Singleton
public class Configuration {

    private Map configuration;
    private Set unconfiguredFields;

    @Inject
    private Instance configurationProvider;

    @PostConstruct
    public void fetchConfiguration() {
		//default values...
        this.configuration = new HashMap() {{
            put("hitsFlushRate", "1");
		    //...
        }};
        this.unconfiguredFields = new HashSet();
        mergeWithCustomConfiguration();
    }


  @javax.enterprise.inject.Produces
    public String getString(InjectionPoint point) {
        String fieldName = point.getMember().getName();
        String valueForFieldName = configuration.get(fieldName);
        if (valueForFieldName == null) {
            this.unconfiguredFields.add(fieldName);
        }
        return valueForFieldName;
    }

    @javax.enterprise.inject.Produces
    public int getInteger(InjectionPoint point) {
        String stringValue = getString(point);
        if (stringValue == null) {
            return 0;
        }
        return Integer.parseInt(stringValue);
    }

//...
}


The most interesting feature is the InjectionPoint argument in the method: public String getString(InjectionPoint point). It represents the injection point :-) and gives you information about the field, it's name and class. The InjectionPoint can be used to uniquely identify and so configure each field of a class individually.

[x-ray's cache flushing was configured that way. You will also find the code above in the git repo, See also page 98 "Configuration Over Convention with Inversion of Control" in Real World Java EE Night Hacks--Dissecting the Business Tier.]


Special Events: Java 8 with Java EE 7: "More Power with Less Code", 13th October, 2014 and Java EE 7: "Testing and Code Quality", 14th October, 2014

A book about rethinking Java EE Patterns

Comments:

this is a remarkable example and hack to implement Injection mechanisms

Posted by Lava Kafle on September 07, 2011 at 02:24 PM CEST #

My first impression: AMAZING but OBSCURE!
If the project is big, and there are many injections like this, I'm afraid it could be hard for the developer to locate where the injected value comes from.
And another question: what's the behavior of a singleton session in a clustered environment? Will the server, e.g. GlassFish, synchronize the configuration between clusters automatically?

Posted by shinzey on September 08, 2011 at 07:58 AM CEST #

Hi Adam,

Nice @Inject example. I am going to use this for sure! Just one question: What is the reason you made these @Inject fields private? (considering your previous blog: http://www.adam-bien.com/roller/abien/entry/inject_with_package_private_fields)

Tnx,
Ivar

Posted by Ivar on September 08, 2011 at 01:32 PM CEST #

@Shinzey,

"If the project is big, and there are many injections like this, I'm afraid it could be hard for the developer to locate where the injected value comes from."

The nice thing about the approach above is: all the configuration is coming from one source: from a class called Configuration. It centralizes all the configuration and makes it more readible.

"And another question: what's the behavior of a singleton session in a clustered environment? Will the server, e.g. GlassFish, synchronize the configuration between clusters automatically?"

Singletons are not clustered. This is also not needed for the purpose of configuration. Usually the state does not change after deployment. Otherwise it could be fetched from a DB.

thanks for your comment!,

adam

Posted by Adam Bien on September 08, 2011 at 03:38 PM CEST #

@Ivar,

"Just one question: What is the reason you made these @Inject fields private? "

A really good question with a simple answer: I'm usually not going to mock out primitive datatypes in unit tests. The example above was tested with arquillian.

But your are right: for readability reasons it might be better to use default visibility for all injected fields. Regardless whether they are other class instances or (semi) primitives.

thanks!,

adam

Posted by Adam Bien on September 08, 2011 at 03:41 PM CEST #

To all that try to use this: Don't forget (as I did) to add a beans.xml in your WEB-INF otherwise the @Inject will be ignored. And it may take a while to find the cause...

Ivar

Posted by Ivar on September 08, 2011 at 05:13 PM CEST #

Hi Adam,

Some thoughts and additions:
http://blog.eisele.net/2011/09/configure-java-ee-applications-or.html

Posted by Markus on September 09, 2011 at 12:15 AM CEST #

Hi adam,

i like(d) the idea very much when i first heard it at a JAX. the problems i see:

1) not refactoring-safe: if the class fields are renamed, configuration does not work. if configuration will work is only checked at runtime - and of course only if the bean is used.

2) what about configuration values that semantically belong to each other and need dependant validation checking? do this in the configuration-used-class? repeat these checks in other classes that use the same (sub)set of configuration values? do this in the configuration-bean...?

3) did you do performance tests? :) whats the impact on using injection on many fields? noticable?

manuel.

Posted by Manuel Hartl on September 10, 2011 at 04:45 AM CEST #

@Manuel,

"1) not refactoring-safe: if the class fields are renamed, configuration does not work. if configuration will work is only checked at runtime - and of course only if the bean is used."

You could introduce your own,"usual" annotation to name your field independently. Then refactoring will work. However: I prefer the Convention over Configuration approach.

"2) what about configuration values that semantically belong to each other and need dependant validation checking? do this in the configuration-used-class? repeat these checks in other classes that use the same (sub)set of configuration values? do this in the configuration-bean...?"

A custom annotation could provide you whatever meaning you need.

"3) did you do performance tests? :) whats the impact on using injection on many fields? noticeable?"

I think the startup will be a few milliseconds slower :-).

For @RequestScoped managed beans there could be a performance impact. There should be no difference for EJBs.

Take a look at x-ray - it comes with more complete implementation of configuration: http://java.net/projects/x-ray

thanks for your comments!,

adam

Posted by Adam Bien on September 10, 2011 at 02:29 PM CEST #

I boggle at your whole concept. Externally managed configuration should better get kept at a central place (as your Configuration class) and not scattered all over classes throwing primitive values all around.

If I wanted to end up with this result by all means, I'd rather create my own annotation (eg. @ExternalConfig) and an aspectj interceptor with about 3 lines of code to read and throw the values there. This would result in less magic and make the whole concept more explicit than exploiting @Inject for this.

Still, I would much rather go with good object-oriented behaviour as otherwise people may end up thinking this is actually good practice..

Posted by Kristof Jozsa on January 01, 2012 at 11:00 PM CET #

Adam, did you receive my comment from a couple of days ago?

Posted by Kristof Jozsa on January 04, 2012 at 10:02 PM CET #

Hi Adam,

after reading your excellent book, I decide to change the way I manage application configuration. Now i'm trying to implement a configuration provider that retrieves configuration properties from a database table, but I've some problems with injection. I've defined a Configurator class as a @Singleton @Startup bean and a ConfigurationProvider implemented as a @Stateless session bean that access the database trough a JPA EntityManager, but this approach doesn't work at all. Do you have any suggestion on how to implement such a configuration provider? Thanks a lot

Posted by Patrizio on November 22, 2013 at 05:08 PM CET #

Hi Adam,
I wish to test your tutorial code downloading it, but, I don't know which projet on
http://java.net/projects/x-ray
correspond to it ?

Posted by WAH Ndjoman on July 08, 2014 at 08:38 AM CEST #

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