Spring FactoryBean-managed wiring: Part 2

I finally succeeded in getting rid of the XML configuration for the Spring container, and managed to wire everything using Spring annotations.
This post will describe what changes I had to make and what issues I experienced when converting the configuration to annotations.

XML vs. Annotations

Different opinions exist about XML configuration or annotations. I won’t go too far in those.
I like annotations because it makes your configuration readable directly in your source code, and you don’t have to go find some configured bean in one of the huge XML files.
On the other hand, configuring a Spring container using XML is much more verbose, but everything can be found in one file – or at least multiple files in one location – and there’s no magic involved. When using annotations, it might seem like dark magic when a bean can’t be injected, just because you forgot to give it a proper name or use the proper qualifier. Also, using separate versions of configuration files and Maven profiles is also only possible using XML.
So, just to tag along with the crowd and new way of thinking, I chose to get rid of the XML completely for this small HelloWorld project and only use Spring annotations to configure the application.
Of course, it depends on the circumstances whether or not you want to use XML or annotations, or even both.

Bye Bye XML

The first thing I did was delete the application-config.xml file. Of course I then had to change the main application class to instantiate the ApplicationContext using the AnnotationConfigApplicationContext.

The new main class now looks like this:

public class FactoryBeanDemo {
    ...
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext("be.stesch");

        HelloWorldService helloWorldService = (HelloWorldService) applicationContext.getBean("helloWorldService");
        LOGGER.debug("Printing {}", helloWorldService.getHelloWorld());
        System.out.println(helloWorldService.getHelloWorld());
    }
    ...
}

Of course, running this application will spawn an Exception immediatly, because when scanning the base-package no Spring configured beans will be found any longer.
You will get the following Exception:

Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'helloWorldService' is defined
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:527)
        ...

So I had to take some more steps to complete the configuration.

Basic Spring annotations

First, I have to declare the service beans that I’m going to use in the FactoryBean to be Spring beans.
To make a Java bean a Spring-managed service bean, you use the @Component or @Service annotation.
You also have several other annotations – called stereotypes – to do the same thing, but they have a slightly different meaning and will be used in different contexts. See the link Classpath scanning and managed components for more information.

  • @Component: a generic stereotype for any Spring-managed component.
  • @Repository: used in the persistence layer to declare a Spring-managed DAO component.
  • @Service: used in the service layer to declare a Spring-managed business service facade.
  • @Controller: used in the presentation layer to declare a Spring-managed controller, for example a web controller.

Then I configure the FactoryBean itself to be able to let it create and instantiate the correct HelloWorldService object.
You have to declare the HelloWorldServiceFactory bean to be a @Component.
Trying basically to convert the XML configuration straight to annotations, I annotated the getObject() method with the @Bean annotation.
What these annotations should do is say: I have a factory-bean HelloWorldServiceFactoryBean which I want to be a Spring-managed bean. It’s purpose it to create another Spring-managed bean of type HelloWorldService by using the factory-method getObject().
You have to pass the name attribute to the @Bean annotation to make sure the returned service instance will be called ‘helloWorldService‘.

@Component
public class HelloWorldServiceFactoryBean implements FactoryBean<HelloWorldService>, ApplicationContextAware {
    ...
    @Override
    @Bean(name = "helloWorldService")
    public HelloWorldService getObject() throws Exception {
        HelloWorldService helloWorldService = null;

        if (ServiceConstants.COMPANY_A.equalsIgnoreCase(serviceType)) {
            LOGGER.debug("Getting bean '{}'", ServiceConstants.COMPANY_A_SERVICE);
            helloWorldService = (HelloWorldService) applicationContext.getBean(ServiceConstants.COMPANY_A_SERVICE);
        } else if (ServiceConstants.COMPANY_B.equalsIgnoreCase(serviceType)) {
            LOGGER.debug("Getting bean '{}'", ServiceConstants.COMPANY_B_SERVICE);
            helloWorldService = (HelloWorldService) applicationContext.getBean(ServiceConstants.COMPANY_B_SERVICE);
        }

        return helloWorldService;
    }
    ...
}

You might think you’re finished now, but running the main application will present you the next Exception.

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'helloWorldService' defined in class path resource [be/stesch/demo/factorybean/HelloWorldServiceFactoryBean.class]: factory-bean 'helloWorldServiceFactoryBean' returned null
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:355)
        ...

It seems a little bit weird that no class of your own application is mentioned in the stacktrace, apart from the main application class. Time to debug the application.
When you put a breakpoint in the getObject() method of the HelloWorldServiceFactoryBean you’ll notice that the serviceType field, that used to come from a properties file, is null. Of course – we forgot to declare a Spring bean for the PropertyPlaceholderConfigurer.

