【问题标题】:How to get spring RestTemplate, scala and jackson to play nice to together如何让 spring RestTemplate、scala 和 jackson 一起玩得很好
【发布时间】:2014-01-06 02:01:36
【问题描述】:

我似乎可以使用 Jackson 来制作 Json-String 的映射器 --> scala.collection.Map。

如何将同一个映射器连接到 RestTemplate?

val restTemplate = new RestTemplate()    

val module = new OptionModule with MapModule with SeqModule with IteratorModule
val mapper = new ObjectMapper()
mapper.registerModule(module)

// Get some example JSON
val uri = "http://...."
val response:String = restTemplate.getForObject(uri, classOf[String] )

// *** success ***
// Use the mapper directly: String --> scala.collection.Map
val map1 = mapper.readValue(response, classOf[scala.collection.Map[String, Any]])


// Try hooking up the same module to the RestTemplate:   
val wrappingConverter = new WrappingHttpMessageConverter() 
wrappingConverter.getObjectMapper().registerModule(module)
val list = restTemplate.getMessageConverters()
list.add(wrappingConverter)
restTemplate.setMessageConverters(list)

// *** FAILS ***
// org.springframework.http.converter.HttpMessageNotReadableException: Could not read    
// JSON: Can not construct instance of scala.collection.Map, problem: abstract types 
// either need to be mapped to concrete types, have custom deserializer, or be 
// instantiated with additional type information
val map2 = restTemplate.getForObject(uri, classOf[scala.collection.Map[String, Any]] )

【问题讨论】:

  • 1. WrappingHttpMessageConverter 是什么?我在 Spring 文档中没有看到这一点? 2. 出于测试的目的,最好为单独的ObjectMappers 提供单独的模块实例。

标签: json spring scala jackson


【解决方案1】:

假设

  1. WrappingHttpMessageConverterMappingJackson2HttpMessageConverter 的派生类,或类似它的某个类。
  2. 您使用的是 Spring 4.0(尽管这个答案可能也适用于 Spring 3.2)

问题

默认的RestTemplate 构造函数会尝试检测Jackson 是否在您的类路径中,如果是,则将MappingJackson2HttpMessageConverter 添加到MessageConverters 列表中。由于它已经在列表中,因此将在您的 WrappingHttpMessageConverter 被检查之前使用它。

该默认转换器没有安装 Scala 模块。这就是事情变得棘手的地方。 HttpMessageConverterExtractor尝试询问第一个转换器是否可以反序列化类型;目前 ObjectMapper 为此测试返回true(它是否应该是一个更长的话题,不像看起来那么明确)。提取器不会处理一个转换器可能会失败的想法,但稍后的转换器可能会成功(就像您的情况一样)。

解决方法

您需要确保 Spring 在尝试使用任何其他模块之前找到配置了 Scala 模块的 ObjectMapper。您可以通过多种方式做到这一点;最强大的是搜索预配置的转换器并更新您找到的第一个转换器,如果您没有找到,则添加一个新的:

val jacksonConverter = list.asScala.collectFirst {
  case p: MappingJackson2HttpMessageConverter => p
}
if (jacksonConverter.isDefined) {
  jacksonConverter.get.getObjectMapper.registerModule(module)
}
else {
  list.add(new MappingJackson2HttpMessageConverter) // or your derived class if you prefer
}

其他选项包括将您的自定义消息转换器添加到列表的前面,或者在添加您自己的之前删除现有的 Jackson 转换器。

【讨论】:

  • 为了我!谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-27
  • 2015-04-30
  • 2011-03-16
  • 2016-11-13
  • 1970-01-01
  • 2010-09-05
相关资源
最近更新 更多