SyntaxHighlighter

Wednesday, May 9, 2012

Custom PropertySource in Spring 3.1 - Part 3

This post is the third in a series of posts showing examples of registering a custom property source in Spring 3.1, where the property source requires non-trivial initialization of its own. Part 1 showed initialization of a stand-alone application, and Part 2 showed initialization of integration tests. This part will show how to initialize a custom property source in a Spring MVC web application.

Spring 3.1 introduced a very convenient hook for customizing the application context in a Spring web application - the ApplicationContextInitializer interface. An ApplicationContextInitializer can be used to set active profiles and register custom property sources, among other things.

Here is an example of an ApplicationContextInitializer that registers the RedisPropertySource introduced in Part 1.


Just like in the stand-alone example from Part 1, an ApplicationContext is created and initialized in order to wire up the components of the custom property source. This example uses the same property-source-context.xml configuration file from Part 1.

The ApplicationContextInitializer is registered with the Spring MVC servlet by adding a stanza to the web.xml file like this:


An alternative to adding the context-param stanza to web.xml is to implement a WebApplicationInitializer and add the ApplicationContextInitializer programmatically.


The JavaDoc for WebApplicationInitializer is a great source of documentation on programmatically configuring the servlet context. In this example, most of the servlet context configuration is in web.xml, showing that the two approaches can be combined.

The last interesting part of this example is a Controller to show the property placeholder values injected into the GreetingService from Part 1:


For the sake of simplicity, this example just returns a String without using a view. Like with the stand-alone example, the values returned from the GreetingService are resolved against a properties file included with the project. These default values can be overridden by setting operating system environment variables, setting Java command line options, or by starting a Redis server as described in Part 1.

The code for all three parts of this series is available in a runnable project in GitHub. The GitHub project also shows all the configuration using Java config in addition to the XML config shown here.

Tuesday, March 20, 2012

Custom PropertySource in Spring 3.1 - Part 2

A previous post described the process for registering a custom PropertySource in a Spring 3.1 application. Part 1 covered registering the custom PropertySource in a stand-alone Spring application. As part of building out an example, I also wanted to be able to test the custom PropertySource in a JUnit test case - the kind of test case you would write when doing integration testing.

In the stand-alone example, the important part of the code involved registering the custom PropertySource after an application context was created, but before the beans in the context are instantiated and their properties set (including the resolving of any property placeholders in property settings). Since the code in the stand-alone example is in full control of creating and setting up the application context, adding the custom PropertySource to the context was straight-forward.

Spring provides the TestContext framework to make setting up JUnit integration test cases fast and easy. With Spring 3.1, the TestContext framework was updated to support some of the major 3.1 themes such as Java configuration and Bean Profiles. Implementations of the ContextLoader interface are responsible for setting up the application context, and the @ContextConfiguration annotation applied to the test case class gives control over how the context is loaded. Since most of the work of setting up the application context is done by a ContextLoader implementation, it takes a bit more work to manipulate the context after it is created but before it is refreshed.

The trick to making this work is to leverage a hook that is implemented in one of the classes in the ContextLoader heirarchy - the customizeContext() method. By providing your own implementation of the ContextLoader and overriding the customizeContext() method, you get the chance to manipulate the context before it is refreshed.

The attributes used with the @ContextConfiguration annotation determine the subclass of AbstractGenericContextLoader that Spring uses to load the context. Here is an example of an integration test case that uses XML configuration:


The "loader" attribute of the @ContextConfiguration is the most important part of this test case. By default, using the "locations" attribute of @ContextConfiguration causes the Spring to load the application context using a GenericXmlContextLoader. The "loader" attribute is used to specify an application-specific subclass of GenericXmlContextLoader that overrides the customizeContext() method. Using the same RedisPropertySource implementation and XML configuration file from Part 1, this ContextLoader will instantiate and register the custom PropertySource into the application context:


That's it! As usual, Spring provides just enough extension points in the just right places to get the job done.

All the code listed here is available in a runnable project in GitHub. The GitHub project also shows all the configuration using Java config in addition to the XML config shown here.

Monday, March 12, 2012

Custom PropertySource in Spring 3.1 - Part 1

One of the improvements made to the Spring Framework in the 3.1 release is in the area of property placeholders. Chris Beams explains how the new unified property management system works in a blog posting on the SpringSource community site.

Several implementations of the new PropertySource interface are provided with the framework. PropertySource implementations backed by Java system properties and operating system environment variables are registered by default. If you specify one or more properties files using the <context:property-placeholder> tag in an XML configuration file or using the @PropertySource annotation on a Java config @Configuration class, the framework registers a PropertySource implementation backed by the specified files.

