2016-09-14 83 views
0

我正在嘗試爲應用程序/ x-www-form-urlencoded和字符串有效負載以及其他應用程序/ json格式與json主體創建2個服務的資源。將ByteArrayOutputStream轉換爲Kotlin中的json

我有這樣的代碼:

@POST @Path("/test") 
fun test(@Context request: ContainerRequest): Response { 
    val baos = ByteArrayOutputStream() 
    request.entityStream.use { it.copyTo(baos) } 
    val ipnRawData = baos.toString() 
    var map : Map<String,Any> 
    map = when (request.headers.getFirst("Content-Type")) { 
     "application/json" -> objectMapper.convertValue(ipnRawData,Map::class.java) as Map<String,Any> 
     "application/x-www-form-urlencoded" -> LinkedHashMap() 
     else -> throw UnsupportedOperationException() 
    } 
    //....handle the map 
    return Response.status(200).build() 
} 

但是,當我嘗試使用JSON選項運行它,和身體:{"name" :"test"}),我得到一個錯誤:

"java.lang.IllegalArgumentException: Can not construct instance of java.util.LinkedHashMap: no String-argument constructor/factory method to deserialize from String value ('{ "name" :"test"}')"

感謝您的幫助,Yoel

回答

5

您應該使用mapper.readValue將JSON反序列化爲對象。

使用原始傑克遜而不Jackson-Kotlin module

val map: Map<String, String> = JSON.readValue("""{"name" :"test"}""", 
         object : TypeReference<Map<String, String>>() {}) 

這通過在一個object expression與超類TypeReference指定你想要全泛型仍然完好無損以創建類型(你方法從類型遭受擦除)。

相反,如果你使用Jackson-Kotlin module你只需要:

val map: Map<String, String> = JSON.readValue("""{"name" :"test"}""") 

因爲它有輔助/擴展功能隱藏一些像TypeReference創建醜陋的東西。

你應該總是使用Jackson-Kotlin module與科特林代碼,這樣你可以實例化任何類型的科特林對象包括具有所有val參數,沒有缺省構造數據類的,把它理解爲空,也處理爲默認值構造函數參數。一個簡單的單機例如:

import com.fasterxml.jackson.module.kotlin.* 

val JSON = jacksonObjectMapper() // creates ObjectMapper() and adds Kotlin module in one step 

val map: Map<String, String> = JSON.readValue("""{"name" :"test"}""") 

通知進口.*,這樣它拿起所有的擴展功能,否則你需要明確的導入:com.fasterxml.jackson.module.kotlin.readValue

或者在你的情況下,修改後的代碼將是:

import com.fasterxml.jackson.module.kotlin.readValue 

val objectMapper = jacksonObjectMappe() // instead of ObjectMapper() 

... 

@POST @Path("/test") 
fun test(@Context request: ContainerRequest): Response { 
    val bodyAsString = request.entityStream.bufferedReader().readText() 
    val map: Map<String, Any> = when (request.headers.getFirst("Content-Type")) { 
     "application/json" -> objectMapper.readValue(bodyAsString) 
     "application/x-www-form-urlencoded" -> LinkedHashMap() 
     else -> throw UnsupportedOperationException() 
    } 
    //....handle the map 
    return Response.status(200).build() 
} 

的代碼也被清理一點點去除使用var和閱讀更科特林friendl實體流y方式。

還要注意的是,Content-Type頭可能會更復雜,它可能包含編碼以及如:

Content-type: application/json; charset=utf-8 

所以,你可能要來檢查了效用函數,如果標題是「等於application/json或開始與application/json;「,而不是隻有平等檢查。

最後,您可以直接將request.entityStream傳遞給objectMapper.readValue,並且絕對不要將其複製到字符串中。readValue有各種過載對於這些類型的輸入有幫助。

+0

感謝您的詳細解答和有用的提示! – Joel