The relatively recent trend of 'fluent' interfaces in Java has lead to some interesting challenges when registering these within the Spring Framework. Read more about a new XML namespace created to simplify the definition of fluent beans in Spring.

One of the more recent developments in the Java community is the use of fluent interfaces . This appears to be a natural progression from the Builder pattern towards a mini DSL that eases readability and, in many cases, drastically simplifies code. I've seen these crop up in a few notable locations, including Google Guava and Joda Time . I'm a big fan and try to use these where they make sense, and would encourage you to at least be aware of the ideas behind it - even if you're not entirely won over yet.

The difficulty with this new method of initialising objects is that it deviates from the JavaBeans standard that Spring relies on to find property accessors. In fact, the fluent bean doesn't necessarily have properties that match the fluent methods!

The easy solution to this is to use Spring's Java-based container configuration , but that's not always an option. For those cases where XML configuration is the only way forward, I've created a custom XML namespace to create beans using fluent interfaces. Here's an example showing the creation of a bean using standard Spring Java config followed by how it would be done using the new namespace:

As you can see, the XML structure is designed to mirror both the Spring property-based accessors as well as typical Builder pattern methods. Most of what you see is configurable, including the build method (defaults to build ), method prefix (defaults to with ), and fluent style (defaults to PROPERTIES ).

The reason the fluent style exists is to support bean definition for quasi-fluent interfaces. Classes like Java's StringBuilder are a good example of this, where a series of method invocations (in this case, append ) successively construct the underlying object. These aren't really fluent interfaces, nor are they your typical Builder class - but I thought they were similar enough to warrant inclusion. Fluent properties operate in a manner comparable with JavaBeans properties, except that it uses the configured prefix instead of the standard set prefix. Using fluent methods, however, does not use any prefix at all - but simply invokes the method as named.

Usage

All you need to do to make use of this library in your own application is include it as a regular Maven dependency with the following coordinates:

Once you've included the dependency, you should be able to define beans with the sg namespace (as per the example above). If you want to make changes, view the source code, or submit feature requests or bug reports, you can access the project on GitHub .

Other Approaches

I've seen a few questions on StackExchange and other that address this problem, but none of the solutions appear to address this generically for the majority use case without requiring a lot of boilerplate code (like writing a BeanInfo implementation for each fluent type). While these solutions appear to work, the repetitive code doesn't seem necessary.

Another limitation in using the BeanInfo extension is that you're still quite limited in defining what your setter method looks like. Many libraries have done away with the "set" prefix (which I guess is a misnomer when you're not setting a field value) and favoured prefixes like "with". Even if you could match the varieties of fluent method names, you would still be left in a position where Spring discards the return value - which doesn't help in certain circumstances. My approach solves both of these problems.

Future Enhancements

One of the limitations in this version is that all fluent methods must have an arity of one. Clearly this precludes many use cases where multiple method parameters are expected by the target object. It would definitely be a worthwhile improvement to support methods with multiple parameters, but I need to consider how this can be achieved safely while also respecting method overloads that collections.

Another restriction is the requirement to define a build method. There are cases where this isn't required - typically when creating an immutable bean where the bean class is the builder class. An example of this can be seen in the test case that uses a Joda Time DateTime . The workaround in this particular case was to set the build method as toDateTime , which simply returns this .

I'm sure there are many other improvements that can be made, but hopefully this is better than the status quo. Hopefully Spring sees it fit to include some native support for fluent bean creation in a future release.



Published

19 December 2012

Share

submit to reddit