Java 使用Jackson(反序列化)Scala案例类
我使用Jackson测试了Scala case类的序列化 反序列化test.javaJava 使用Jackson(反序列化)Scala案例类,java,json,scala,serialization,jackson,Java,Json,Scala,Serialization,Jackson,我使用Jackson测试了Scala case类的序列化 反序列化test.java public static void main(String[] args) throws Exception { // being lazy to catch-all final ObjectMapper mapper = new ObjectMapper(); final ByteArrayOutputStream stream = new Byt
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());
}
}
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 } """
}
Foo.scala
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());
}
}
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案例类 Jackson希望您的类是一个JavaBean,这意味着它希望该类的每个属性都有一个getX()和/或setX() 选项1 您可以使用注释在Scala中创建JavaBean类 范例
case class Person(
@BeanProperty val name: String,
@BeanProperty val age: Int,
@BeanProperty val hobbies: Option[String]
)
在这种情况下,val意味着只定义了一个getter。如果需要设置器进行反序列化,则将属性定义为var
选项2
虽然选项1可以工作,但如果您真的想使用Jackson,有一些包装器允许它处理Scala类,这可能是一种更好的方法。我没有使用它,因为我只是使用内置的Json库来播放 找到了一个适用于jackson和scala案例类的解决方案 我为jackson使用了一个scala模块-jackson模块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字符串
转换为案例类
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字符串转换为Case类/对象
Case类/对象转换为JSON字符串
- 请找到一个工作和详细的答案,我已经使用泛型提供
- 与Jackson相比,对对象进行反序列化要容易得多。下面是一个例子:
案例类城市(名称:String,活动:String,纬度:Double)
隐式val cityRW=upickle.default.macroRW[City]
val str=“”{“名称”:“巴塞罗那”,“娱乐活动”:“吃塔帕斯”,“纬度”:41.39}”
val barcelona=upickle.default.read[City](str)
杰克逊的解决方案更加冗长。请参阅此处了解有关此方法的更多信息。如果您使用的是Spring MVC,请使用如下配置:
import java.util.List
@配置
@EnableWebMvc
类WebConfig扩展了WebMVCConfiguer{
覆盖def configureMessageConverters(转换器:列表[HttpMessageConverter[\u]]):单位={
val conv=新映射Jackson2HttpMessageConverter();
val mapper=JsonMapper.builder()
.addModule(DefaultScalaModule)
.build();
conv.setObjectMapper(映射器);
转换器。添加(conv);
}
}
然后,序列化/反序列化纯case类和集合类型将按预期工作。Jackson有几个很好的Scala包装器;你至少应该考虑使用其中一个。Play json恰好是我使用的。好的方法(IMO)使用基于类型类的反序列化,您可以向case类的伴生对象添加成员,告诉它如何来回映射到JSON,并提供很好的习惯用法。您的解决方案没有涉及“嗜好:选项[String]”属性,我认为他的部分问题在于将json字符串属性作为选项[String]处理。Jackson需要知道如何将选项[String]解释为Some[String]或noneer注意:1)@JsonProperty在case类上是不必要的,特别是当属性名与字段名相同时。2) 您应该尝试使用与jackson core相同版本的jackson module scala。3) Jackson 2.0被重新打包为com.fasterxml,但在其他方面的效果与Jackson 1.0一样好(如果不是更好的话)。对于选项1,只需输入一个小的输入参数
name
,而不是name
,您需要在case类中添加一个无参数构造函数,如下所示:{def this()=this(“,0,None)}
既然从最初的问题开始已经五年了,我应该补充一点,这个答案以前可能是有效的,但是我现在使用Scala2.13.4
和jackson模块Scala 2.11.3
和jackson数据格式csv 2.11.3
,这是必要的,否则我会得到消息“无法构造`Person`的实例(不存在像默认构造函数那样的创建者)”