2016-09-14 55 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