使用 Jackson 对 Scala Case 类进行(反)序列化

2022-09-03 03:30:56

我使用 Jackson 测试了 Scala 案例类的序列化。

反序列化测试.java

    public static void main(String[] args) throws Exception { // being lazy to catch-all

        final ObjectMapper mapper          = new ObjectMapper();
        final ByteArrayOutputStream stream = new ByteArrayOutputStream();

        mapper.writeValue(stream, p.Foo.personInstance());

        System.out.println("result:" +  stream.toString());
    }
}

Foo.scala

object Foo {
  case class Person(name: String, age: Int, hobbies: Option[String])
  val personInstance = Person("foo", 555, Some("things"))
  val PERSON_JSON = """ { "name": "Foo", "age": 555 } """
}

当我运行上面的Java类时,抛出了一个异常:main

[error] Exception in thread "main" org.codehaus.jackson.map.JsonMappingException: 
 No serializer found for class p.Foo$Person and no properties discovered 
 to create BeanSerializer (to avoid exception, 
 disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) )

如何(反)序列化 Scala 案例类?


答案 1

Jackson 期望你的类是 JavaBean,这意味着它期望该类的每个属性都有一个 getX() 和/或 setX()。

备选案文1

您可以使用注释BeanProperty在Scala中创建JavaBean类。

case class Person(
   @BeanProperty val name: String, 
   @BeanProperty val age: Int, 
   @BeanProperty val hobbies: Option[String]
)

在这种情况下,val 将意味着只定义了一个 getter。如果需要用于反序列化的 setter,请将属性定义为 var。

备选案文2

虽然选项1可以工作,但如果你真的想使用Jackson,有一些包装器允许它处理Scala类,如FasterXML的scala模块,这可能是一个更好的方法。我没有使用它,因为我刚刚使用内置的Json库来玩。


答案 2

找到了一个适用于 jackson 和 scala case 类的解决方案。

我为jackson使用了一个scala模块 - jackson-module-scala。

libraryDependencies ++= Seq(
 "com.fasterxml.jackson.core" % "jackson-databind" % "2.5.3",
 "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.2.2"
)

我必须用@JsonProperty在我的案例类中注释字段。

这是我的 case 类的样子:

case class Person(@JsonProperty("FName") FName: String, @JsonProperty("LName") LName: String)

这就是我反序列化的方式:

val objectMapper = new ObjectMapper() with ScalaObjectMapper
objectMapper.registerModule(DefaultScalaModule)
val str = """{"FName":"Mad", "LName": "Max"}"""
val name:Person = objectMapper.readValue[Person](str)

序列化更容易:

val out = new ByteArrayOutputStream()
objectMapper.writeValue(out, name)
val json = out.toString

想澄清我正在使用

com.fasterxml.jackson.databind.ObjectMapper

在问题中,他似乎正在使用

org.codehaus.jackson.map.ObjectMapper 

这不适用于ScalaObjectMapper。