web-dev-qa-db-ja.com

ジャクソン:プロパティが欠落している場合はどうなりますか?

@JsonPropertyを使用してコンストラクターパラメーターに注釈を付けたが、Jsonがそのプロパティを指定していない場合はどうなりますか。コンストラクターはどの値を取得しますか?

Null値を持つプロパティとJSONに存在しないプロパティを区別するにはどうすればよいですか?

57
Gili

Programmer Bruce および StaxMan による優れた回答の要約:

  1. コンストラクターによって参照される欠落しているプロパティーには、デフォルト値 Javaの定義どおり が割り当てられます。

  2. セッターメソッドを使用して、暗黙的または明示的に設定されているプロパティを区別できます。セッターメソッドは、明示的な値を持つプロパティに対してのみ呼び出されます。セッターメソッドは、ブールフラグ(isValueSetなど)を使用してプロパティが明示的に設定されたかどうかを追跡できます。

44
Gili

@JsonPropertyを使用してコンストラクターパラメーターに注釈を付けたが、Jsonがそのプロパティを指定しなかった場合はどうなりますか。コンストラクターはどのような値を取得しますか?

このような質問については、サンプルプログラムを作成して、何が起こるかを確認したいだけです。

以下はそのようなサンプルプログラムです。

import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.ObjectMapper;

public class JacksonFoo
{
  public static void main(String[] args) throws Exception
  {
    ObjectMapper mapper = new ObjectMapper();

    // {"name":"Fred","id":42}
    String jsonInput1 = "{\"name\":\"Fred\",\"id\":42}";
    Bar bar1 = mapper.readValue(jsonInput1, Bar.class);
    System.out.println(bar1);
    // output: 
    // Bar: name=Fred, id=42

    // {"name":"James"}
    String jsonInput2 = "{\"name\":\"James\"}";
    Bar bar2 = mapper.readValue(jsonInput2, Bar.class);
    System.out.println(bar2);
    // output:
    // Bar: name=James, id=0

    // {"id":7}
    String jsonInput3 = "{\"id\":7}";
    Bar bar3 = mapper.readValue(jsonInput3, Bar.class);
    System.out.println(bar3);
    // output:
    // Bar: name=null, id=7
  }
}

class Bar
{
  private String name = "BLANK";
  private int id = -1;

  Bar(@JsonProperty("name") String n, @JsonProperty("id") int i)
  {
    name = n;
    id = i;
  }

  @Override
  public String toString()
  {
    return String.format("Bar: name=%s, id=%d", name, id);
  }
}

その結果、コンストラクターにはデータ型のデフォルト値が渡されます。

Null値を持つプロパティとJSONに存在しないプロパティを区別するにはどうすればよいですか?

単純なアプローチの1つは、逆シリアル化処理後にデフォルト値をチェックすることです。JSONに要素が存在するがnull値を持っている場合、null値を使用して、対応するJavaフィールド例:

import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.annotate.JsonMethod;
import org.codehaus.jackson.map.ObjectMapper;

public class JacksonFooToo
{
  public static void main(String[] args) throws Exception
  {
    ObjectMapper mapper = new ObjectMapper().setVisibility(JsonMethod.FIELD, Visibility.ANY);

    // {"name":null,"id":99}
    String jsonInput1 = "{\"name\":null,\"id\":99}";
    BarToo barToo1 = mapper.readValue(jsonInput1, BarToo.class);
    System.out.println(barToo1);
    // output:
    // BarToo: name=null, id=99

    // {"id":99}
    String jsonInput2 = "{\"id\":99}";
    BarToo barToo2 = mapper.readValue(jsonInput2, BarToo.class);
    System.out.println(barToo2);
    // output:
    // BarToo: name=BLANK, id=99

    // Interrogate barToo1 and barToo2 for 
    // the current value of the name field.
    // If it's null, then it was null in the JSON.
    // If it's BLANK, then it was missing in the JSON.
  }
}

class BarToo
{
  String name = "BLANK";
  int id = -1;

  @Override
  public String toString()
  {
    return String.format("BarToo: name=%s, id=%d", name, id);
  }
}

別のアプローチは、必要なJSON要素をチェックするカスタムデシリアライザーを実装することです。そしてさらに別のアプローチは、 http://jira.codehaus.org/browse/JACKSON にあるジャクソンプロジェクトで拡張リクエストを記録することです。

35

@Programmer_Bruceの答えで説明されているコンストラクターの動作に加えて、null値と欠損値を区別する1つの方法は、セッターを定義することです:setterは明示的なnull値でのみ呼び出されます。設定された値を追跡する場合、カスタムセッターはプライベートブールフラグ(「isValueSet」など)を設定できます。

フィールドとセッターの両方が存在する場合、セッターはフィールドよりも優先されるため、この方法でも動作を「オーバーライド」できます。

12
StaxMan

私は、Optionクラスのスタイルで何かを使用することを考えています。Nothingオブジェクトは、そのような値があるかどうかを教えてくれます。ジャクソン(ScalaなどではなくJava)でこのようなことをした人はいますか?

3
Roberto

(私のスレッドは、OPの質問に答えていない場合でも、Google経由でこのスレッドを見つける一部の人々にとって役立つかもしれません)
省略可能なプリミティブ型を扱っており、他の回答で説明されているようなセッターを使用したくない場合(たとえば、フィールドをファイナルにする場合)、ボックスオブジェクトを使用できます。

public class Foo {
    private final int number;
    public Foo(@JsonProperty Integer number) {
        if (number == null) {
            this.number = 42; // some default value
        } else {
            this.number = number;
        }
    }
}

jSONにnullが実際に含まれている場合、これは機能しませんが、プリミティブのみが含まれているか、存在しないことがわかっている場合は十分です。

0
Felk

別のオプションは、validateシリアル化解除後のオブジェクトを手動で、またはJava Bean検証、またはスプリングを使用している場合はスプリング検証サポートなどのフレームワークを介して).

0
abdel