Monday, November 19, 2007

Spring bean configuration validation

If you enthousiastically use Spring like me and dutifully inject every dependency in your beans with Spring's XML configuration, you have probably encountered the situation that you forgot to inject a property and received a NullPointerException from an unexpected place in your code. Wouldn't it be nice to check the configuration of your bean after it is instantiated? Your bean could implement the InitializingBean interface, which would cause the Spring application context to call the afterPropertiesSet method after your bean is instantiated and injected with dependencies. This would make your bean directly dependent on Spring and you probably would not want that.

Attribute "init-method"

A better solution is to call a method of your bean that validates its own configuration with the "init-method" attribute of the bean element in the application context XML:
<bean id="bean1" class="net.kazed.spring.config.validator.ExampleBean1" init-method="validateConfiguration">
 <property name="bean2" ref="bean2"/>
 <property name="bean3" ref="bean3"/>
</bean>
public void validateConfiguration() {
 DependencyAssert.notNull(bean2, "bean2");
 DependencyAssert.notNull(bean3, "bean3");
}
The Spring container will call the "validateConfiguration" method after your bean, in which you can check if all required dependencies are injected. The only thing is that you should not forget to add the "init-method" attribute.

BeanPostProcessor

Since our goal was to catch configuration mistakes, this solution just is not good enough. Fortunately, you can create a post-processor for the Spring container that will examine every created bean after instantiation and dependency injection. By implementing a BeanPostProcessor, you can invoke the validateConfiguration method. To make it nice and intuitive, we can create an interface ValidatableConfiguration with the validateConfiguration method. Interface:
public interface ValidatableConfiguration {
/**
 * Validate the configuration of the object.
 */
void validateConfiguration();
}
ValidatingBeanProcessor:
public class ValidatingBeanProcessor implements BeanPostProcessor {
  public Object postProcessBeforeInitialization(Object bean, String beanName)
   throws BeansException {
   return bean;
  }

  public Object postProcessAfterInitialization(Object bean, String beanName)
   throws BeansException {
   if (bean instanceof ValidatableConfiguration) {
     try {
       ((ValidatableConfiguration) bean).validateConfiguration();
     } catch (DependencyNullException e) {
       throw new ConfigurationValidationException("Configuration of bean '" + beanName
         + "' failed - " + e.getMessage(), e);
     }
   }
   return bean;
  }
}
We just declare the ValidatingBeanProcessor once in the application context, and the container will use it for every created bean:
<bean id="beanValidator" class="net.kazed.spring.config.validator.ValidatingBeanProcessor">
The nice thing is that we only have to make the bean implement the ValidatableConfiguration interface and it will automatically be used to validate the bean whenever you declare it in the application context. Advantages:
  • Intuitive design - implement interface and it will be validated
  • No special configuration (except from the one ValidatingBeanProcessor)
  • Validation is done only once and during instantiation of the application context - it will fail early
  • Error message is descriptive - no more puzzling NullPointerException

Constructor injection

Traditionally, the Spring team favored setter injection because of more readable configuration. Spring has always also supported constructor injection and recently this has received more attention in the Spring community (see Alef's blog). Constructor injection makes validation incredibly simple: just validate in the constructor.
public ExampleBean1(ExampleBean2 bean2, ExampleBean3 bean3) {
 super();
 DependencyAssert.notNull(bean2, "bean2");
 DependencyAssert.notNull(bean3, "bean3");
 this.bean2 = bean2;
 this.bean3 = bean3;
}
<bean id="bean1c" class="net.kazed.spring.config.validator.ExampleBean1">
 <constructor-arg ref="bean2"/>
 <constructor-arg ref="bean3"/>
</bean>
As you can see, constructor injection is a bit harder to read because the arguments are nameless and depend on the order.

Conclusion

I would prefer to use constructor injection and use (or combine with) setter injection if some dependencies are optional. The BeanPostProcessor is very useful because it is non-obtrusive and automatically validates the configuration of a bean when it implements an interface that you define yourself and can be a logical part of your domain model. Retrieve here the source code of these examples.