As Chris described, you can also register your own custom PropertySource implementations. This would be useful if you need bean properties to be stored in an external data source so they can be controlled outside of the application deployment process, or if you need properties to be encrypted or encoded for security reasons.

I decided to develop a custom PropertySource in a sample application. This PropertySource has some non-trivial bootstrapping of its own that needs to be done before it can be used, and Spring beans and dependency injection are used to bootstrap the PropertySource. The custom PropertySource must be instantiated, configured, and registered into to the application context containing the property placeholders before the application context is refreshed to make sure the property placeholders are resolved against the custom PropertySource.

To test this, I created a trivial bean with a few String properties:


and created a Spring XML config file named "app-context.xml" to instantiate the bean and set the properties:


When the GreetingService bean is instantiated, the Spring container will resolve the ${greeting.hello} and ${greeting.welcome} property placeholders and replace them with any specified text.

I then created a very simple Java main to bootstrap a Spring application context and show the properties injected into the bean:


With all this in place, I can run the GreetingApp class and play with setting the ${greeting.hello} and ${greeting.welcome} properties in environment variables, Java system properties, and properties files.

Next comes the custom PropertySource. I decided to use Redis as a backing store for configurable properties. Since Redis is a key-value store, it is a very natural fit for this example. I also decided to use Spring Data Redis to access the Redis data store. With Spring Data Redis, the code for the custom PropertySource was very simple. The PropertySource interface expects implementations to delegate to a "source" object to encapsulate the property values, so I created a RedisPropertySource which delegates to a RedisRepository. The RedisRepository in turn uses one of the RedisTemplate classes provided by Spring Data Redis.

Here is the code for the RedisPropertySource:


and the code for the RedisRepository:


Since the PropertySource bean and all related beans must be instantiated and wired together before the application beans can be instantiated, the PropertySource configuration goes in its own Spring XML config file named property-source-context.xml:


The application bootstrapping code is changed to instantiate the PropertySource bean and register it with the application's context:


The important thing to notice in this second version of the GreetingAppXmlConfig class is in the createAppContext() method. A second parameter is passed to the ClassPathXmlApplicationContext constructor to prevent the application context from being "refreshed" when it is created. This means the XML config file will be read and validated, but the beans defined in the context will not be created yet. The custom PropertySource is then registered with the application context, and the context is manually refreshed.

Of course, a Redis server has to be running and accessible before the GreetingApp main is run. The Redis command line client can be used to set and clear "greeting.hello" and "greeting.welcome" keys in the Redis server to test the RedisPropertySource. This example assumes the Redis server is running on "localhost" on the default port, but those values can be changed by setting properties of the JedisConnectionFactory bean in the property-source-context.xml file.

In the end, the code to make a custom RedisPropertySource work is very simple. The configuration and bootstrapping is also simple once the right sequence of events is understood.

I also worked on registering a custom PropertySource in a JUnit test case, which also took some figuring to get it right. Since this post has gotten pretty long, I'm going to continue that in a Part 2 post.

All the code listed here is available in a runnable project in GitHub. The GitHub project also shows all the configuration using Java config in addition to the XML config shown here.

Tuesday, November 29, 2011

Groovy-DDLUtils

Apache DDLUtils is a small but very useful library for migrating data and translating SQL schemas from one SQL database to another. DDLUtils includes support for an impressive list of SQL dialects, including all the major commercial and open-source RDBMS products.

The DDLUtils project provides a jar file containing the library code and a set of Ant tasks that use the library to perform common tasks - exporting a schema from a live database to a text file, and importing a schema from a text file to a live database. I haven't written an Ant XML build file for several years, and after some time away I find the Ant XML very verbose and cumbersome to work with.

Looking for an easier and more accessible way harness the power of DDLUtils, I turned to Groovy. Groovy scripts are a great way to leverage Java APIs in an expressive way, often with just a few lines of code. After using a few special-purpose Groovy scripts with DDLUtils, I decided to generalize the script to make it more configuration-driven and therefore more usable. The result is the Groovy-DDLUtils project.

The Groovy-DDLUtils project page on GitHub includes documentation on using and customizing the Groovy script, so I won't repeat that here. Take a look, give it a try, and send any feedback or enhancements suggestions via issues on GitHub, or comments on this blog.

Friday, November 11, 2011

Wrapping a Groovy script with Gradle

