用于Scala.Option的Spring RequestParam格式化程序


问题内容

我们在Scala应用程序中使用Spring MVC,我想弄清楚如何解包Scala
Option,以便可以使用正确地转换它们@RequestParam。我认为该解决方案可能与Formatter
SPI有关
,但由于Option可以包含任意数量的值(我希望Spring正常处理该值,就像转换后的值一样),因此我不确定如何使它正常工作值根本不是Option)。本质上,Option在正常转换发生之后,我几乎想对要包装的值进行附加转换。

例如,给出以下代码:

@RequestMapping(method = Array(GET), value = Array("/test"))
def test(@RequestParam("foo") foo: Option[String]): String

网址/test应导致foo参数的值为None,而网址/test?foo=bar应导致foo参数的值为Some("bar")/test?foo可能会导致字符串为空或None)。


问题答案:

我们设法通过创建AnyRefto Option[AnyRef]转换器并将其添加到Spring MVC
来解决此问题ConversionService

import org.springframework.beans.factory.annotation.{Autowired, Qualifier}
import org.springframework.core.convert.converter.ConditionalGenericConverter
import org.springframework.core.convert.converter.GenericConverter.ConvertiblePair
import org.springframework.core.convert.{ConversionService, TypeDescriptor}
import org.springframework.stereotype.Component

import scala.collection.convert.WrapAsJava

/**
 * Base functionality for option conversion.
 */
trait OptionConverter extends ConditionalGenericConverter with WrapAsJava {
  @Autowired
  @Qualifier("mvcConversionService")
  var conversionService: ConversionService = _
}

/**
 * Converts `AnyRef` to `Option[AnyRef]`.
 * See implemented methods for descriptions.
 */
@Component
class AnyRefToOptionConverter extends OptionConverter {
  override def convert(source: Any, sourceType: TypeDescriptor, targetType: TypeDescriptor): AnyRef = {
    Option(source).map(s => conversionService.convert(s, sourceType, new Conversions.GenericTypeDescriptor(targetType)))
  }

  override def getConvertibleTypes: java.util.Set[ConvertiblePair] = Set(
    new ConvertiblePair(classOf[AnyRef], classOf[Option[_]])
  )

  override def matches(sourceType: TypeDescriptor, targetType: TypeDescriptor): Boolean = {
    Option(targetType.getResolvableType).forall(resolvableType =>
      conversionService.canConvert(sourceType, new Conversions.GenericTypeDescriptor(targetType))
    )
  }
}