使用Jackson来(De) – 将Scala案例类序列化
我使用Jackson测试了Scala案例类的序列化。
DeserializeTest.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
时,抛出了exception:
[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) )
我如何(de)-serial化Scala案例类?
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将仅表示定义了一个吸气剂。 如果需要用于反序列化的setter,则将属性定义为var。
选项2
虽然选项1可以工作,但如果你真的想使用Jackson,那么有一些包装器可以处理Scala类,比如FasterXML的scala模块 ,这可能是一种更好的方法。 我没有使用它,因为我刚刚使用内置的Json库来播放。
找到了一个适用于jackson和scala案例类的解决方案。
我使用了一个scala模块用于jackson – 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。
根据Priyank Desai的回答,我创建了一个将json string
转换为case class
的generics函数
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.scala.DefaultScalaModule import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper def jsonToType[T](json:String)(implicit m: Manifest[T]) :T = { val objectMapper = new ObjectMapper() with ScalaObjectMapper objectMapper.registerModule(DefaultScalaModule) objectMapper.readValue[T](json) }
用法:
case class Person(@JsonProperty("name") Name:String, @JsonProperty("age") Age:Int) val personName = jsonToType[Person](jsonString).name