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」インスタンスに作成するようにJacksonに指示する方法はありますか?クラス'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

残念ながら、適切に実装できない機能の特定の組み合わせがあります。これはそのうちの 1 つかもしれません (100% 確信があるわけではありません。Jackson github の問題または Jira について、Bug/RFE を気軽に提出してください)。これは、方法@JsonUnwrapped@JsonCreator両方がデータの潜在的な並べ替えを必要とするためです。また、実際のインスタンスを作成する順序が複雑になるためです。したがって、概念的にはこれは可能ですが、実装が難しい場合があります。

@JsonUnwrappedJackson 2.0 について:ハンドリングのいくつかの部分が改善されているため、1.9 よりも確実に試してみます。そこに修正/改善が追加されます。1.9 ブランチでは、可能な限りバグ修正がバックポートされますが、新しい機能は追加されません。

于 2012-07-24T17:03:47.600 に答える