The idea is to get rid of XML completely, and only use annotations. This way, we cannot use XML to declare a PropertyPlaceholderConfigurer spring-bean, the way I did it in part 1. The property value somehow has to get injected in the FactoryBean to be able to use it in the getObject() method.

What I did was creating an ApplicationConfig class that is responsible for creating Spring beans like the PropertyPlaceHolderConfigurer. I got my inspiration from a DZone Javalobby article: Spring and Hibernate application with zero XML.
The ApplicationConfig class has to be annotated with @Component, and the method creating the PropertyPlaceHolderConfigurer gets the @Bean annotation indicating that it will create a Spring-managed bean. Previously the @Bean and also @Configuration annotations were part of the JavaConfig project. As of version 3.0, JavaConfig got migrated into the core Spring framework.

This is the ApplicationConfig class and the getPropertyPlaceholderConfigurer() method:

@Component
public class ApplicationConfig {
    @Bean
    public PropertyPlaceholderConfigurer getPropertyPlaceholderConfigurer() {
        PropertyPlaceholderConfigurer propertyPlaceholderConfigurer = new PropertyPlaceholderConfigurer();
        propertyPlaceholderConfigurer.setLocation(new ClassPathResource("application-config.properties"));

        return propertyPlaceholderConfigurer;
    }
}

Then I inject the ‘service_type‘ property value into the HelloWorldServiceFactoryBean‘s serviceType field using the @Value annotation.
I also found that way of injecting properties in the Spring and Hibernate DZone article mentioned above.

@Component
public class HelloWorldServiceFactoryBean implements FactoryBean<HelloWorldService>, ApplicationContextAware {
    ...
    @Value("${service_type}")
    private String serviceType;
    ...
}

All Spring beans previously configured in XML are now configured by annotations.
Everything is annotated the way I configured it in XML and the way I thought the configuration should work.

And then the truth came out!

More code change necessary!

I got a very weird Exception that I did not expect to see:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'helloWorldService' defined in class path resource [be/stesch/demo/factorybean/HelloWorldServiceFactoryBean.class]: No matching factory method found: factory bean 'helloWorldServiceFactoryBean'; factory method 'getObject()'. Check that a method with the specified name exists and that it is non-static.
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:528)
    ...

The factory-method getObject() is not found in the declared FactoryBean. What the …?
It really is there, it exists.
The method returns a HelloWorldService instance, it exists in the HelloWorldServiceFactoryBean which is annotated with the @Component annotation and is thus Spring-managed, and the method itself is annotated with the @Bean annotation and thus should create the ‘helloWorldService‘ Spring-managed bean.
I was completely baffeled, and it took me a while to scourge around the Internet searching for people with the same problem and some solutions.

I did not find the exact same problem, but I came up with a solution using some examples I’ve found on the Internet.
I used the same ApplicationConfig class where I created the PropertyPlaceholderConfigurer to also create the HelloWorldService.
To do this, I’ll have to access the HelloWorldServiceBeanFactory‘s getObject() method and return the created instance as a Spring-managed bean. To be able to get the FactoryBean, I’ll need access to the ApplicationContext. I made the ApplicationConfig class implement ApplicationContextAware so that the ApplicationContext would be injected into the ApplicationConfig class.

This is the source code:

@Component
public class ApplicationConfig implements ApplicationContextAware {
    private ApplicationContext applicationContext;

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    ...

    @Bean(name = "helloWorldService")
    public HelloWorldService getHelloWorldService() throws Exception {
        HelloWorldService helloWorldService = applicationContext.getBean(HelloWorldServiceFactoryBean.class)
                .getObject();
        return helloWorldService;
    }
}

Also, do not forget to remove the @Bean annotation from the getObject() factory-method in the FactoryBean. Otherwise the same Exception will keep occuring and the application won’t work.

When you run the application now, you’ll see that the correct HelloWorldService instance is created – depending on the ‘service_type‘ property value, and that the application works correctly.

Why annotating the same getObject() factory-method with the @Bean annotation as it was configured in XML doesn’t work, I do not know.
In XML you have to prefix the factory-bean attribute value with an &amp; but I did not find any possibity to do so with annotations.
Why doing the same thing with more or less the same code from another class does work, I do not know either.
But perhaps, someone else might find the solution to a problem like this thanks to my blog post.

If anyone knows and cares to explain the why’s and how’s about this issue, or has other opinions about the solution, please be so kind to post your comments underneath this blog post.


Conclusion

