如何让SpringTemplate,scala和jackson一起玩得很开心

时间:2013-12-18 02:56:04

标签: json spring scala jackson

我似乎能够使用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 个答案:

答案 0 :(得分:3)

Assumtions

  1. WrappingHttpMessageConverterMappingJackson2HttpMessageConverter的派生类,或类似的类。
  2. 你正在使用Spring 4.0(虽然这个答案可能也适用于Spring 3.2)
  3. 问题

    默认的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转换器之前将其删除。