Sunday, November 10, 2013

NumberToEnumConverter extending Spring's factory converters

Custom Spring converters - taking it beyond the API

I use Spring regularly & quite a lot for years now, and even though I hold the highest respect for the Spring people, there are still a few needed extensions you find yourself required to write by yourself.
The Spring Converters mechanism is an awesome, huge part of Spring's core and base classes and used by their beans definitions, creation and property injections.
A nice feature which I used a long while ago, and quite some from then on is the enum conversion,
which only supports the StringToEnum conversion. (@see StringToEnumConverterFactory)
I won't get into why the Spring guys choose to make the only converter to Enum available for us simple minded, as the Enum itself is a creature whom deserves and gets a lot of respect by itself, and this post deals with the conversion API and not the subtleties of the java language.
An Extension RequirementHaven't you ever found yourself needed to use numbers to enum conversion?
(holding integers for index purposes to your enum to be used with switch-case statements...can't wait for Java 8 already to start refactoring all that redundant code :-) )
If you use spring in your code, you may find the StringToEnumConverter pretty handy, maybe you've used it without even knowing it.
Well using the StringToEnum is a given, and a nice converter infrastructure is always required in any medium to large applications. So this is the way to use Spring's power to make it simple and using Java's help (Java helping spring...weird but this time it was the case).

Firstly the convention for the ConverterFactory:
@Component(value = "NumberToEnumConverterFactory")
public class NumberToEnumConverterFactory implements ConverterFactory{
...
final Method method = number.getClass().getComponentType().getMethod("getValue");
final Object enumValue = ReflectionUtils.invokeMethod(method, instance);
...
}
see full code

Making a generic factory to be used whenever and where ever you need it.
An important thing here to do is to setup some sort of convention to your Enum classes.
I saw people use @annotations, or pass some kind of a String/Integer or even another enum to determine the conversion methods for the reflection's invocation.
I decided to make a simple convention, saying that my enum will have a value field, with a getter method to it, hence the "getValue" method invocation. Make a choice to your liking, keeping in mind the KISS factor. have-course you'll have to make changes to my ConverterFactory if you do want to take a different approach.

Secondly the PropertyEditor:
@Component
public class PriorityEnumPropertyTypeEditor extends PropertyEditorSupport
implements ApplicationContextAware

Making the above class as a @Component will assist you to register into Spring's core.
And during the Beans creation Spring will use the PropertyEditorSupport class, trying to find the proper Converter class to convert the type when used as a property.

Lastly the application context xml:
Don't forget to register the Custom PropertyEditor, this can be done with Spring's CustomEditorConfigurer, which is simply accessed in one of your application-context XMLs.

see the Context xml

Using This mechanism is a simple way to achieve nice and simple conversion while injecting your integer property values as Enums into your beans. A Maven project source code example can be downloaded from my Github, see you next time :-)

full source code