Skip to main content

FxContainer - IoC container written in JavaFX, for JavaFX applications

Posted by srikanth on August 21, 2010 at 11:38 AM PDT

NOTE: A  slidedeck with 20 slides of "How To" JavaFX Dependency Injection with FxContainer is available here.  

The world is already filled with dozens of IoC containers. Do we need another one? That is the question I pondered a lot before setting out to write a DI/IoC container in JavaFX. I will briefly cover the facts that necessitated writing one and then show how to use it.

Constructor Injection or Setter Injection?

All IoC containers provide two type of dependency injection - constructor injection and setter injection. Constructor injection is technically impossible as the JavaFX language does not support overloaded constructors. While setter injection is possible, it does seem very artificial in JavaFX. JavaFX instance variables are typically declared as public or public-init etc. This means the initialization of these variable is typically as follows:

var finder = MovieFinder {
  movieDao: MovieDao { }
}

A MovieDao is provided when the MovieFinder is initialized. Notice that this falls under neither constructor injection nor setter injection. Due to lack of a name, I call it Init Injection. If we were to use Spring to inject the Dao into the MovieFinder, then the MovieFinder class should look like this:

public class MovieFinder {
  public-init movieDao:MovieDao;

  public function setMovieDao(dao:MovieDao) {
    this.movieDao = dao;
  }
}

Writing setters method for instance variables that are public-init seems very artificial. If somehow, we could inject the dao using the init, it would be ideal.

Basics of JavaFX Init Injection

The code snippet below captures this idea of Init-Injection using JavaFX reflection:

FXLocal.Context ctx = FXLocal.getContext();
FXClassType clzType = ctx.findClass("org.fxobjects.MovieFinder"); //get the class
FXObjectValue objValue = clzType.allocate(); //allocate memory for the class-instance
FXVarMember varMember = clzType.getVariable("movieDao"); //get the variable-type
FXValue varValue = ctx.mirrorOf(Some String or object); //create the variable-value
objValue.initVar(varMember, varValue); //initialize the variable-type in class-instance with the variable-value
//do more initVar as needed
objValue.initialize(); //Finally initialize the object

This is exactly the core idea behind the dependency injection in FxContainer (but on a much larger scale and internally complex to address real world problems)

NOTE: There is another additional side effect of setter injection that is covered in detail in this post - http://weblogs.java.net/blog/srikanth/archive/2010/06/12/wiring-javafx-objects-spring-tread-caution

Guice and Spring

Two of the most popular IoC containers are Guice and Spring. Spring supports both annotations and XML based configuration. Guice supports annotation and programmatic binding configuration and a mixture of both. Guice is most productive by combining annotations, generics and sprinkled with programmatic binding as needed. Unfortunately JavaFX supports neither annotations nor generics and this is a big disadvantage. This essentially means we are down to Spring. In addition to shortcomings of Spring (in the context of JavaFX) listed earlier, Spring jars add up (spring-core, spring-beans + spring-context + commons) and the size of spring jars alone exceeds 1MB at minimum.  It is not bad if your application is a huge one and is regularly used (and hence cached) by users. How about if you could get most benefits of Spring XML-like features of Dependency Injection with a footprint less than 75 K and in a style natural to JavaFX. Well that’s FxContainer for you !!

What is FxContainer?

FxContainer small footprint IoC container that is xml driven. [For those that cry of death by xml, you could really organize the xml into different logical files and mitigate the issue quite well.]

FxContainer 1.0 can be downloaded from the project site - https://fxobjects.dev.java.net

SVN is located here - https://fxobjects.dev.java.net/source/browse/fxobjects/

FxObjects is the umbrella project that encompasses several related but cohesive JavaFX frameworks with the single goal of making enterprise JavaFX development easy. FxObjects enables methodical, pattern based and test friendly way of developing JavaFX applications based on ideas and best practices distilled from real life usage. For those interested in seeing FxObjects and FxContainer ease JavaFX application development, here is a big picture: (Only few components are ready. There is more work to do. Anybody interested in contributing?)

FxObjects Architecture Roadmap

A whirlwind tour of FxContainer

If you are familiar with Spring, you will feel right at home with FxContainer. I will use simple examples to illustrate the features. Listing below shows the wiring of objects. (This is a subset of a large sample shipped with the framework) Both Java and JavaFX objects can be mixed. A JavaFX object can hold reference to Java and JavaFX objects and primitives. A Java object can hold reference to a JavaFX object via interface.

Simple Dependency Injection