As a conclusion, I can say that it is possible to get rid of the XML entirely. The whole Spring container can be configured by annotating your classes and annotating methods that create beans.
What I had hoped was that I could just use the source code of my previous post about the XML configuration and annotate the existing code.
But that wasn’t completely the case. I had to write some extra code to create a PropertyPlaceholderConfigurer to be able to inject property values in other Spring-managed beans. I also had to move the factory-method – or at least the annotation that I thought would mark getObject() as a factory-method – to another class so there too extra code had to be written.
Of course the changes were minimal, but still they had to be done.

All in all, I learned something about Spring configuration with annotations and I’m eager to read your comments and gain some more knowledge about the subject.

Again, you can find the complete source code and Maven POM file in my Public DropBox folder: http://dl.dropbox.com/u/33979885/Blog%20Source%20Code/factorybean-annotation-demo.zip

Spring FactoryBean-managed wiring

For my first post I’ll cover a client’s request on one of my projects, and how I was able to implement it.
First I’ll explain some background information as to how I got to the subject, and I’ll then explain the technicalities with some example code.

Background information

I had to migrate a project’s security mechanism from a LDAP directory to a user DAO.
Application security was configured with Acegi Security for Spring. The project’s POM file specified Acegi Security 1.0.3 and the Spring Framework 1.2.8.

The configuration of the user DAO security strategy was finished quite quickly after some research on the subject. But the client had an extra request.
For one departmental agency that used the application, the new DAO security strategy has to be used. For another departmental agency, a separately configured LDAP directory still had to be used.
Other configuration logic in the application was already based on a property key ‘location‘ which specified the departmental agency that the application had to be configured for. The client wanted to use the same property key to determine the security configuration.

I had to use the existing Acegi Security ProviderManager configuration that had a list of AuthenticationProviders and had to add the correct AuthenticationProvider for the specified departmental agency.

I wanted to find a solution for dynamically creating a Spring bean and wiring it inside the ProviderManager. Thanks to a colleague of mine, I got myself directed to the FactoryBean feature of Spring.

Hello FactoryBean!

Of course I won’t handle the exact configuration and details I used on the project itself, but i’ll explain the details using a HelloWorld-style example.

What is FactoryBean and what is it meant for? As quoted from the Spring Framework 3.0 reference:

You implement the org.springframework.beans.factory.FactoryBean interface for objects that are themselves factories.

The FactoryBean interface is a point of pluggability into the Spring IoC container’s instantiation logic. If you have complex initialization code that is better expressed in Java as opposed to a (potentially) verbose amount of XML, you can create your own FactoryBean, write the complex initialization inside that class, and then plug your custom FactoryBean into the container.

Imagine:
You have a HelloWorld application for two companies.
The two companies run exactly the same application, both on separate servers. You only want to maintain the application once, and want to be able to change the configuration at deployment time using a properties file. You can use Maven profiles to select the properties file for company A, or the properties file for company B. You would be able to use Maven profiles for all other Spring configuration files too, but when the configuration changes for all companies you’ll have to modify all the XML files instead of just one.
You want to use only one Spring ApplicationContext XML file for the entire Spring Container configuration. You don’t want to have to maintain separate files for every different company.

This is where the FactoryBean comes in.
You can let the FactoryBean create or instantiate a specific implementation of a Bean and return it to inject it into another Bean that will use it as a dependency.

Implementation

I have two services, HelloWorldServiceCompanyAImpl and HelloWorldServiceCompanyBImpl.

public class HelloWorldServiceCompanyAImpl implements HelloWorldService {
    @Override
    public String getHelloWorld() {
        return "Hello Company A!";
    }
}
public class HelloWorldServiceCompanyBImpl implements HelloWorldService {
    @Override
    public String getHelloWorld() {
        return "Hello Company B!";
    }
}

I have a properties file containing the property on which is decided what service implementation will be wired when running the application.

# 'company_a' for the HelloWorldServiceCompanyAImpl
# 'company_b' for the HelloWorldServiceCompanyBImpl
service_type=company_a

At the moment I use XML for configuring the Spring container.
In the FactoryBean, I want to be able to get the two pre-configured Spring beans from the Spring ApplicationContext. Normally you could instantiate the Java beans yourself by just using the new operator, but in my client’s case I had to use a pre-configured LdapAuthenticationProvider or DaoAuthenticationProvider. Constructing and configuring them in code wasn’t the way I wanted to go.

I implemented a FactoryBean that is also ApplicationContextAware. This way, the ApplicationContext will be available in the BeanFactory’s implementation, provided you generated the necessary getter and setter for the ApplicationContext instance. From this ApplicationContext instance, I retrieve the service beans in the FactoryBean getObject() method.
Both service beans are plain simple Spring beans with no complex XML configuration or anything special.