Groovy is great for scripting Java APIs in a very simple and expressive way. Providing utilities written in Groovy can sometimes be met with resistance, as any user of such a script first needs to download the appropriate version of Groovy and any other jar file dependencies. Grape helps with the dependency problem, but relies on all jar file dependencies being in a dependency repository, and the user of the script having access to a repository.

The Cookbook section of the Groovy site includes a script called WrappingGroovyScript that solves the Groovy and external jar dependency problems. As the page says, WrappingGroovyScript creates a self-contained jar file with your Groovy script, the Groovy runtime, and all other dependencies nicely bundled together. A user of your utility can then just run the generated jar using "java -jar". Very nice.

Then I got started thinking that Gradle should be able to do the same type of bundling for Groovy scripts. Here is a Gradle script that accomplishes that goal.


To use the script, just copy the contents of the Gist into your own build.gradle file, change the mainClassName, and add your dependencies.

That's it! Very simple and elegant, even smaller than the WrappingGroovyScript solution.

Monday, October 24, 2011

SQLFire and Spring Roo

SQLFire is an exciting new member of the VMware vFabric family, joining the likes of tc Server, GemFire, Hyperic, and RabbitMQ. SQLFire provides an in-memory high-performance data fabric with a familiar SQL interface.

Chris Harris wrote a series of blog entries about getting starting with SQLFire, using Grails to quickly generate a test application. In the same spirit as Chris' articles, this posting will show the steps for creating a simple Spring Roo application that uses SQLFire for data persistence.

The Roo reference docs contain a great tutorial for building a "pizza shop" application with Roo. This article will use the pizza shop tutorial application as a starting point. If you want to get familiar with Roo you can go through the full tutorial first, and then come back to this article. If you just want to jump into SQLFire, everything you need to get the application running is contained here. This article assumes that you already have Roo and all of its dependencies installed and working, and that you have some understanding of how to use the Roo shell.

Step 1: Create the Pizza Shop application

If you already have the Pizza Shop Roo application running, you can skip this step and go on to Step 2. If you haven't followed the Roo tutorial to create the Pizza Shop application, you can quickly create the app now.

First, copy the text in the box below and paste it into a file named "pizza.roo". This is the same set of Roo commands used in the tutorial, which will be run as a script.

pizza.roo
project --topLevelPackage com.springsource.roo.pizzashop
persistence setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY
entity --class ~.domain.Topping
field string --fieldName name --notNull --sizeMin 2
entity --class ~.domain.Base --testAutomatically 
field string --fieldName name --notNull --sizeMin 2
entity --class ~.domain.Pizza --testAutomatically 
field string --fieldName name --notNull --sizeMin 2
field number --fieldName price --type java.lang.Float
field set --fieldName toppings --type ~.domain.Topping
field reference --fieldName base --type ~.domain.Base
entity --class ~.domain.PizzaOrder --testAutomatically 
field string --fieldName name --notNull --sizeMin 2
field string --fieldName address --sizeMax 30
field number --fieldName total --type java.lang.Float 
field date --fieldName deliveryDate --type java.util.Date
field set --fieldName pizzas --type ~.domain.Pizza
controller all --package ~.web
Next, execute the following list of operating system and Roo commands to create a project root directory, make the project root the current directory, start the Roo shell, run the script to create the tutorial application, and run the application.
~/projects> mkdir roo-pizza
~/projects> cd roo-pizza
~/projects/roo-pizza> roo
roo> script /path/to/pizza.roo
Created ... (long list of Roo messages omitted)
Script required 8 second(s) to execute
~.web roo> quit 
~/projects/roo-pizza> mvn tomcat:run
The last command uses Maven to build the project and run the application in an embedded Tomcat server. The first time you run Maven, it may take a while to download all the dependencies for Roo and the application.

Use your favorite browser and navigate to the address "http://localhost:8080/pizzashop/". You should see the Roo application home screen. You can test the app by creating and listing bases, toppings, pizzas, pizza orders, etc.

Step 2: Introducing SQLFire

If you haven't already, download SQLFire from the download site. Installation is very simple. Assuming the installer package is in the root of the user home directory, run the following command.
~> java -jar SQLFire10Beta_Installer.jar
This will create a "SQLFire10Beta" directory under the directory the installer was run from. The "bin" directory under the install directory contains a script that is used to stop, start, and control SQLFire. Run the following commands to start a new SQLFire instance.
~/SQLFire10Beta> mkdir server1
~/SQLFire10Beta> bin/sqlf server start -dir=server1 &
The "server start" command will start a SQLFire server node with default options, using the specified directory to store state. SQLFire will be listening for JDBC connections from "localhost" only on port 1527.

