2016-05-08 11 views
1

Hier ist ein (ein Teil) Serverantwort:Jackson ist zu verkennen Objektfeld mit 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" 
     } 
    } 
    ] 
} 

Ich habe eine Result Klasse, die wie ist (getrimmte Code zu reduzieren):

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() //... 

} 

Und ich habe ein Abstract ClassTObject genannt:

@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; 
    } 
} 

Das Problem ist, weil ich

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

verwendet wird, es nicht update_id als ein Feld zu erkennen, anstatt sie es als JsonTypeInfo.Id.NAME und zeigt mir erkennt:

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] 

Jetzt sagen Sie mir bitte, wie ich jackson sagen kann parsen update_id als ein Feld von TObject und verwechseln Sie es nicht als JsonTypeInfo.Id.NAME?

+0

Ich bearbeitete Frage habe und es verbessert. Jetzt denke ich, dass es nicht mehr vage ist. –

Antwort

1

Ich werde versuchen zu erklären, was hier vorgeht. Also schauen wir uns Ihre Anmerkungen an: Jackson wird erwarten, dass Result dieses Format hat. { "ok": true, "result": []} und dieser Teil ist richtig. Aber TObject hat

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

Und JsonTypeInfo.As.WRAPPER_OBJECT bedeutet, dass Jackson versuchen {"chat":{}} oder {"message":{}} oder {"message_entity":{}} innerhalb Ergebnis-Array zu finden. Hier Demo:

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

Aber das erste Element, das Sie in Ihrem json haben, ist eigentlich ein update_id. Und Jackson kann keinen update_id Typ finden, deshalb hört er einfach auf zu analysieren und löst eine Ausnahme aus. So beantwortet Ihre Frage: how can I tell jackson to parse update_id as a field of TObject and don't confuse it as JsonTypeInfo.Id.NAME: Es kann nicht mit JsonTypeInfo getan werden, weil Jackson nicht einmal denkt, dass dieser Teil von TObject ist. Er wird versuchen, TObject 1 Schicht niedriger in JSON zu finden. Wenn Sie Ihren JSON nicht ändern können, müssen Sie Ihre Klassen vollständig neu strukturieren oder einen benutzerdefinierten Deserializer erstellen.

Ich habe kleine Demo, wie Sie @JsonAnySetter und @JsonAnyGetter hier verwenden können: https://gist.github.com/varren/766b6830878c9e15c51784f57b303646#file-jsonanygetter-and-jsonanysetter

Individuelle JsonDeserializer und JsonSerializer für Update-Klasse in dieser Demo auch arbeiten können. https://gist.github.com/varren/766b6830878c9e15c51784f57b303646#file-custom-deserializer-and-serializer

Entfernen Sie einfach alle Typeinfo Anmerkungen und fügen

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

Danke! Ich genieße es, Ihre vollständige Antwort zu lesen, und ich werde es als Antwort markieren, wenn ich jeden Aspekt verstehe, weil es keine gewöhnliche Antwort ist und eher wie ein Vortrag ist. Wie auch immer, ich habe ein paar Fragen. 1. Warum haben Sie '@ JsonIgnore' in' TObject' Feldern verwendet? Hat das nicht zur Folge, dass Jackson Getter und Setter für 'update_id' ignoriert? 2 .: Warum haben Sie '@ JsonProperty' in jedem Feld verwendet, obwohl sie auch ohne Annotation erkannt werden konnten? –

+1

@ AlirezaMohamadi 1) Ich benutze benutzerdefinierte 'JsonSerializer' und ich möchte updateId innerhalb Nachricht nicht serialisieren. Ich möchte '{" update_id ": 1," message "= {}}' bekommen, aber wenn ich update_id nicht ignoriere, bekomme ich "message" = {"update_id": 1} 'deshalb kann ich es manuell einfügen 'update_id' im selben lvl mit' message' im Serializer. und verhindere die Standard-Serialisierung mit @JsonIgnore 2) Ich habe http://www.jsonschema2pojo.org/ benutzt, um alle POJO zu generieren. und wie Sie manchmal Feldnamen sehen ein bisschen anders '@JsonProperty (" message_id ") öffentliche Integer messageId;' aber sicher, können Sie jede Vorgehensweise, die Sie hier mögen. – varren

+1

@AlirezaMohamadi btw ich habe eine Annahme gemacht, dass deine TObject jsons eine Struktur wie diese haben: '{" update_id ": 1," message ": {...}}' oder '{" update_id ": 1," chat ": { ...}} 'oder' {"update_id": 1, "message_entity": {...}} 'also wenn du nicht gefragt hast, dann sollte ich wahrscheinlich meinen Beitrag aktualisieren) – varren