{"id":1402,"date":"2013-04-07T19:16:29","date_gmt":"2013-04-08T00:16:29","guid":{"rendered":"http:\/\/unitstep.net\/?p=1402"},"modified":"2013-04-07T19:16:29","modified_gmt":"2013-04-08T00:16:29","slug":"spring-mvc-request-parameter-conversion-with-minimal-configuration","status":"publish","type":"post","link":"https:\/\/unitstep.net\/blog\/2013\/04\/07\/spring-mvc-request-parameter-conversion-with-minimal-configuration\/","title":{"rendered":"Spring MVC request parameter conversion with minimal configuration"},"content":{"rendered":"

I’ve been playing around with Spring Web MVC a bit and was looking for something similar to Jersey’s Parameter Classes<\/a> 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.<\/p>\n

Here’s how I achieved a similar result in Spring Web MVC. (Note: the following examples were done with Spring 3.2.1<\/em>)<\/p>\n

<\/p>\n

Built-in?<\/h2>\n

Spring does provide some build-in support for conversion to specific types. For example, you can convert to Date and various numeric types<\/a>. 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<\/a>)<\/p>\n

Minimize configuration<\/h2>\n

I searched for a bit and found<\/a> various<\/a> solutions<\/a>, 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<\/acronym><\/a> 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.<\/p>\n

Solution<\/h2>\n

Here’s what I came up with, based on this answer on Stack Overflow<\/a>.<\/p>\n

    \n
  1. \n

    Define a custom annotation for your converters so they can be automatically found<\/h3>\n
    @Target({ ElementType.TYPE, ElementType.FIELD })\r\npublic @interface MyConverter {\r\n}<\/code><\/pre>\n<\/li>\n
  2. \n

    Create a converter class, annotated with your custom annotation and @Component<\/code><\/h3>\n

    This is so it will be available for injection via @Resource<\/code>. (In this example, we convert to a Joda Time LocalDate<\/a><\/code>)<\/p>\n

    The converter class must implement Spring’s Converter<\/a><\/code> interface.<\/p>\n

    @Component\r\n@MyConverter \r\npublic class LocalDateConverter implements Converter<String, LocalDate> {\r\n\r\n  public static final String DATE_FORMAT = \"YYYY-MM-dd\";\r\n\r\n  @Override\r\n  public LocalDate convert(final String source) {\r\n    return LocalDate.parse(source, DateTimeFormat.forPattern(DATE_FORMAT));\r\n  }\r\n}<\/code><\/pre>\n<\/li>\n
  3. \n

    Create a bean that extends FormattingConversionServiceFactoryBean<\/code> that will auto-register all converters<\/h3>\n

    Here is where all the converters annotated with your custom annotation (and @Resource<\/code>) are injected.<\/p>\n

    public class MyConversionServiceFactoryBean extends FormattingConversionServiceFactoryBean {\r\n\r\n  @Resource\r\n  @MyConverter\r\n  private List<Converter<?, ?>> myConverters;\r\n\r\n  @Override\r\n  protected void installFormatters(final FormatterRegistry registry) {\r\n    \/\/ NOTE: This method call is deprecated.\r\n    super.installFormatters(registry);\r\n\r\n    for (final Converter<?, ?> converter : this.myConverters) {\r\n      registry.addConverter(converter);\r\n    }\r\n  }\r\n\r\n}<\/code><\/pre>\n<\/li>\n
  4. \n

    Edit Spring configuration so that the auto-registering bean is loaded<\/h3>\n

    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.<\/p>\n

    <mvc:annotation-driven conversion-service=\"applicationConversionService\" \/>\r\n<bean class=\"com.myapplication.spring.mvc.controller.converters.MyConversionServiceFactoryBean\" id=\"applicationConversionService\"\/><\/code><\/pre>\n<\/li>\n
  5. \n

    Modify controller method to use the proper type<\/h3>\n

    Note that if conversion fails (via an uncaught exception from the convert()<\/code> method) then the client will see a 400 Bad Request response.<\/p>\n

    @RequestMapping(value = \"widget\/{date}\", method = RequestMethod.GET)\r\n@ResponseBody\r\npublic String getWidgetDate(@PathVariable(\"date\") final LocalDate date) {\r\n  \/\/ We get auto-conversion to a LocalDate type... \r\n  \/\/ Just spits back the date to the client.\r\n  return date.toString();\r\n}<\/code><\/pre>\n<\/li>\n<\/ol>\n

    Summary<\/h2>\n

    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.<\/p>","protected":false},"excerpt":{"rendered":"

    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 […]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[64,197,400],"tags":[450,401,493],"_links":{"self":[{"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/posts\/1402"}],"collection":[{"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/comments?post=1402"}],"version-history":[{"count":20,"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/posts\/1402\/revisions"}],"predecessor-version":[{"id":1447,"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/posts\/1402\/revisions\/1447"}],"wp:attachment":[{"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/media?parent=1402"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/categories?post=1402"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/tags?post=1402"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}