You can use the "sqlf" command to make sure SQLFire is up and running.
~/SQLFire10Beta> bin/sqlf 
sqlf> connect client 'localhost:1527';
sqlf> show tables in sys;
sqlf> quit;
SQLFire should display a list of system tables that are created in each new database.

Step 3: Modifying the application for SQLFire

Now that the Pizza Shop application is created and SQLFire is running, we can modify the app to use SQLFire as the database instead of the Hypersonic database suggested by the Roo tutorial. This requires editing two configuration files and making the SQLFire JDBC driver available to the application via Maven.

First, edit the file "persistence.xml", which is in the directory "/src/main/resources/META-INF" under the project root directory. Change the line containing the "hibernate.dialect" property to use the Apache Derby dialect instead of the Hypersonic (HSQL) dialect. In the example below, line 6 has been changed to use the Derby dialect. This is the only line in the file that needs to be changed (comments are omitted from the Roo-generated file for clarity).

/src/main/resources/META-INF/persistence.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect"/>
      <property name="hibernate.hbm2ddl.auto" value="create"/>
      <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>
      <property name="hibernate.connection.charSet" value="UTF-8"/>
    </properties>
  </persistence-unit>
</persistence>
Next, change the "database.properties" file in the directory "/src/main/resources/META-INF/spring". All four properties in this file should be changed to match the example below.

/src/main/resources/META-INF/spring/database.properties
database.url=jdbc:sqlfire://localhost:1527/
database.driverClassName=com.vmware.sqlfire.jdbc.ClientDriver
database.username=pizza
database.password=pizza
The jar file containing the SQLFire thin-client JDBC driver must be made available to the application at run-time. Since Roo uses Maven to build and package the application, we can add the SQLFire jar files as dependencies to the Pizza Shop project. To do this, edit the "pom.xml" file in the project root directory and add the following to the "<dependencies>" section of the file. At the time of this posting, SQLFire is still in beta so we will use "1.0-beta" as the version.

/pom.xml
<dependency>
  <groupId>com.vmware.sqlfire</groupId>
  <artifactId>sqlfireclient</artifactId>
  <version>1.0-beta</version>
</dependency>
The beta release of the SQLFire client jar file is not available in any public Maven repositories. The jar file is included in the SQLFire distribution, and can be installed to your local Maven repository. From the "lib" directory under the SQLFire installation directory, run the following Maven command.
~/SQLFire10Beta/lib> mvn install:install-file -DgroupId=com.vmware.sqlfire /
-DartifactId=sqlfireclient -Dversion=1.0-beta /
-Dpackaging=jar -Dfile=sqlfireclient.jar
Finally, re-run the Maven command to start the application in an embedded Tomcat server.
~/projects/roo-pizza> mvn tomcat:run
Once again, point your browser at http://localhost:8080/pizzashop and verify that the application is running. Try creating a few entities (bases, toppings, pizzas) and use the "sqlf" client to verify that the data is being stored in SQLFire.
~/SQLFire10Beta> bin/sqlf 
sqlf> connect client 'localhost:1527';
sqlf> show tables in pizza;
sqlf> set schema pizza;
sqlf> select * from base;
Next Steps

From here, you can set up a more complex SQLFire data fabric with multiple nodes, using a peer-to-peer or locator topology, as described in the SQLFire documentation and in Chris Harris' Grails + SQLFire series.

You can also use Maven to package the application into a war file and run it in Tomcat, tc Server, or another web server.
~/projects/roo-pizza> mvn package

Friday, March 11, 2011

Customizing Spring 3 mvc:annotation-driven

In Spring 3, it is very easy to configure an application with all the basic MVC components using the mvc:annotation-driven tag.

The default configuration can be customized with arguments to the mvc:annotation-driven tag (such as "validator" and "conversion-service") and other tags in the mvc: namespace. In Spring 3.0.0 the set of customization options was somewhat limited, but it has grown with each Spring release. Spring 3.1 adds a mvc:message-converters to address one of the more common customization needs.

A very common mistake developers make when they need to customize the annotation-driven configuration is to use mvc:annotation-driven and also manually define a AnnotationMethodHandlerAdapter bean with customized properties, like this:
<mvc:annotation-driven/>

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
 <property name="customArgumentResolver">
   <bean class="com.example.ExampleArgumentResolver" />   
 </property>
  <property name="messageConverters">
    <list>
      <bean id="marshallingHttpMessageConverter"
            class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter"
            p:marshaller-ref="marshaller" p:unmarshaller-ref="marshaller"/>
    </list>
  </property>
</bean>

This does not work as expected. With this configuration, you end up with two AnnotationMethodHandlerAdapter beans in your application context - one created by mvc:annotation-driven and the one created manually. The one created by the framework is used, and the one created manually is ignored.

One working solution to this problem is to remove the mvc:annotation-driven tag and instead manually define all the annotation support beans. This is not ideal, as there is not a good way to keep up with all the beans defined automatically by mvc:annotation-driven as the annotation support evolves in the framework.

The preferred solution to the customization problem is to implement a BeanPostProcessor to modify properties of the AnnotationMethodHandlerAdapter bean created by mvc:annotation-driven in-place, instead of replacing it. This is not hard to do, and provides all the flexibility needed to customize the annotation support.

Here is an example of what this solution can look like. This solution uses a very flexible class that has all the same properties as AnnotationMethodHandlerAdapter, but configures an existing HandlerAdapter instead of creating a second one. Usage of this solution would look like this:

<mvc:annotation-driven/>

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapterConfigurer" init-method="init">
 <property name="customArgumentResolver">
   <bean class="com.example.ExampleArgumentResolver" />   
 </property>
  <property name="messageConverters">
    <list>
      <bean id="marshallingHttpMessageConverter"
            class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter"
            p:marshaller-ref="marshaller" p:unmarshaller-ref="marshaller"/>
    </list>
  </property>
</bean>

Look closely at line 3 in the second example, since this is the only line that is different from the first example. The bean being created is a AnnotationMethodHandlerAdapterConfigurer instead of a AnnotationMethodHandlerAdapter. The Configurer class manipulates the HandlerAdapter already created by the framework, but is configured just like AnnotationMethodHandlerAdapter. The "init-method" argument to the bean definition is important, as it causes the configuration to happen after the application context is up and running.

Here is what the Configurer looks like:
public class AnnotationMethodHandlerAdapterConfigurer {
  @Autowired
  private AnnotationMethodHandlerAdapter adapter;

  private WebBindingInitializer webBindingInitializer;
  private HttpMessageConverter[] messageConverters;
  private PathMatcher pathMatcher;
  private UrlPathHelper urlPathHelper;
  private MethodNameResolver methodNameResolver;
  private WebArgumentResolver[] customArgumentResolvers;
  private ModelAndViewResolver[] customModelAndViewResolvers;

  private boolean replaceMessageConverters = false;

  public void init() {
    if (webBindingInitializer != null) {
      adapter.setWebBindingInitializer(webBindingInitializer);
    }

    if (messageConverters != null) {
      if (replaceMessageConverters) {
        adapter.setMessageConverters(messageConverters);
      } else {
        adapter.setMessageConverters(mergeMessageConverters());
      }
    }

    if (pathMatcher != null) {
      adapter.setPathMatcher(pathMatcher);
    }

    if (urlPathHelper != null) {
      adapter.setUrlPathHelper(urlPathHelper);
    }

    if (methodNameResolver != null) {
      adapter.setMethodNameResolver(methodNameResolver);
    }

    if (customArgumentResolvers != null) {
      adapter.setCustomArgumentResolvers(customArgumentResolvers);
    }

    if (customModelAndViewResolvers != null) {
      adapter.setCustomModelAndViewResolvers(customModelAndViewResolvers);
    }
  }

  private HttpMessageConverter[] mergeMessageConverters() {
    return (HttpMessageConverter[])
                  ArrayUtils.addAll(messageConverters, adapter.getMessageConverters());
  }

  public void setWebBindingInitializer(WebBindingInitializer webBindingInitializer) {
    this.webBindingInitializer = webBindingInitializer;
  }

  public void setPathMatcher(PathMatcher pathMatcher) {
    this.pathMatcher = pathMatcher;
  }

  public void setUrlPathHelper(UrlPathHelper urlPathHelper) {
    this.urlPathHelper = urlPathHelper;
  }

  public void setMethodNameResolver(MethodNameResolver methodNameResolver) {
    this.methodNameResolver = methodNameResolver;
  }

  public void setCustomArgumentResolver(WebArgumentResolver argumentResolver) {
    this.customArgumentResolvers = new WebArgumentResolver[] {argumentResolver};
  }

  public void setCustomArgumentResolvers(WebArgumentResolver[] argumentResolvers) {
    this.customArgumentResolvers = argumentResolvers;
  }

