首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用与Jerkson一起的非默认构造函数?

使用与Jerkson一起的非默认构造函数?
EN

Stack Overflow用户
提问于 2012-08-24 02:42:24
回答 1查看 366关注 0票数 0

我需要序列化/反序列化一个Scala类,其结构如下所示:

代码语言:javascript
复制
@JsonIgnoreProperties(ignoreUnknown = true, value = Array("body"))
case class Example(body: Array[Byte]) {

    lazy val isNativeText = bodyIsNativeText
    lazy val textEncodedBody = (if (isNativeText) new String(body, "UTF-8") else Base64.encode(body))

    def this(isNativeText: Boolean, textEncodedBody: String) = this((if(isNativeText) str.getBytes("UTF-8") else Base64.decode(textEncodedBody)))

    def bodyIsNativeText: Boolean = // determine if the body was natively a string or not

}

它的主要成员是一个字节数组,它可能表示一个UTF-8编码的文本字符串,但可能不是。主构造函数接受一个字节数组,但是有一个备用构造函数,它接受一个带有标志的字符串,指示该字符串是base64编码的二进制数据,还是我们要存储的实际本机文本。

为了序列化到JSON对象,如果主体是本机文本,我希望将其存储为本机字符串,而不是base64 64编码的字符串。这就是为什么我使用@JsonIgnoreProperties不包含body属性,而是有一个在JSON中得到回响的textEncodedBody

当我试图像这样反序列化它时,问题就出现了:

val e = Json.parse[Example]("""{'isNativeText': true, 'textEncodedBody': 'hello'}""")

我收到以下错误:

com.codahale.jerkson.ParsingException:无效JSON。需要身体,但找到了isNativeText,textEncodedBody。

显然,我有一个将work...it不是默认构造函数的构造函数。我如何强迫Jerkson使用这个非默认的构造函数?

编辑:我尝试同时使用@JsonProperty@JsonCreator注解,但是jerkson似乎忽略了这两种注释。

EDIT2:纵观jerkson案例类序列化源代码,它看起来就像一个case类方法,其名称与其字段的名称相同,它将以@JsonProperty的方式使用--即作为JSON。如果我能这样做,它就能解决我的问题。由于对Scala不太熟悉,我不知道如何做到这一点;一个案例类是否有可能拥有一个与其字段名称相同的用户定义方法?

作为参考,下面的代码让我得出这样的结论.

代码语言:javascript
复制
private val methods = klass.getDeclaredMethods
                                .filter { _.getParameterTypes.isEmpty }
                                .map { m => m.getName -> m }.toMap

  def serialize(value: A, json: JsonGenerator, provider: SerializerProvider) {
    json.writeStartObject()
    for (field <- nonIgnoredFields) {
      val methodOpt = methods.get(field.getName)
      val fieldValue: Object = methodOpt.map { _.invoke(value) }.getOrElse(field.get(value))
      if (fieldValue != None) {
        val fieldName = methodOpt.map { _.getName }.getOrElse(field.getName)
        provider.defaultSerializeField(if (isSnakeCase) snakeCase(fieldName) else fieldName, fieldValue, json)
      }
    }
    json.writeEndObject()
  }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-08-24 10:25:29

如果我错了,请纠正我,但是看起来Jackson/Jerkson不支持任意嵌套的JSON。有一个使用嵌套的wiki上的例子,但它看起来目标类必须有对应于嵌套JSON的嵌套类。

无论如何,如果您没有在case类中使用嵌套,那么只需声明第二个case类和几个隐式转换就可以了:

代码语言:javascript
复制
case class Example(body: Array[Byte]) {
    // Note that you can just inline the body of bodyIsNativeText here
    lazy val isNativeText: Boolean = // determine if the body was natively a string or not
}

case class ExampleRaw(isNativeText: Boolean, textEncodedBody: String)

implicit def exampleToExampleRaw(ex: Example) = ExampleRaw(
    ex.isNativeText,
    if (ex.isNativeText) new String(ex.body, "UTF-8")
    else Base64.encode(ex.body)
)

implicit def exampleRawToExample(raw: ExampleRaw) = Example(
    if (raw.isNativeText) raw.textEncodedBody.getBytes("UTF-8")
    else Base64.decode(textEncodedBody)
)

现在您应该能够这样做了:

代码语言:javascript
复制
val e: Example = Json.parse[ExampleRaw](
  """{'isNativeText': true, 'textEncodedBody': 'hello'}"""
)

您可以保留添加的原始方法和注释,以使JSON生成继续使用Example类型,或者只需使用强制转换:

代码语言:javascript
复制
generate(Example(data): ExampleRaw)

更新:

为了帮助捕获错误,您可能也需要这样做:

代码语言:javascript
复制
case class Example(body: Array[Byte]) {
    // Note that you can just inline the body of bodyIsNativeText here
    lazy val isNativeText: Boolean = // determine if the body was natively a string or not
    lazy val doNotSerialize: String = throw new Exception("Need to convert Example to ExampleRaw before serializing!")
}

如果您不小心将Example的实例而不是ExampleRaw传递给generate调用,则会引发异常。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12102550

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档