Spring MVC request parameter conversion with minimal configuration

I’ve been playing around with Spring Web MVC a bit and was looking for something similar to Jersey’s Parameter Classes that would provide conversion to custom types. I liked how with Jersey, you could encapsulate the conversion logic in a single class and have that reused across multiple methods with minimal configuration.

Here’s how I achieved a similar result in Spring Web MVC. (Note: the following examples were done with Spring 3.2.1)

Built-in?

Spring does provide some build-in support for conversion to specific types. For example, you can convert to Date and various numeric types. But, what if you want to convert a request parameter to some other custom type or a type from a third party? (Such as the date-time classes from Joda Time)

Minimize configuration

I searched for a bit and found various solutions, but they all seemed to require too much configuration: In addition to writing a converter class, you’d have to manually the converter with a ConversionService (either in code or in XML configuration). I didn’t like the idea of having to register the converter class; instead, I wanted it to be registered automatically based on some annotations.

Solution

Here’s what I came up with, based on this answer on Stack Overflow.

  1. Define a custom annotation for your converters so they can be automatically found

    @Target({ ElementType.TYPE, ElementType.FIELD })
    public @interface MyConverter {
    }
  2. Create a converter class, annotated with your custom annotation and @Component

    This is so it will be available for injection via @Resource. (In this example, we convert to a Joda Time LocalDate)

    The converter class must implement Spring’s Converter interface.

    @Component
    @MyConverter 
    public class LocalDateConverter implements Converter<String, LocalDate> {
    
      public static final String DATE_FORMAT = "YYYY-MM-dd";
    
      @Override
      public LocalDate convert(final String source) {
        return LocalDate.parse(source, DateTimeFormat.forPattern(DATE_FORMAT));
      }
    }
  3. Create a bean that extends FormattingConversionServiceFactoryBean that will auto-register all converters

    Here is where all the converters annotated with your custom annotation (and @Resource) are injected.

    public class MyConversionServiceFactoryBean extends FormattingConversionServiceFactoryBean {
    
      @Resource
      @MyConverter
      private List<Converter<?, ?>> myConverters;
    
      @Override
      protected void installFormatters(final FormatterRegistry registry) {
        // NOTE: This method call is deprecated.
        super.installFormatters(registry);
    
        for (final Converter<?, ?> converter : this.myConverters) {
          registry.addConverter(converter);
        }
      }
    
    }
  4. Edit Spring configuration so that the auto-registering bean is loaded

    Ok, I lied: There is one piece of configuration you need, but once it’s made it need never be changed, even when you define additional converters.

    <mvc:annotation-driven conversion-service="applicationConversionService" />
    <bean class="com.myapplication.spring.mvc.controller.converters.MyConversionServiceFactoryBean" id="applicationConversionService"/>
  5. Modify controller method to use the proper type

    Note that if conversion fails (via an uncaught exception from the convert() method) then the client will see a 400 Bad Request response.

    @RequestMapping(value = "widget/{date}", method = RequestMethod.GET)
    @ResponseBody
    public String getWidgetDate(@PathVariable("date") final LocalDate date) {
      // We get auto-conversion to a LocalDate type... 
      // Just spits back the date to the client.
      return date.toString();
    }

Summary

I hope you found this useful. With just a little bit of work, we have a bean that will auto-register and make available any new converters you define, so as long as you annotate the converter properly.

2 Comments »

  1. Thanks a lot of … very useful tutorial …

  2. Segun argumenta Google, si bien la aplicación es
    legal, el inconveniente se halla en el potencial empleo que los usuarios podían darle para piratear aplicaciones puesto que si
    Aptoide se fundamenta en la buen y honesto accionar de los usarios quienes podían usarlo para tener
    copias de seguridad de aplicaciones que no estaban en Google Play, también podían subir aplicaciones
    de pago y así piratear esas aplicaciones.

Post a Comment

(required)

(will not be published) (required)

XHTML tags allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Note: rel="nofollow" will be added to all links in comments.

Comments will be closed on Sunday, April 19th, 2015.