  public void setCustomModelAndViewResolver(ModelAndViewResolver customModelAndViewResolver) {
    this.customModelAndViewResolvers = new ModelAndViewResolver[] {customModelAndViewResolver};
  }

  public void setCustomModelAndViewResolvers(ModelAndViewResolver[] customModelAndViewResolvers) {
    this.customModelAndViewResolvers = customModelAndViewResolvers;
  }

  public void setMessageConverters(HttpMessageConverter[] messageConverters) {
    this.messageConverters = messageConverters;
  }

  public void setReplaceMessageConverters(boolean replaceMessageConverters) {
    this.replaceMessageConverters = replaceMessageConverters;
  }
}

There is one property of the Configurer class that does not correspond directly to a property of AnnotationMethodHandlerAdapter: "replaceMessageConverters". By default this is false, which causes any configured MessageConverters to be added to the converters already configured into the AnnotationMethodHandlerAdapter. If this property is set to true, then the automatically-configured MessageConverters are thrown away and only those injected into the Configurer will be used.

This approach will become less and less interesting as Spring 3.1 is released and mvc:annotation-driven continues to evolve. Until then, it solves a problem that a lot of developers have spent time figuring out the hard way.

A Better Spring Meta-validator

Spring MVC 3 has a very rich set of features for binding and validating input data to command objects, including class-based validation and annotation-based validation.

Custom class-based validators can be registered with Spring MVC in one of two ways (as described in the documentation): configured in each @Controller class using the @InitBinder method, or configured at the application level using the "mvc:annotation-driven" tag with a "validator" argument. Using the per-controller approach gives lots of control when each Controller needs its own validators, but adding all those @InitBinder methods can become tedious (and therefore error-prone).

In a previous post, I showed a method for creating a meta-validator that could be configured as the global application-level validator, and would in turn delegate to other configured validators as appropriate for the command object type. This post is a refinement if that idea, giving more control over which validators are automatically discovered and globally available.

This flexibility is achieved by using annotations on the validators that should be globally available through the meta-validator, as in this example (stolen from the Spring documentation):


The first line is the part that is new - the @ValidatorComponent annotation. I don't love the name, but "Validator" was already taken and having the interface and annotation share a name would be confusing.

With the supporting code below, any classes that extend org.springframework.validation.Validator and also have the @ValidatorComponent annotation on them are automatically detected by the meta-validator and called when appropriate. Validators without the annotation are ignored by the meta-validator, and can be configured individually in @InitBinder methods if required.

Here is the code that makes this work. First, the annotation itself:


This annotation is annotated with @Component, which means validators using this annotation are also eligible for component scanning.

And, at last, the meta-validator class:


Using @Autowired with a collection as a way to get all beans of a certain type was a fairly recent discovery for me, and I like it much better than the older method of extending ApplicationContextAware and asking the ApplicationContext for "beansOfType". Otherwise this code is pretty straight-forward - it just scans the list of injected Validator beans and remembers any that have the annotation on them.

The setValidators() method is provided for the case where third-party validators also need to be registered with the meta-validator, such as the LocalValidatorFactoryBean needed to configure JSR-303 bean validation support.

Here is an example of a Spring XML configuration file that wires all this together:


That's it! Now all you have to do is write your validator classes (and their unit tests), annotate them with @ValidatorComponent, and let the framework do the rest.


Friday, May 28, 2010

Getting the classpath with Groovy

In a recent Groovy project, I needed to get the classpath that was used to start the program so I could pass it as a command-line parameter to another program being launched.

You can easily get the the list of classpath URLs used by the program's classloader. Most of the hints I found showed how to do this from a Groovy script, but it appears to work a little differently in a program.

Here is the code I came up with to get the classpath in a script:

def getClassPath() {
   def loaderUrls = this.class.classLoader.rootLoader.URLs
   def files = loaderUrls.collect { new URI(it.toString()).path - '/'}
   return files.join(File.pathSeparator)
}

println getClassPath()

And here is the same code in a program (i.e. a class with a main):

class ClassPathTestClass {
   static void main(args) {
      println new ClassPathTestClass().getClassPath()
   }

   def getClassPath() {
      def loaderUrls = this.class.classLoader.URLs
      def files = loaderUrls.collect { new URI(it.toString()).path - '/' }
      return files.join(File.pathSeparator)
   }
}

The difference is in how the list of URLs is initially retrieved. From a script you can get the list with "this.class.classLoader.rootLoader.URLs". In a program you use "this.class.classLoader.URLs".

