简体   繁体   English

序列化Scala用例类并在Java中反序列化它们

[英]Serialize Scala case classes and deserialize them in Java

I need to serialize a hierarchy of scala case classes as JSON to store them in a db. 我需要将scala case类的层次结构序列化为JSON,以将它们存储在db中。 I am currently using json4s and it works quite well. 我当前正在使用json4s,并且效果很好。 However, when deserializing in Java jackson requires me to have an empty constructor for case classes (which doesn't exist). 但是,在Java中反序列化时,杰克逊要求我为case类提供一个空的构造函数(不存在)。

The other option I tried is to define a deserialization function in my scala library, import it in the Java code and run it at runtime to read a string and build the relative class of the hierarchy. 我尝试的另一个选项是在我的Scala库中定义反序列化函数,将其导入Java代码中,然后在运行时运行它以读取字符串并构建层次结构的相对类。 In this way I am able to reconstruct the object in the Java world. 通过这种方式,我可以在Java世界中重建对象。 Afterwards, I want to return this object: if I return it as an object I am not able to serialize it correctly (jackson uses different logic than json4s); 之后,我想返回该对象:如果将其作为对象返回,则无法正确序列化(杰克逊使用的逻辑与json4s不同); if I use my scala function, I am able to create a string and return it, but for some reasons it gets returned escaped: 如果使用我的scala函数,我可以创建一个字符串并返回它,但是由于某些原因,它逃脱了返回:

"{\"jsonClass\":\"TimeExtremaConfig\",\"name\":\"payment_first_seen_hotel_id_on_agency\"}

Is there a better way to approach this problem? 有没有更好的方法来解决此问题? Either finding a way to deserialize case classes and use jackson all over the place or avoiding the escaping in the second option 寻找一种方法来反序列化案例类并在各处使用杰克逊,或者避免在第二种方法中进行转义

Have you tried using the Jackson Scala Module ? 您是否尝试过使用Jackson Scala模块

It does a pretty good job of handling instances of case classes within Scala : Scala中处理案例类实例的工作非常出色:

case class Parent(name: String, children: List[Child])
case class Child(name: String)

def test(): Unit = {

  val mapper = new ObjectMapper() with ScalaObjectMapper
  mapper.registerModule(DefaultScalaModule)

  val bobString = mapper.writeValueAsString(Parent("Bob", List(Child("Alice"))))
  println(s"String: $bobString")

  val bob = mapper.readValue[Parent](bobString)
  println(s"Object: $bob")
}

Ouputs:

String: {"name":"Bob","children":[{"name":"Alice"}]}
Object: Parent(Bob,List(Child(Alice)))

And you can effectively do the same from the Java side (please excuse the collection interop): 而且您可以从Java方面有效地做同样的事情(请原谅集合互操作):

final ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new DefaultScalaModule());

final Child alice = new Child("Alice");
final List<Child> children = new ArrayList<>();
children.add(alice);

final String bobString = mapper.writeValueAsString(
  new Parent("Bob", 
    JavaConversions.asScalaBuffer(children).toList()));
System.out.println(bobString);

final Parent bob = mapper.readValue(bobString, Parent.class);
System.out.println(bob);

it sounds like you have control over the scala library, how about trying the JsonCreator annotation with the case class? 听起来您已经控制了scala库,如何通过case类尝试JsonCreator批注? Must we use @JsonProperty in Scala case classes? 我们必须在Scala案例类中使用@JsonProperty吗?

While it doesn't look great, it tells jackson to use the parametrized constructor instead of looking for the default constructor. 虽然看起来不太好,但它告诉杰克逊使用参数化的构造函数,而不是寻找默认的构造函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM