【scala】Jackson正反序列化解决继承、多态

父类上注明,在需要多态属性上使用jackson注解。多层父类如果使用到,如 new TypeReference[List[...]] {}。每层都需要添加注解。

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "clz", visible = true)
@JsonSubTypes(value = Array( ... )

原理就:反序列化时候使用类中已有的clz属性值。判定类型并反序列化。

举个例子:
定义类:

import com.fasterxml.jackson.annotation.{JsonSubTypes, JsonTypeInfo}
import com.fasterxml.jackson.annotation.JsonSubTypes.Type

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "clz", visible = true)
@JsonSubTypes(value = Array(
  new Type(value = classOf[Triangle], name = "Triangle")
  , new Type(value = classOf[Rectangle], name = "Rectangle")
  , new Type(value = classOf[Circle], name = "Circle")
))
trait Shape {
  def name: String  // 形状名称
}

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "clz", visible = true)
@JsonSubTypes(value = Array(
  new Type(value = classOf[Triangle], name = "Triangle")
  , new Type(value = classOf[Rectangle], name = "Rectangle")
))
trait Polygon extends Shape {
  def edges: Int
  // 多边形
}

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "clz", visible = true)
@JsonSubTypes(value = Array(
  new Type(value = classOf[Circle], name = "Circle")
))
trait curve extends Shape {
// 曲线
}

// 三角形
case class Triangle(var name: String
                    , var edges: Int
                   ) extends Polygon with Product with Serializable {
  val clz: String = "Triangle"
}

// 长方形
case class Rectangle(var name: String
                     , var edges: Int
                    ) extends Polygon with Product with Serializable {
  val clz: String = "Rectangle"
}
// 圆形
case class Circle(var name: String
                  , var edges: Int
                  , var diameter: Int
                 ) extends curve with Product with Serializable {
  val clz: String = "Circle"
}

测试


import com.fasterxml.jackson.core.`type`.TypeReference
import com.fasterxml.jackson.databind.{DeserializationFeature, ObjectMapper}
import com.fasterxml.jackson.databind.json.JsonMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import org.scalatest.funsuite.AnyFunSuite

class ShapeTest extends AnyFunSuite {
  
  def getMapper: ObjectMapper = {
    var mapper: ObjectMapper = JsonMapper.builder()
      .addModule(DefaultScalaModule)
      .build()
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    mapper
  }

  val mapper = getMapper

  test("serde") {

    val t1 = Triangle("right triangle", 3)
    val r1 = Rectangle("square", 4)
    val c1 = Circle("circle", 0, 10)
    val ls1: List[Shape] = List(t1, c1)
    val str1 = mapper.writeValueAsString(ls1)
    println(str1) // [{"name":"right triangle","edges":3,"clz":"Triangle"},{"name":"circle","edges":0,"diameter":10,"clz":"Circle"}]
    val ls2 = mapper.readValue(str1, new TypeReference[List[Shape]] {})
    println(ls2) // List(Triangle(right triangle,3), Circle(circle,0,10))


    val ls3: List[Polygon] = List(t1, r1)
    val str2 = mapper.writeValueAsString(ls3)
    println(str2) // [{"name":"right triangle","edges":3,"clz":"Triangle"},{"name":"square","edges":4,"clz":"Rectangle"}]
    val ls4 = mapper.readValue(str2, new TypeReference[List[Polygon]] {})
    println(ls4) // List(Triangle(right triangle,3), Rectangle(square,4))
  }
}

结果:
(1)多层集成也没问题。最终都会反序列化为case class定义的clz类型。
(2)自定义的clz属性保证类型不会被更改。

参考文章1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值