This is the relevant code for instantiating or getting the correct service bean in the FactoryBean:

public class HelloWorldServiceFactoryBean implements FactoryBean<HelloWorldService>, ApplicationContextAware {
    private static final Logger LOGGER = LoggerFactory.getLogger(HelloWorldServiceFactoryBean.class);
    private ApplicationContext applicationContext;
    private String serviceType;
    ...
    @Override
    public HelloWorldService getObject() throws Exception {
        HelloWorldService helloWorldService = null;

        if (ServiceConstants.COMPANY_A.equalsIgnoreCase(serviceType)) {
            LOGGER.debug("Getting bean '{}'", ServiceConstants.COMPANY_A_SERVICE);
            helloWorldService = (HelloWorldService) applicationContext.getBean(ServiceConstants.COMPANY_A_SERVICE);
        } else if (ServiceConstants.COMPANY_B.equalsIgnoreCase(serviceType)) {
            LOGGER.debug("Getting bean '{}'", ServiceConstants.COMPANY_B_SERVICE);
            helloWorldService = (HelloWorldService) applicationContext.getBean(ServiceConstants.COMPANY_B_SERVICE);
        }

        return helloWorldService;
    }
    ....
}

The FactoryBean is configured like this:

    ...
   <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:application-config.properties" />
    </bean>

    <bean id="helloWorldServiceFactory"
        class="be.stesch.demo.factorybean.HelloWorldServiceFactoryBean">
        <property name="serviceType" value="${service_type}" />
    </bean>
    ...

The HelloWorldService bean is configured in the ApplicationContext XML without specifying the class attribute. I don’t want Spring itself to instantiate the bean, but I want to use a FactoryBean to do so. This requires some special configuration.
When you just enter the FactoryBean’s bean id for the factory-bean attribute, the factory-method will not be found. This is because the factory-method will be searched in the bean that is created by the FactoryBean – in this case, the HelloWorldService. To refer to the FactoryBean itself, the bean id must be prefixed by an &, or more specifically an &amp; in the XML file itself.

When you need to ask a container for an actual FactoryBean instance itself, not the bean it produces, you preface the bean id with the ampersand symbol & (without quotes) when calling the getBean() method of the ApplicationContext. So for a given FactoryBean with an id of myBean, invoking getBean("myBean") on the container returns the product of the FactoryBean, and invoking getBean("&myBean") returns the FactoryBean instance itself.

This leads us to the following HelloWorldService bean configuration:

    ...
    <bean id="helloWorldService" factory-bean="&amp;helloWorldServiceFactory"
        factory-method="getObject" />
    ...

In my Main class, I get the HelloWorldService instance from the ApplicationContext and print out it’s message.
Depending on the ‘service_type‘ property in the application-config properties file, it will print out ‘Hello Company A!’ or ‘Hello Company B!’.

public class FactoryBeanDemo {
    ...
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-context.xml");

        HelloWorldService helloWorldService = (HelloWorldService) applicationContext.getBean("helloWorldService");
        LOGGER.debug("Printing {}", helloWorldService.getHelloWorld());
        System.out.println(helloWorldService.getHelloWorld());
    }
    ...
}

You can find the complete source code, including the Maven POM file in my DropBox public folder, on the following link: http://dl.dropbox.com/u/33979885/Blog%20Source%20Code/factorybean-xml-demo.zip


In the next part, I hope to be able to get rid of all the XML configuration, and configure the Spring container using annotations.
I tried to do so already, but I got an Exception when running the application. I also got it using XML for configuration, but there it got resolved by prefixing the FactoryBean with &amp;.
As far as I can tell from the @Bean javadoc, the same thing should happen automatically when annotating the getObject() method.

The @Bean annotation may be used on any methods in an @Component class, in which case they will get processed in a configuration class ‘lite’ mode where they will simply be called as plain factory methods from the container (similar to factory-method declarations in XML). The containing component classes remain unmodified in this case, and there are no unusual constraints for factory methods.

I get the following Exception:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'createHelloWorldService' defined in class path resource [be/stesch/demo/factorybean/HelloWorldServiceFactoryBean.class]: No matching factory method found: factory bean 'helloWorldServiceFactoryBean'; factory method 'createHelloWorldService()'. Check that a method with the specified name exists and that it is non-static.
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:528)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:983)

If anyone would know a solution to this, please be so kind to post your comments to this topic.
I’ll try to describe it further in the next part.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: