我使用Jackson Scala模块.
我已经创建了一个小的序列化工具来处理Play2框架接收的json有效负载.
def unserializePayloadAs[T](implicit requestContext: RequestContext[JsValue]): T = {
val json: String = Json.stringify(requestContext.request.body)
unserialize(json)
}
def unserialize[T](json: String): T = {
objectMapper.readValue(json)
}
Run Code Online (Sandbox Code Playgroud)
Jackson Scala模块的readValue具有签名:
def readValue[T: Manifest](content: String): T = {
readValue(content, constructType[T])
}
Run Code Online (Sandbox Code Playgroud)
在尝试使用我的反序列化代码时,我有一个堆栈.
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate abstract type [simple type, class scala.runtime.Nothing$] (need to add/enable type information?)
at [Source: java.io.StringReader@7bb78579; line: 1, column: 2]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164) ~[jackson-databind-2.2.0.jar:2.2.0]
at com.fasterxml.jackson.databind.deser.std.ThrowableDeserializer.deserializeFromObject(ThrowableDeserializer.java:77) ~[jackson-databind-2.2.0.jar:2.2.0]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121) ~[jackson-databind-2.2.0.jar:2.2.0]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2888) ~[jackson-databind-2.2.0.jar:2.2.0]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2041) ~[jackson-databind-2.2.0.jar:2.2.0]
at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper$class.readValue(ScalaObjectMapper.scala:157) ~[jackson-module-scala_2.10-2.2.0.jar:2.2.0]
at utils.CustomSerializer$$anon$1.readValue(CustomSerializer.scala:17) ~[na:na]
at utils.CustomSerializer$.unserialize(CustomSerializer.scala:39) ~[na:na]
at utils.CustomSerializer$.unserializePayloadAs(CustomSerializer.scala:35) ~[na:na]
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,当我在代码中添加清单时,它工作正常:
def unserializePayloadAs[T: Manifest](implicit requestContext: RequestContext[JsValue]): T = {
val json: String = Json.stringify(requestContext.request.body)
unserialize(json)
}
def unserialize[T: Manifest](json: String): T = {
objectMapper.readValue(json)
}
Run Code Online (Sandbox Code Playgroud)
有人能解释那里发生了什么吗?当我们使用带有Manifest上下文绑定的方法调用方法时,使用no的参数化方法Manifest,然后将Manifest Nothing提供给第一个方法?
我本来期望某种编译错误,告诉我我正在调用readValue一个没有Manifest或类似的参数化类型,这似乎更快失败.
举一个稍微简单的例子:
def getManifest[A: Manifest] = implicitly[Manifest[A]]
Run Code Online (Sandbox Code Playgroud)
或等效的desugared版本:
def getManifest[A](implicit whatever: Manifest[A]) = whatever
Run Code Online (Sandbox Code Playgroud)
然后:
scala> def getIt[T]: Manifest[T] = getManifest
<console>:8: error: type mismatch;
found : Manifest[Nothing]
required: Manifest[T]
Note: Nothing <: T, but trait Manifest is invariant in type T.
You may wish to investigate a wildcard type such as `_ <: T`. (SLS 3.2.10)
def getIt[T]: Manifest[T] = getManifest
^
Run Code Online (Sandbox Code Playgroud)
发生的事情是,当编译器试图推断出类型参数时getManifest,有许多类型Manifest在范围内有实例,并且无法在它们之间进行选择,因此它采用默认选择,Nothing.
(您在运行时而不是编译时看到此错误,因为当您使用基于反射的方法进行序列化时会发生这种情况.)
我们可以添加一个上下文绑定:
def getIt[T: Manifest]: Manifest[T] = getManifest
Run Code Online (Sandbox Code Playgroud)
或者,等效地:
def getIt[T](implicit whatever: Manifest[T]): Manifest[T] = getManifest
Run Code Online (Sandbox Code Playgroud)
现在一切都很好 - Manifest范围内有一个最精确的实例,因此编译器可以(适当地)解析getManifestto 的类型参数T.
在以下示例中,您可以更加显着地看到这一点:
scala> trait Foo[A]
defined trait Foo
scala> def getFoo[A: Foo] = implicitly[Foo[A]]
getFoo: [A](implicit evidence$1: Foo[A])Foo[A]
scala> implicit object stringFoo extends Foo[String]
defined module stringFoo
scala> def getIt[T]: Foo[T] = getFoo
<console>:10: error: type mismatch;
found : Foo[String]
required: Foo[T]
def getIt[T]: Foo[T] = getFoo
^
Run Code Online (Sandbox Code Playgroud)
由于Foo范围(for String)中只有一个实例,编译器可以在解析类型参数时选择它getFoo,并且最终会出现不同的类型不匹配.
| 归档时间: |
|
| 查看次数: |
790 次 |
| 最近记录: |