2016-05-08 8 views
1

でオブジェクトフィールドを間違えているが(の一部)サーバーの応答です:ジャクソンはここJsonTypeInfo.Id.NAME

{ 
    "ok": true, 
    "result": [ 
    { 
     "update_id": 489881706, 
     "message": { 
     "message_id": 5, 
     "from": { 
      "id": 188474643, 
      "first_name": "Alireza", 
      "last_name": "Mohamadi", 
      "username": "SuNova" 
     }, 
     "chat": { 
      "id": 188474643, 
      "first_name": "Alireza", 
      "last_name": "Mohamadi", 
      "username": "SuNova", 
      "type": "private" 
     }, 
     "date": 1462608191, 
     "text": "1" 
     } 
    } 
    ] 
} 

私は(コードを減らすためにトリム)のようなものですResultクラスを作成しました

public class Result 
{ 
    private TObject[] result; 
    private boolean ok; 

    public void setOk (boolean ok) //Rest of the code 

    public void setResult (TObject[] result) //... 

    public TObject[] getResult() //... 

    public boolean getOk() //... 

} 

そして私はTObjectと呼ばれるAbstract Classを持っている:

@JsonTypeInfo (use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT) 
@JsonSubTypes ({ 
     @JsonSubTypes.Type (name = "chat", value = Chat.class), 
     @JsonSubTypes.Type (name = "message", value = Message.class), 
     @JsonSubTypes.Type (name = "message_entity", value = MessageEntity.class), 
}) 
public abstract class TObject 
{ 
    int update_id; 
    boolean isUpdate; 

    public void setUpdate_id (int update_id) 
    { 
     this.update_id = update_id; 
     isUpdate = true; 
    } 
    public int getUpdate_id() 
    { 
     return update_id; 
    } 
} 

問題私はそれではなく、それはJsonTypeInfo.Id.NAMEとしてそれを認識してくれ示している、フィールドとしてupdate_idを認識していない

@JsonTypeInfo (use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT) 

を使用しているため、次のとおりです。

com.fasterxml.jackson.databind.JsonMappingException: Could not resolve type id 'update_id' into a subtype of [simple type, class org.telegram.objects.TObject]: known type ids = [TObject, chat, message, message_entity] 

今、私がジャクソンを伝えることができる方法を教えてくださいをフィールドTObjectとして解析し、それをJsonTypeInfo.Id.NAMEと混同しないでください。

+0

を追加します。今私はそれが曖昧ではないと思う。 –

答えて

1

ここで何が起こっているのか説明しようとします。あなたの注釈を見てみましょう。 ジャクソンはResultがこのフォーマットを持つことを期待しています。 { "ok": true, "result": []}とこの部分は正しいです。しかし

@JsonTypeInfo (use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT) 

そしてJsonTypeInfo.As.WRAPPER_OBJECTは、ジャクソンは結果の配列内{"chat":{}}または{"message":{}}または{"message_entity":{}}を見つけようとすることを意味しますTObjectています。ここではデモです:

{ "ok": true, "result": [{"chat":{}}, {"message_entity":{}}, {"message":{}}]} 

しかし、あなたはJSONを持っている最初の要素は、実際にupdate_idです。そしてjacksonはupdate_idタイプを見つけることができません。なぜなら彼は解析を中止して例外をスローします。あなたの質問に答えてください:how can I tell jackson to parse update_id as a field of TObject and don't confuse it as JsonTypeInfo.Id.NAMEjacksonはこの部分がTObjectであるとは考えていないので、とすることはできません。彼はjsonでTObjectを1層下げようとします。 jsonを変更できない場合は、クラスを完全に再構成するか、カスタムデシリアライザを作成する必要があります。

私はあなたがここに@JsonAnySetter@JsonAnyGetterを使用することができますどのように小さなデモ作っ:https://gist.github.com/varren/766b6830878c9e15c51784f57b303646#file-jsonanygetter-and-jsonanysetter

カスタムJsonDeserializerJsonSerializerを更新クラスのために、このデモでも動作することができます。 https://gist.github.com/varren/766b6830878c9e15c51784f57b303646#file-custom-deserializer-and-serializer

ちょうどすべてのTypeInfoの注釈を削除し、私は質問を編集して、それを改善してきました

private static class TObjectDeserializer extends JsonDeserializer<TObject> { 
    @Override 
    public TObject deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { 
     JsonNode tree = p.readValueAsTree(); 
     tree.get("chat"); 
     TObject resultValue = null; 
     if(tree.has("chat")){ 
      resultValue = p.getCodec().treeToValue(tree.get("chat"), Chat.class); 
     }else if(tree.has("message")){ 
      resultValue = p.getCodec().treeToValue(tree.get("message"),Message.class); 
     } else if(tree.has("message_entity")){ 
      resultValue = p.getCodec().treeToValue(tree.get("message_entity"),MessageEntity.class); 
     } 
     if(resultValue!= null) 
      resultValue.setUpdateId(tree.get("update_id").asInt()); 
     return resultValue; 
    } 
} 

private static class TObjectSerializer extends JsonSerializer<TObject> { 
    private static ObjectMapper mapper = new ObjectMapper(); 
    @Override 
    public void serialize(TObject value, JsonGenerator gen, SerializerProvider serializers) throws IOException { 
     gen.writeStartObject(); 

     gen.writeNumberField("update_id", value.getUpdateId()); 
     String key = ""; 

     if(value instanceof Chat){ 
      key = "chat"; 
     }else if(value instanceof Message){ 
      key = "message"; 
     } else if(value instanceof MessageEntity){ 
      key = "message_entity"; 
     } 
     gen.writeFieldName(key); 
     gen.writeRawValue(mapper.writeValueAsString(value)); 

     gen.writeEndObject(); 
    } 
} 
+0

ありがとう!私はあなたの完全な答えを読むのを楽しんでいます。それは通常の答えではなく、もっと講義に似ているので、私はあらゆる側面を取って答えとしてマークします。 とにかく質問があります。 1:なぜ '@ JsonIgnore'を' TObject'フィールドで使ったのですか?これはJacksonが 'update_id'のゲッターとセッターを無視する原因にはなりませんか? 第2の理由:アノテーションなしでも認識できるのに対して、なぜ@ JsonPropertyを各フィールドで使用したのですか? –

+1

@AlirezaMohamadi 1)カスタム 'JsonSerializer'を使用しています。メッセージ内でupdateIdをシリアル化したくありません。私は '{" update_id ":1、" message "= {}}'を取得したいのですが、もしupdate_idを無視しなければ、 '' message "= {" update_id ":1}'を得るでしょう。シリアライザの 'message'で同じlvlの' update_id'を呼び出します。 @JsonIgnoreでデフォルトのシリアライゼーションを防ぐ2)私はhttp://www.jsonschema2pojo.org/を使用してすべてのPOJOを生成しました。 @JsonProperty( "message_id")public Integer messageId;しかし、あなたがここで好きな方法を使うこともできます。 – varren

+1

@AlirezaMohamadi私はあなたのTObjectjsonsが次のような構造を持っていると仮定しました: '{" update_id ":1、" message ":{...}}'または '{" update_id ":1、" chat ":{ ...}} '{{" update_id ":1、" message_entity ":{...}}'これはあなたが尋ねたものではない場合、私はおそらく私の投稿を更新すべきです) – varren

関連する問題