我正在尝试使用Jackson ObjectMapper将Scala类序列化/反序列化为JSON。序列化工作正常,但是我遇到了试图重新读回JSON的类型异常。我通过添加适当的批注来修复了大多数异常,但是它不适用于我的Map成员...似乎杰克逊正在尝试处理密钥JSON对象中作为类中的属性,而不是映射中的键。 (我相信这与其他类似问题不同,因为他们直接在地图内容上调用了readValue
。)
这是我的ObjectMapper设置:
val mapper = new ObjectMapper() with ScalaObjectMapper
mapper.registerModule(DefaultScalaModule)
这是我带注释的类和成员的样子:
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
class MyClass extends Serializable {
@JsonDeserialize(
as = classOf[mutable.HashMap[String, Long]],
keyAs = classOf[java.lang.String],
contentAs = classOf[java.lang.Long]
)
val counts = mutable.Map.empty[String, Long]
}
如果我给它一些JSON,如:
{"counts":{"foo":1,"bar":2}}
并用mapper.readValue[MyClass](jsonString)
我遇到像UnrecognizedPropertyException: Unrecognized field "foo" (class mutable.HashMap), not marked as ignorable
这样的异常。
我尝试将DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
添加到我的映射器配置中,但是在这种情况下似乎没有任何作用,而且我不确定是否需要这种全局设置。
我如何说服Jackson将字符串“ foo”和“ bar”当作地图成员字段中的键而不是HashMap类中的属性?自动写出来似乎做对了。
还值得注意的是:在对临时文件或字符串变量进行快速出入单元测试中,反序列化似乎可以正常工作,但是当我尝试运行整个应用程序并读取其先前编写的JSON时,反序列化似乎效果很好。据我所知,它正在进行相同的readValue
调用,我不知道为什么它在测试中似乎可以正常工作。
答案 0 :(得分:0)
我做了一个简单的测试,像这样:
case class TestClass (counts: mutable.HashMap[String, Long])
我将其转换为:
val objectMapper = new ObjectMapper() with ScalaObjectMapper
objectMapper.registerModule(DefaultScalaModule)
val r3 = objectMapper.readValue("{\"counts\":{\"foo\":1,\"bar\":2}}", classOf[TestClass])
显然,它对我有用。可能与您使用的Jackson或Scala版本有关。例如,您尝试过其他版本的Jackson吗?
答案 1 :(得分:0)
我的问题是由于没有在我的mapper配置单例中使用链接而导致的竞争状况。
我的旧代码更像这样:
private var mapper: ObjectMapper with ScalaObjectMapper = _
def getMapper: ObjectMapper with ScalaObjectMapper = {
if (mapper == null) {
mapper = new ObjectMapper() with ScalaObjectMapper
mapper.registerModule(DefaultScalaModule)
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
}
mapper
}
如您所见,如果一个线程初始化了映射器,但尚未禁用未知属性失败,则另一个线程可能返回并使用尚未设置该标志的映射器,这解释了为什么我看到了仅在某些时间出现错误。
正确的代码使用链接,以便使用所有配置来设置映射器单例:
private var mapper: ObjectMapper = _
def getMapper: ObjectMapper = {
if (mapper == null) {
mapper = new ObjectMapper()
.registerModule(DefaultScalaModule)
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
}
mapper
}
(我还删除了实验性ScalaObjectMapper
混入。)
答案 2 :(得分:-1)
尝试jsoniter-scala,您将享受到这些天来如何使用Scala轻松,安全,高效地解析和序列化JSON:https://github.com/plokhotnyuk/jsoniter-scala
它的关键功能之一是能够在编译时生成编解码器,甚至可以打印其源代码。您将不会遇到任何会影响代码的运行时魔术,例如反射或字节代码替换。