Implementing Seam style @Logger injection with Spring

Seam provides a number of features to help programmers with the tedious but necessary logging. One of them is the @Logger annotation that is used to inject a Seam Log instance into a Seam component. For example instead of writing:

private Log log = LogFactory.getLog(MyClass.class);

you can write:

@Logger private Log log;

and Seam will inject an appropriate logger. Below we will try to to implement this feature using the Spring Framework for objects managed by the Spring DI container (actually a BeanFactory).

The Spring DI container provides a number of extension interfaces that beans can implement to get callbacks from the container in various stages of the container operation. One callback interface is the BeanPostProcessor. BeanPostProcessors are called before and after the initialization of each bean and allow the custom modification of bean instances (for example wrapping an instance with a dynamic proxy).

The only thing we have to do to implement the @Logger injection (besides defining a @Logger annotation) is to write a BeanPostProcessor that, before each bean gets initialized (right after it gets constructed), will iterate over the fields of the bean to detect any @Logger annotations and construct and inject a new logger instance.

Let’s define the annotation:

package com.tzavellas.spring.logger;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target(FIELD)
@Documented
public @interface Logger { }

and now the BeanPostProcessor:

package com.tzavellas.spring.logger;

import java.lang.reflect.Field;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.util.ReflectionUtils;

import static org.springframework.util.ReflectionUtils.FieldCallback;

public class LoggerPostProcessor implements BeanPostProcessor {

  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    return bean;
  }

  public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
    ReflectionUtils.doWithFields(bean.getClass(), new FieldCallback() {
      public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
        if (field.getAnnotation(Logger.class) != null) {
          Log log = LogFactory.getLog(bean.getClass());
          field.set(bean, log);
        }
      }
    });
    return bean;
  }
}

Below I have a small JUnit test to verify that it works:

package com.tzavellas.spring.logger;

import static org.junit.Assert.*;

import org.apache.commons.logging.Log;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;

public class LoggerPostProcessorTest {

  DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

  @Before
  public void setupFactory() {
    RootBeanDefinition bean = new RootBeanDefinition(Bean.class, true);
    factory.addBeanPostProcessor(new LoggerPostProcessor());
    factory.registerBeanDefinition("bean", bean);
  }

  @Test
  public void injectLogger() {
    Bean b = (Bean) factory.getBean("bean");
    assertNotNull(b.log);
    b.doSomething();
  }
}

class Bean {

  @Logger Log log;

  public void doSomething() {
    log.debug("message");
  }
}

This is a very simple implementation since the goal of this article is to demonstrate the extensibility of the Spring DI container and not to implement a complete solution. One limitation is that this implementation only injects loggers (actually commons-logging Logs) to public fields (Seam can inject Seam Logger to private fields).

To use the above in a Spring XML file you simply define a bean with class com.tzavellas.spring.logging.LoggerPostProcessor (the id/name is not needed). The BeanFactory/ApplicationContext will automatically detect all beans that implement the BeanPostProcessor interface at startup time and will initialize them and then call them every time a bean gets initialized.

New features in Spring IDE 2.0M3

Spring IDE 2.0M3 was released and the springframework.org site writes about the long-awaited Spring Webflow support. Spring IDE now includes graphical and XML editors for Spring WebFlow.

I believe that this major new feature hides 3 very important new features that IMHO programmers will find more useful, since people working with Spring spend more time editing Spring XML files than WebFlow XML files.

New Spring 2.0M3 features for Spring XML

  • Spring IDE now integrates with class reference search (Shift+Ctrl+G). This means that the results of class reference search now also include Spring beans.
  • The XML bean editor now supports renaming of bean ids (Refactor -> Rename bean element, or Alt+Shift+R)
  • Spring IDE now participates in class refactorings (class rename, class move and property rename).

See the changelog of the 2.0M3 release for more information about changes and new features.

I am using the Spring IDE 2.0 milestones from the development update site and I am very satisfied with all the new features. The Spring IDE team is doing a great job (thanks guys) and I believe that the 2.0 release is going to be a huge step forward.

Using java.util.Date values in Spring bean definitions

In a Spring bean definition you can set value properties to a bean by using the value attribute in the property element. For example below I set the value of the firstName property of a bean with id spiros of type com.tzavelas.beans.Person to Spiros.

