使用 Jackson 对 Scala 案例进行(反)序列化 Class
Using Jackson to (De)-serialize a Scala Case Class
我使用 Jackson 测试了 Scala 案例 class 的序列化。
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 } """
}
当我运行上面main
的Javaclass时,抛出异常:
[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 案例 classes?
Jackson 期望您的 class 是一个 JavaBean,这意味着它期望 class 每个 属性 都有一个 getX() and/or setX() .
选项 1
您可以使用注解 BeanProperty.
在 Scala 中创建 JavaBean classes
例子
case class Person(
@BeanProperty val name: String,
@BeanProperty val age: Int,
@BeanProperty val hobbies: Option[String]
)
在这种情况下,val 意味着只定义了 getter。如果你想要用于反序列化的设置器,你将属性定义为 var.
选项 2
虽然选项 1 可行,但如果您真的想使用 Jackson,可以使用包装器来处理像 FasterXML's scala module 这样的 Scala classes,这可能是更好的方法。我没有使用它,因为我只是使用内置的 Json 库来玩。
找到了适用于 jackson 和 scala 的解决方案 classes.
我为 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 在我的案例 class 中注释字段。
这是我的案例 class 的样子:
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
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
我创建了一个通用函数来转换 JSON String to Case Class/Object
和 Case Class/Object to JSON String
。
请找到我使用泛型提供的有效且详细的答案 here。
使用 upickle 比 Jackson 更容易反序列化对象。这是一个例子:
case class City(name: String, funActivity: String, latitude: Double)
implicit val cityRW = upickle.default.macroRW[City]
val str = """{"name":"Barcelona","funActivity":"Eat tapas","latitude":41.39}"""
val barcelona = upickle.default.read[City](str)
Jackson 的解决方案更加冗长。请参阅此 post 以了解有关此方法的更多信息。
如果您使用的是 Spring MVC,请使用如下配置:
import java.util.List
@Configuration
@EnableWebMvc
class WebConfig extends WebMvcConfigurer {
override def configureMessageConverters(converters: List[HttpMessageConverter[_]]): Unit = {
val conv = new MappingJackson2HttpMessageConverter();
val mapper = JsonMapper.builder()
.addModule(DefaultScalaModule)
.build();
conv.setObjectMapper(mapper);
converters.add(conv);
}
}
然后序列化/反序列化普通大小写 类 和集合类型将按预期工作。
我使用 Jackson 测试了 Scala 案例 class 的序列化。
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 } """
}
当我运行上面main
的Javaclass时,抛出异常:
[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 案例 classes?
Jackson 期望您的 class 是一个 JavaBean,这意味着它期望 class 每个 属性 都有一个 getX() and/or setX() .
选项 1
您可以使用注解 BeanProperty.
在 Scala 中创建 JavaBean classes例子
case class Person(
@BeanProperty val name: String,
@BeanProperty val age: Int,
@BeanProperty val hobbies: Option[String]
)
在这种情况下,val 意味着只定义了 getter。如果你想要用于反序列化的设置器,你将属性定义为 var.
选项 2
虽然选项 1 可行,但如果您真的想使用 Jackson,可以使用包装器来处理像 FasterXML's scala module 这样的 Scala classes,这可能是更好的方法。我没有使用它,因为我只是使用内置的 Json 库来玩。
找到了适用于 jackson 和 scala 的解决方案 classes.
我为 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 在我的案例 class 中注释字段。
这是我的案例 class 的样子:
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
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
我创建了一个通用函数来转换
JSON String to Case Class/Object
和Case Class/Object to JSON String
。请找到我使用泛型提供的有效且详细的答案 here。
使用 upickle 比 Jackson 更容易反序列化对象。这是一个例子:
case class City(name: String, funActivity: String, latitude: Double)
implicit val cityRW = upickle.default.macroRW[City]
val str = """{"name":"Barcelona","funActivity":"Eat tapas","latitude":41.39}"""
val barcelona = upickle.default.read[City](str)
Jackson 的解决方案更加冗长。请参阅此 post 以了解有关此方法的更多信息。
如果您使用的是 Spring MVC,请使用如下配置:
import java.util.List
@Configuration
@EnableWebMvc
class WebConfig extends WebMvcConfigurer {
override def configureMessageConverters(converters: List[HttpMessageConverter[_]]): Unit = {
val conv = new MappingJackson2HttpMessageConverter();
val mapper = JsonMapper.builder()
.addModule(DefaultScalaModule)
.build();
conv.setObjectMapper(mapper);
converters.add(conv);
}
}
然后序列化/反序列化普通大小写 类 和集合类型将按预期工作。