The second line in each of the "getClassPath" methods took more tweaking than expected. The "new URI(it.toString()).path - '/'" syntax removes any encoding from the URL paths and strips everything but the path out of the URL. This has only been tested on Windows, I'm not sure if this will work exactly the same on other platforms.

Monday, May 10, 2010

Spring 3 Validation Aspect

Update: The problem that this article addresses has been fixed in Spring 3.1. If possible, upgrade to Spring 3.1 and skip the work-around below. See SPR-6709 for more details.

This post is a follow-up to a thread on the Spring Framework support forums. The thread discusses an issue with Spring 3 and the JSR-303 style of annotation-based validation.

To summarize the thread: the @Valid annotation can be used to trigger validation of a parameter to a method of an MVC Controller, but the validation is not properly invoked when the @Valid annotation is used along with the @RequestBody annotation. Without the @RequestBody annotation, the Spring DataBinder mechanism - with full @Valid support - is used to unmarshal the input message to the parameter object. With the @RequestBody annotation, the MessageConverter mechanism - without any @Valid support - is used instead of the DataBinder mechanism.

The issue is also documented in the Spring issue tracking system.

While waiting for Spring to address this gap, several people have developed work-arounds using Spring AOP. I also decided to use this approach. One of my goals in a work-around was to come up with a solution that was very easy to back out when Spring fixes the problem with @RequestBody and @Valid. The AOP-based approach meets this goal, since we can simply remove the aspect when the framework has proper support for this combination of annotations.

There are a few ways to implement an aspect for this, including one posted to the Spring forum thread by user @taku. The implementations are similar but differ in details like how controller methods are intercepted and how validation errors are dealt with.

The aspect my project is using will intercept a call to a method of a Spring-managed bean when the method has the @RequestMapping annotation on it. (Other approaches intercept methods that following certain naming convention or methods of controllers in certain packages.) Each parameter of an intercepted method is inspected, and an injected validator is called for every parameter that has both the @RequestBody and @Valid annotation on it.

If any method parameter fails validation, an HttpMessageConversionException will be thrown. This exception can then be caught and handled by the framework or by @ExceptionHandler methods in a controller. BindException would have been a more natural exception to throw, but it is a checked exception so it cannot be easily thrown from the aspect.

Here is the code for the aspect:

RequestBodyValidatorAspect.java:
@Aspect
public class RequestBodyValidatorAspect {
  private Validator validator;

  @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
  private void controllerInvocation() {
  }

  @Around("controllerInvocation()")
  public Object aroundController(ProceedingJoinPoint joinPoint) throws Throwable {

    MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
    Method method = methodSignature.getMethod();
    Annotation[][] argAnnotations = method.getParameterAnnotations();
    String[] argNames = methodSignature.getParameterNames();
    Object[] args = joinPoint.getArgs();

    for (int i = 0; i < args.length; i++) {
      if (hasRequestBodyAndValidAnnotations(argAnnotations[i])) {
        validateArg(args[i], argNames[i]);
      }
    }

    return joinPoint.proceed(args);
  }

  private boolean hasRequestBodyAndValidAnnotations(Annotation[] annotations) {
    if (annotations.length < 2)
      return false;

    boolean hasValid = false;
    boolean hasRequestBody = false;

    for (Annotation annotation : annotations) {
      if (Valid.class.isInstance(annotation))
        hasValid = true;
      else if (RequestBody.class.isInstance(annotation))
        hasRequestBody = true;

      if (hasValid && hasRequestBody)
        return true;
    }
    return false;
  }

  @SuppressWarnings({"ThrowableInstanceNeverThrown"})
  private void validateArg(Object arg, String argName) {
    BindingResult result = getBindingResult(arg, argName);
    validator.validate(arg, result);
    if (result.hasErrors()) {
      throw new HttpMessageConversionException("Validation of controller input parameter failed",
              new BindException(result));
    }
  }

  private BindingResult getBindingResult(Object target, String targetName) {
    return new BeanPropertyBindingResult(target, targetName);
  }

  @Required
  public void setValidator(Validator validator) {
    this.validator = validator;
  }
}

One limitation with this work-around is that it can only apply a single validator to all controllers. If you are using JSR-303 style annotation-based validation exclusively then this is not a problem - you just inject a LocalValidatorFactoryBean into the aspect. If you need to use a mix of annotation-based validation and class-based validation, this becomes a problem. 

To get around this limitation and make this AOP-based approach more flexible, I also implemented a meta-validator that finds all Validator classes in the application context and calls the appropriate validator for the type of object being validated. This meta-validator can then be injected into the aspect (and into the DataBinder). All other validators are just declared as beans in the app context.

