First of all ... Im relatively new in Spring, I use spring 3.x and I DONT LIKE SPRING'S XML CONFIGURATION FILES ... I dont want for every refactoring I do, to run into XML file for updates ...
I'm trying to configure spring in a way that for any request, if I have some @RequestParam/@RequestBody/@PathVariable etc with type other than String in my hadlers, spring will convert values to that type correctly or put null to handler's args (I never use primitive types in handler arguments). So far so good ...
Until now I've registered all converter/converterFactory classes like this:
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<!-- converters is a set of both converters and converterfactories -->
<bean class="controller.converters.enumConverter" />
<bean class="controller.converters.integerConverter" />
<bean class="controller.converters.objects.FooConverter" />
...
</list>
</property>
</bean>
Is there any way to register converters with annotations?
Can anything (or just basic stuff) about spring XML be done with annotations only, and get rid of XML configuration once and for all? ... and how?
Spring does not have annotation support for Converters, but you can build your own.
All you need is an custom qualifier annotation (lets call it @AutoRegistered
) and some kind of Converter/Formatter Registrar (implements FormatterRegistrar
) that registers all the Spring Beans with this @AutoRegistered
annotation (and some xml to register this registration service).
Then you need to annotate your conveter with this annotation (and some other annotation to make it a spring bean) and that is all.
@AutoRegistered
annotation:
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface AutoRegistered {}
Registration service:
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.converter.Converter;
import org.springframework.format.FormatterRegistrar;
import org.springframework.format.FormatterRegistry;
public class AutoregisterFormatterRegistrar implements FormatterRegistrar {
/**
* All {@link Converter} Beans with {@link AutoRegistered} annotation.
* If spring does not find any matching bean, then the List is {@code null}!.
*/
@Autowired(required = false)
@AutoRegistered
private List<Converter<?, ?>> autoRegisteredConverters;
@Override
public void registerFormatters(final FormatterRegistry registry) {
if (this.autoRegisteredConverters != null) {
for (Converter<?, ?> converter : this.autoRegisteredConverters) {
registry.addConverter(converter);
}
}
}
}
XML configuration for the registrar:
<bean id="applicationConversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatterRegistrars">
<set>
<bean
class="AutoregisterFormatterRegistrar"
autowire="byType" />
</set>
</property>
</bean>
BTW for your enum converter you do not need a ConversionFactory
- a simple converter is enough:
@AutoRegistered
@Component
public class EnumConverter implements Converter<Enum<?>, String> {
/** Use the same immutable value instead of creating an new array every time. */
private static final Object[] NO_PARAM = new Object[0];
/** The prefix of all message codes. */
private static final String PREFIX = "label_";
/** The separator in the message code, between different packages
as well as between package can class. */
private static final String PACKAGE_SEPARATOR = "_";
/** The separator in the message code, between the class name
and the enum case name. */
private static final String ENUM_CASE_SEPARATOR = "_";
/** The message source. */
private MessageSource messageSource;
@Autowired
public EnumConverter(final MessageSource messageSource) {
if (messageSource == null) {
throw new RuntimeException("messageSource must not be null");
}
this.messageSource = messageSource;
}
@Override
public String convert(final Enum<?> source) {
if (source != null) {
String enumValueName = source.name();
String code = PREFIX + source.getClass().getName().toLowerCase().
replace(".", PACKAGE_SEPARATOR)
+ ENUM_CASE_SEPARATOR + enumValueName.toLowerCase();
String message = messageSource.getMessage(code, NO_PARAM, enumValueName,
LocaleContextHolder.getLocale());
return message;
} else {
return "";
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With