<bean id="spiros" class="com.tzavellas.beans.Person">
  <property name="firstName" value="Spiros"/>
</bean>

In Spring XML, by default, you can only set string and number values in bean properties. Now, what happens when the Javabean, you want to configure, has a value property that is of type java.util.Date?

Spring provides an extensible way to set any arbitrary object value to a bean property. This is done with a Javabean standard mechanism called PropertyEditors. PropertyEditors are objects whose purpose is to transform an object’s value to a string and vice versa. These objects implement the java.beans.PropertyEditor interface.

Spring has out of the box implemented some very useful PropertyEditors for common classes, like java.util.Date, java.io.File and others, that can be found in org.springframework.beans.propertyeditors package. To use the above editors in your spring configuration you have to first register them with a CustomEditorConfigurer. CustomEditorConfigurer is a BeanFactoryPostProcessor and runs after the BeanFactory is initialized.

In the below code I have an example where I register a CustomDateEditor that binds java.util.Date values to bean properties. Then I have a bean definition where I set a bean property to a date value.

The Java code for the example Javabean:

package com.tzavellas.beans;

import java.util.Date;

public class Person {

  private Date birthDate;
  private String firstName;

  public Date getBirthDate() {
    return birthDate;
  }
  public void setBirthDate(Date birthDate) {
    this.birthDate = birthDate;
  }
  public String getFirstName() {
    return firstName;
  }
  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }
}

The XML configuration:

<bean id="customEditorConfigurer"
      class="org.springframework.beans.factory.config.CustomEditorConfigurer">
  <property name="customEditors">
    <map>
      <entry key="java.util.Date">
        <bean class="org.springframework.beans.propertyeditors.CustomDateEditor">
          <constructor-arg index="0">
            <bean class="java.text.SimpleDateFormat">
              <constructor-arg value="dd/MM/yyyy"/>
            </bean>
          </constructor-arg>
          <constructor-arg index="1" value="false"/>
        </bean>
      </entry>
    </map>
  </property>
</bean>

<bean id="spiros" class="com.tzavellas.beans.Person">
  <property name="firstName" value="Spiros"/>
  <property name="birthDate" value="15/04/1980"/>
</bean>

As you can see I am passing a java.text.SimpleDateFormat to the constructor of the CustomDateEditor and later in the definition of the bean with id spiros I am setting a date property using the format I specified in the CustomDateEditor.

UPDATE: For the above code to work you have to use an ApplicationContext. A BeanFactory (like XmlBeanFactory) does not work here because BeanFactories do not auto-detect BeanFactoryPostProcessors like the CustomEditorConfigurer used in the above code.

Testing Spring AOP code

In Using the Spring AOP Framework with EJB Components, Eugene Kuleshov presents a really nice way to test Spring AOP configuration code and advices. When you use Spring AOP use can easily test your target objects with unit tests, but how do you test the weaved code?

In the above article Eugene Kuleshov uses unit tests that reference the Spring ApplicationContext that has the AOP configuration code. Then at the setup method of the TestCase class he registers a custom BeanPostProcessor that provides mock implementations for the target objects. At the test methods he trains the mock objects and tests the all the AOP code except the target objects.

I really liked the trick with the custom BeanPostProcessor to provide the mock objects. I’ll probably start using this trick in my tests really soon.

BTW Using the Spring AOP Framework with EJB Components also provides lots of information on how to effectively use Spring in a EJB 2.x environment. If you are maintaining EJB 2.x applications and you want to make your applications more testable over time you should probably read this article.

SpringIDE

If you are developing with the Spring Framework and you use the Eclipse IDE, then you should definitely check out the SpringIDE Eclipse plug-in. This plug-in is a Spring Framework subproject that aims to assist developers with the development of Spring applications.

The main features of SpringIDE are:

  • Spring bean definition editor (with auto-complete support)
  • Graphical view of Spring beans
  • Spring beans Eclipse view
  • Graphical editor for Spring Web-Flow (under development)

See here for a screenshot of the bean definition editor while I am configuring a DispatcherServlet for a new project.

For more information visit the Spring IDE homepage.