Here is the code for the meta-validator:

public class TypeMatchingValidator implements Validator, InitializingBean, ApplicationContextAware {
  private ApplicationContext context;
  private Collection validators;

  public void afterPropertiesSet() throws Exception {
    findAllValidatorBeans();
  }

  public boolean supports(Class clazz) {
    for (Validator validator : validators) {
      if (validator.supports(clazz)) {
        return true;
      }
    }

    return false;
  }

  public void validate(Object target, Errors errors) {
    for (Validator validator : validators) {
      if (validator.supports(target.getClass())) {
        validator.validate(target, errors);
      }
    }
  }

  private void findAllValidatorBeans() {
    Map<String, Validator> validatorBeans =
            BeanFactoryUtils.beansOfTypeIncludingAncestors(context, Validator.class, true, false);
    validators = validatorBeans.values();
    validators.remove(this);
  }

  public void setApplicationContext(ApplicationContext context) throws BeansException {
    this.context = context;
  }
}


Here is an example of a Spring XML configuration file using the validator aspect and the meta-validator together:

<!-- enable Spring AOP support -->  
  <aop:aspectj-autoproxy proxy-target-class="true"/>

  <!-- declare the validator aspect and inject the validator into it -->
  <bean id="validatorAspect" class="com.something.RequestBodyValidatorAspect">
    <property name="validator" ref="validator"/>
  </bean>

  <!-- inject the validator into the DataBinder framework -->
  <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="webBindingInitializer">
      <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer" p:validator-ref="validator"/>
    </property>
  </bean>

  <!-- declare the meta-validator bean -->
  <bean id="validator" class="com.something.TypeMatchingValidator"/>

  <!-- declare all Validator beans, these will be discovered by TypeMatchingValidator -->
  <bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
  <bean class="com.something.PersonValidator"/>
  <bean class="com.something.AccountValidator"/>

Friday, April 30, 2010

Introducing SpringDoclet

As the Spring Framework evolves, one of the areas that gets better with each release is annotation-based application configuration and wiring. Using Spring annotations in Java classes along with component scanning helps fight the XML bloat that can make some applications difficult to work with.

However, one downside to annotation-based configuration is that there is no central place to find all Spring-managed beans in an application. With XML Spring configuration, all the bean definitions and their injected dependencies can be seen in one or more XML files (if you have the patience to wade through all the XML required for a larger system).

Reducing the XML bloat and moving the wiring closer to the code is worth the loss of visibility in my opinion.

IDEs can help with the visibility issue. SpringSource Tool Suite (or STS, available as a stand-alone Eclipse distribution or as a set of Eclipse plugins) provides a Spring Explorer view which shows components, MVC request mappings, AOP advices, auto-wired dependencies, and more. IntelliJ IDEA has some nice Spring-related features, including navigation between beans and their auto-wired dependencies via gutter icons, but (as far as I know) it doesn't have one view to show all Spring-managed components and mappings in an application.

On the Spring Framework community forums, the user @petrp suggested a tool to generate documentation for controllers and request mappings in a Spring MVC application. The more I thought about this idea the more I liked it. Generating an HTML report from the source code would be another good way to mitigate the visibility issue.

And so, SpringDoclet was born. SpringDoclet is a Javadoc doclet designed to generate an HTML report as part of a project's build process. The report lists all classes decorated with any of the annotations from the org.springframework.stereotype package (@Component, @Service, @Repository, @Controller). It also lists all @RequestMappings with the HTTP method, URL template, and implementing class. Classes listed on the report can be cross-linked to standard Javadoc HTML reports or other source code reports like JXR.

I decided to implement this as doclet so I could get the source code scanning for free, along with integration with Maven, Ant, and other tools that already support Javadoc.

I also chose to implement the doclet in Groovy. I knew the code would need to generate HTML, and Groovy's MarkupBuilder makes that chore a breeze compared to Java. I'm still fairly new to Groovy, and using a new language on a real project (even if it is a small one) is the best way for me to really learn it. I tried to do everything the Groovy way, learned a few tricks along the way, and became much more comfortable with the language.

The code for SpringDoclet is at http://github.com/scottfrederick/springdoclet. For now, you will have to build the doclet before using it. Instructions for building and using SpringDoclet are in the README file on GitHub.

Give it a try, and let me know what you think. Please comment on this post with any feedback, suggestions for enhancements, or (gasp!) bugs.