我正在尝试为2个服务创建一个资源,1个在application / x-www-form-urlencoded和string payload中,另一个应用程序/ json格式用json body。
我有这段代码:
@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选项和body:{"name" :"test"}
)运行它时,我收到错误:
“java.lang.IllegalArgumentException:无法构造java.util.LinkedHashMap的实例:no String-argument构造函数/工厂方法从String值反序列化('{ “name”:“test”}')“
感谢任何帮助,Yoel
答案 0 :(得分: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与Kotlin代码一起使用,以便您可以实例化任何类型的Kotlin对象,包括具有所有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
的使用,并以更加Kotlin友好的方式读取实体流。
另请注意,Content-Type
标头可能更复杂,也可能包含编码,例如:
Content-type: application/json; charset=utf-8
因此,您可能需要一个实用程序函数来检查标题是否等于application/json
或以application/json;
&#34开头;而不仅仅是一次平等检查。
最后,您可以将request.entityStream
直接传递给objectMapper.readValue
,但绝不会将其复制到字符串中。 readValue
有各种重载对这些类型的输入很有帮助。