<fxcontainer>
    <fxobject name="movieFinder" class="org.fxobjects.samples.fxcontainer.MovieFinderImpl">
        <property name="someVar" value="Some random value"/>
        <property name="javaHelper" ref="javaHelperObj"/>
        <property name="jfxHelper" ref="jfxHelperVarObj"/>
    </fxobject>
    <fxobject name="movieLister" class="org.fxobjects.samples.fxcontainer.MovieLister">
        <property name="finder" ref="movieFinder"/>
    </fxobject>
</fxcontainer>

Import XMLs and Properties, Pattern Substitutions

Large xmls can be split into logical xml files and “imported” into another. Properties can also be imported in a similar way and substituted in Spring style for ${ } placeholders

<fxcontainer>
    <import resource="/org/fxobjects/samples/abc.xml"/>
    <import resource="/org/fxobjects/samples/server.properties"/>
    <fxobject name="movieFinder" class="org.fxobjects.samples.fxcontainer.MovieFinderImpl">
        <property name="someVar" value="${propKey1} has a ${propKey2} "/>
    </fxobject>
</fxcontainer>

Wired Object Lifecycle - Singleton, Lazy-Init, Init-Method etc.

All wired objects are singletons by default. Similarly all object initializations are lazy by default and loaded only when the object or the containing object graph is requested. Both of these can be overridden. An init-method can be called after FxContainer finishes wiring the object. Listing below shows all three characteristics. In addition an optional feature called load-order is shown. Load-order is applicable only to eager initialized (i.e. lazy-init = false) objects and determines the order in which object is initialized. Lesser the number, earlier the initialization

<fxcontainer>
    <fxobject name="movieFinder" class="org.fxobjects.samples.fxcontainer.MovieFinderImpl"
             init-method="someMethod" lazy-init="false" singleton="false" load-order="0">
     …
    </fxobject>
</fxcontainer>

Collections, Sequence, Map Support

Collections are supported too. In addition to the usual list, set, map, a JavaFX specific sequence is also supported !. While sequence can be defined only inside a JavaFX parent, others can be defined in Java or JavaFX. Listing below shows a condensed example of all these.

<fxcontainer>
    <fxobject name="jfxHelperVarObj" class="org.fxobjects.samples.fxcontainer.MovieFinderJFXHelper">
        <property name="movieNames">
            <sequence>
                <entry value="Terminator" />
                <entry value="Terminator 2" />
            </sequence>
        </property>
        <property name="movies">
            <sequence>
                <entry ref="${movie1Ref}"/>
                <entry ref="movie2"/>
            </sequence>
        </property>
        <property name="movieList">
            <list>
                <entry ref="movie1"/>
                <entry ref="movie2"/>
            </list>
        </property>
    </fxobject>
</fxcontainer>

Advanced features in Collections support

Below is an example of some advanced features in collection support. Notice the usage of valueClass attribute. If you are using a primitive list within a JavaFX object or primitive list in Java object without parameterizing (i.e. without Generics), the container needs a way to figure out the type of the property. Similar scenario exists for Map. If the objects are of ref types, then these keyClass and valueClass are not needed.

<fxcontainer>
    <fxobject name="jfxHelperVarObj" class="org.fxobjects.samples.fxcontainer.MovieFinderJFXHelper">
        <property name="integerList">
            <list valueClass="Integer">
                <entry value="2"/>
                <entry value="5"/>
            </list>
        </property>
        <property name="codeMap">
            <map keyClass="java.lang.String" valueClass="java.lang.Integer">
                <entry key="mov1" value="1"/>
                <entry key="mov2" value="2"/>
            </map>
        </property>
        <property name="movieMap">
            <map keyClass="java.lang.String">
                <entry key="mov1" valueRef="movie1"/>
                <entry key="mov2" valueRef="movie2"/>
            </map>
        </property>
    </fxobject>
</fxcontainer>

Final word

In developing FxContainer, my main motive was to create that DI container that was easy to use, small footprint and feels natural to JavaFX style of programming all at the same time.

If you have any ideas for improvement or questions, concerns, comments – you are most welcome to post to the project forum website - https://fxobjects.dev.java.net/servlets/ProjectForumView

I’d recommend you also check out FxObjects and see if it helps you uncomplicate enterprise JavaFX application development. Inspite of the 0.1 release, it is very stable, feature rich and makes JavaFX application development fun.

You know, JavaFX isn’t just about jazzy interfaces. It is about elegant programs that are beautiful inside-out. FxObjects and FxContainer are a step towards that.