Spring hand in hand with Swing Application Framework

Starting work on a new application is always a fun period. You get to choose all your frameworks from scratch and you are not limited by any previous mistakes (or decisions, as some call them). For this particular project I had to come up with an architecture that would support a graphical interface, easy configuration and potentially swapping components in and out.

The configuration requirement and the need to be able to swap components naturally made me choose Spring. Using dependency injection and Spring’s easy PropertyPlaceholderConfigurer, these requirements are easily met.

For the interface, I decided to give the Swing Application Framework (JSR 296) a go. The Swing Application Framework (SWAF from now on) is an attempt at making life with Swing a lot easier. It provides the developer with an application lifecycle, easy component configuration, simplified long-running tasks and many more simplifications. The reference implementation can be found at https://appframework.dev.java.net/.

After studying the SWAF API and setting up an simple PoC, I decided to put it all in a Spring context. That’s where the two frameworks did not really get along with each other. The problem lies within the creation of your Application object. Each SWAF application needs to create one class that extends Application and fills in the lifecycle methods. This class is then instantiated by the SWAF framework:

import org.jdesktop.application.Application;

public class TestApplication extends Application
{
  /**
   * Start the application
   */
  public static void main(String[] args)
  {
    Application.launch(TestApplication.class, args);
  }
}

If you know Spring, you also know Spring does not like beans that are created outside of its application context. In order for Spring to play nice with anything created outside the XML bean definition, you have to use @Configurable. The @Configurable annotation allows Spring to meddle in the construction of the object, whenever it happens. For this to work, you need a couple of things:

  1. the bean definition must have the property scope="prototype"
  2. the Application class must be annotated by @Configurable
  3. Spring needs to know that it has to be aware of @Configurable beans. This is done by adding <context:spring-configured/> to your context file
  4. you need to enable either load-time weaving (LTW) or compile time weaving

 

Bean scope

The Application object will be instantiated by SWAF, but you want to configure it in the application context XML file. So you need to tell Spring not to create this bean when it initializes the context. The scope="prototype" property of a bean will ensure this, while you can still define properties and references for the object. The following XML snippet shows a ‘normal’ bean configured as a prototype:

<beans ...>

  <bean name="myApplication" scope="prototype" class="nl.jhk.test.application.MyApplication">
    <property name="windowTitle" value="My Demo Application"/>
    <property name="uiComponents">
      <set value-type="nl.jhk.test.application.ui.ConfigurableComponent">
        <ref bean="loginPanel"/>
        <ref bean="welcomePanel"/>
        <ref bean="mainWindow"/>
      </set>
    </property>
  </bean>

</beans>

 

Adding @Configurable to the Application class

This annotation can be put on any class and is effectively used to make that class’ constructors part of a pointcut. A pointcut is a set of code points where aspects can be woven in. If you have no idea what an aspect is, I suggest you take a look at the Wikipedia page for it. In one sentence: an aspect allows you to add behavior before and after any method without structurally changing the class’ source.

 

Enabling @Configurable

Normally, Spring does not look outside its XML file(s) for beans it has to configure. For most applications that is just fine. For those applications that either need control over bean creation, or have no control over it and hence cannot pass the control to Spring, @Configurable comes to the rescue.

In order for @Configurable to work, you must tell Spring that there are beans in the application that it won’t create, but which it must configure. This is done by adding the <context:spring-configured/> tag to your XML file. The sample below also includes the namespace definition for context:, the other namespaces have been omitted.

<beans  ...
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="...
      http://www.springframework.org/schema/context 
      http://www.springframework.org/schema/context/spring-context-2.5.xsd">

  <context:spring-configured/>

</beans>
Posted in Spring.