2017-09-25 9 views
0

JsonArrayをブール値にデシリアライズする必要があります。配列が存在し、空でない場合、値は "true"に設定する必要があります。 問題は、私のカスタムデシリアライザは、機能している間に残りのフィールドのデシリアライズを解除することです。それらはnullに設定されています。Jacksonカスタムデシリアライザが他のフィールドのデシリアライズを解除する

オブジェクト:

private static class TestObject { 
    private String name; 

    @JsonProperty("arr") 
    @JsonDeserialize(using = Deserializer.class) 
    private Boolean exists = null; 

    private Integer logins; 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public Boolean getExists() { 
     return exists; 
    } 

    public void setExists(boolean exists) { 
     this.exists = exists; 
    } 

    public Integer getLogins() { 
     return logins; 
    } 

    public void setLogins(Integer logins) { 
     this.logins = logins; 
    } 

    @Override 
    public String toString() { 
     return "TestObject{" + 
       "name='" + name + '\'' + 
       ", exists=" + exists + 
       ", logins=" + logins + 
       '}'; 
    } 
} 

デシリアライザ:

public class Deserializer extends JsonDeserializer<Boolean> { 
    @Override 
    public Boolean deserialize(JsonParser jp, DeserializationContext ctxt) 
     throws IOException { 
     if (jp.getCurrentToken() == JsonToken.START_ARRAY) { 
      return true; 
     } 
     return false; 
    } 
} 

テスト

@Test 
public void test() throws JsonParseException, IOException { 
    Boolean result = deserialize(); 
} 

private Boolean deserialize() throws IOException, JsonParseException, 
     JsonProcessingException { 
    TestObject testObject = mapper.readValue("{\n" + 
        " \"arr\": [\n" + 
        "  {\"value\": \"New\"}\n" + 
        " ],\n" + 
        " \"name\": \"name\",\n" + 
        " \"logins\": 36" + 
        "}", 
        TestObject.class); 

    System.out.println(testObject.toString()); 

    return testObject.getExists(); 
} 

私は "ARR" のアレイを削除するか、JSONの一番下に移動し、すべての罰金場合。私がトップに残したら - TestObject{name='null', exists=true, logins=null}

同様の質問(Jackson Custom Deserializer breaks default ones)がありましたが、残念ながらゼロの回答があります。 Jsonを再配置するとコードが正常に動作するので、カスタムデシリアライザがすべてのフィールドで使用されているのではなく、Jacksonがカスタムデシリアライザを実行するときに逆シリアル化を停止します。

+1

私の提案は、配列をブール値にデシリアライズしないことです。配列をリスト/リスト/セットにデシリアライズし、 'getExists'が' arr!= null'かそのようなものを返すようにします。 – Paul

+0

@Paulこれは実際には、アイデアのおかげで、何とか私はそれを考えていない動作します。問題は、それがちょっと醜く、あいまいに見えますが、それ以外の方法がなければ、私はそれをそうするでしょう。 –

+0

場合によっては、2つの醜い解決策のよりきれいなものを選択する必要があります:)私は私が助けることができてうれしいです...私は答えを私のコメントにします。 – Paul

答えて

1

あなたのデシリアライザは、配列の内容に興味がないかもしれませんパーサ上の読み取りマークを前進させる必要があります。

@Override 
public Boolean deserialize(JsonParser jp, DeserializationContext ctxt) 
     throws IOException { 
    JsonNode node = jp.getCodec().readTree(jp); 
    return node.size() != 0; 
} 

コレクションのサイズではなく、コレクションの存在での決定:

あなたは、コレクションのサイズに応じて、一度arrの値を読んで決めることができました文字列化されたオブジェクトにarが含まれているか、またはDeserializer.deserialize()が決して実行されないため、すべてが必要です。この場合、プロパティexistnullになります。したがって、を表す唯一の可能なセマンティクスは存在しません。は空のコレクションです。

私は奇妙なことに、パーザを追跡するためにもう少し明示的な方法を試しました。実際の世界では、上記のバージョンが望ましいです。

@Override 
public Boolean deserialize(JsonParser jp, DeserializationContext ctxt) 
     throws IOException { 
    if (jp.currentToken() == JsonToken.START_ARRAY) { 
     jp.nextToken(); 
     int recursionLevel = 1; 
     while(recursionLevel > 0) { 
      switch (jp.currentToken()) { 
       case START_ARRAY: 
        // just in case of nested arrays 
        recursionLevel++; 
        break; 
       case END_ARRAY: 
        recursionLevel--; 
        break; 
      } 
      jp.nextToken(); 
     } 
     return true; 
    } 
    return false; 
} 
+0

これは適切な解決策です。 'JsonDeserializer' javadocには、ジャクソンが次の要素の作業を開始できるように、デシリアライザから戻る前に読み取りマークを次の要素に移動する必要があることが記載されています。 私の場合は配列なので、試したように一度動かすだけでは十分ではありませんでした。あなたが 'END_ARRAY'に達するまでに何度も動かなければなりません。 'readTree'は、私がjavadocから知る限り、配列全体を読み込み、ツリーを構築し、読み込みマーカーをすべて1つのパッケージに進めます。 –

1

私の提案は、配列をブール値にデシリアライズしないことです。アレイを配列/リスト/セットにデシリアライズし、getExistsに戻り、arr != nullなどを返します。例えば

、JSONは、あなたがこのようなルックスを逆シリアル化している場合:

{ 
    "arr": [{"value": "New"}], 
    "name": "name", 
    "logins": 36 
} 

は、このようなあなたのエンティティを書く:

private static class TestObject 
{ 
    private List<Map<String, String>> arr; 

    // other getters/setters removed for brevity 

    public boolean getExists() 
    { 
    return arr !=null && !arr.isEmpty(); 
    } 
} 
0

それを行うための第三の方法は実際にあります、それは私の場合に適合 - それが欠けていないときJsonArrayは常に少なくとも一つの要素が含まれますので、私が必要とするすべてが正しく読み取りマーカーを進め、その後trueを返すことです。あなたには、いくつかの追加作業のための配列の内容を必要としない場合を除き

if (jp.getCurrentToken().equals(JsonToken.START_ARRAY)) { 
    while (!jp.getCurrentToken().equals(JsonToken.END_ARRAY)){ 
     jp.nextToken(); 
    } 
} 
return true; 

は、単にマーカーを移動するカップルミリ秒速くreadTreeを超えています。

関連する問題