2013-12-18 37 views
2

我似乎能夠使用傑克遜來製作Json-String - > scala.collection.Map的映射器。如何獲得彈簧RestTemplate,Scala和傑克遜一起玩好

如何將同一個映射器連接到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]]) 
+0

1.什麼是WrappingHttpMessageConverter?我在Spring文檔中沒有看到這一點? 2.爲了測試的目的,可能最好爲單獨的ObjectMapper提供單獨的模塊實例。 –

回答

3

Assumtions

  1. WrappingHttpMessageConverter是一個派生類的MappingJackson2HttpMessageConverter,或者一些類,就像它。
  2. 你使用Spring 4.0(雖然這個答案或許也適用於春季3.2)

問題

默認RestTemplate構造嘗試檢測,如果傑克遜是在classpath中,如果是,將MappingJackson2HttpMessageConverter添加到MessageConverters列表中。由於它已經在列表中,因此在您檢查WrappingHttpMessageConverter之前將會使用它。

該默認轉換器沒有安裝Scala模塊。這是事情變得棘手的地方。 HttpMessageConverterExtractor嘗試詢問第一個轉換器是否可以反序列化該類型;目前ObjectMapper爲此測試返回true(它是否應該應該是是一個更長的話題,並不像看起來那麼清晰)。提取器不能處理一個轉換器可能失敗的想法,但後面的一個可能會成功(就像你的情況那樣)。

解決辦法

你需要確保春季與任何其他嘗試之前找到與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轉換器。

+0

對我來說!謝謝! – user48956