3

我对 Jackson 库(1.9 版)很陌生。我只用了几个星期才开始使用它,当它在 Java 中序列化和反序列化对象时,我发现它非常灵活且省时。

但是,我在将“平面” JSON 反序列化为一个由另一个组合的类时遇到了麻烦,而这两者都意味着是不可变的。

我的情况大致如下:

class Foo {

    private final String var1;

    Foo(String var1) {
            this.var1 = var1;
    }
    // getters omitted
}

class A {
    private final Foo foo;
    private final String var2;

    A(/* @JsonUnwrapped doesn't work here */ Foo foo, String var2) {
            this.foo = foo;
            this.var2 = var2;
    }

    @JsonUnwrapped
    Foo getFoo() {
        return foo;
    }

    String getVar2() {
        return var2;
    }
}

class B extends Foo {
    private final String var2;

    B(String var1, String var2) {
            super(var1);
            this.var2 = var2;
    }
    // getters omitted
}

而要反序列化的 JSON 是这样的:

{ "var1" : "some_value", "var2" : "some_other_value" }

问题是:是否有基于注释的方式(因此,无需使用自定义反序列化器)来告诉杰克逊将给定的 JSON 组合到“A”实例?我已经尝试在类“A”构造函数中为 Foo 参数使用 @JsonUnwrapped 属性,但它在多参数构造函数中不受支持,因为它需要 JsonProperty 才能工作(这没有意义,因为实际上没有这些项目的单一属性)。相反,序列化可以完美地使用这种模式。

它也可以通过使用单独的设置器与非不可变类一起使用,但我想知道是否有办法通过仅使用构造函数(或生成器,这在现实中是有意义的)来做同样的事情比示例中的要多得多)。

同样的方法显然适用于从“Foo”继承的“B”类。

提前致谢。

4

2 回答 2

5

请注意,Jackson 的反序列化处理不一定尊重final字段的不变性。因此,一种简单的方法是只提供无参数(私有)构造函数供 Jackson 使用。

import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonFoo
{
  public static void main(String[] args) throws Exception
  {
    // {"var1":"some_value", "var2":"some_other_value"}
    String jsonInput = "{\"var1\":\"some_value\", \"var2\":\"some_other_value\"}";

    ObjectMapper mapper = new ObjectMapper().setVisibility(PropertyAccessor.FIELD, Visibility.ANY);

    A a = new A(new Foo("some_value"), "some_other_value");
    System.out.println(mapper.writeValueAsString(a));
    // output: {"var1":"some_value","var2":"some_other_value"}

    A aCopy = mapper.readValue(jsonInput, A.class);
    System.out.println(mapper.writeValueAsString(aCopy));
    // output: {"var1":"some_value","var2":"some_other_value"}
  }
}

class Foo
{
  private final String var1;

  Foo(String var1) {this.var1 = var1;}

  private Foo() {this.var1 = null;}
}

class A
{
  @JsonUnwrapped
  private final Foo foo;
  private final String var2;

  A(Foo foo, String var2)
  {
    this.foo = foo;
    this.var2 = var2;
  }

  private A()
  {
    this.foo = null;
    this.var2 = null;
  }
}

如果您真的不想提供这样的(额外的)构造函数,那么如果可以使用 设计类似的解决方案会很好@JsonCreator,但我无法让这样的事情发挥作用。因此,我建议在https://github.com/FasterXML/jackson-core/issues记录一个增强请求,也许是为了更好地支持同时使用和注释@JsonCreator参数。@JsonUnwrapped@JsonProperty

于 2012-07-23T22:13:51.453 回答
0

不幸的是,某些功能组合可能无法正确实现;这可能是其中之一(我不是 100% 确定:请随时为 Jackson github 问题或 Jira 提交 Bug/RFE)。这是因为方式@JsonUnwrapped@JsonCreator两者都需要对数据进行潜在的重新排序;也因为创建实际实例的顺序使事情变得复杂。因此,虽然从概念上讲这应该是可能的,但可能存在实施困难。

至于 Jackson 2.0:我肯定会在 1.9 上尝试,因为某些部分的@JsonUnwrapped处理得到了改进;并且将在那里添加任何修复/改进。1.9 分支将尽可能向后移植错误修复,但不会添加新功能。

于 2012-07-24T17:03:47.600 回答