2015-09-24 14 views
10

Ich habe eine abstrakte Klasse namens Instance und dann zwei Implementierungen davon, UserInstance und HardwareInstance. Das Problem, das ich habe ist, dass wenn ich den Rest Endpunkt für ein @POST in die Datenbank nennen, ich habe es im Idealfall wie .../rest/soexample/instance/create sein wollte, wo die Instanz mit dem REST-Endpunkt übergeben wird. Wenn Instance mit mehr als einer Implementierung nicht abstrakt war, würde es in Ordnung sein, aber da ich 2 haben erhalte ich einen Jackson.databind Fehler.Jackson Deserialisierung auf mehreren Typen

„Problem: abstrakte Typen müssen entweder auf konkrete Typen zugeordnet werden, benutzerdefinierte Deserializer haben oder mit zusätzlichen Typinformationen instanziiert werden“

Nach einem Blick auf eine Lösung für dieses ich eine SO Antwort gefunden, sagte die ich könnte so etwas wie verwenden:

@JsonDeserialize(as=UserInstance.class)

Aber es ist offenbar, wie die isonly nützlich, wenn es eine Implementierung der abstrakten Klasse ist. Vorausgesetzt, ich kann es nicht zweimal nennen, da es keine Möglichkeit geben würde, zu entscheiden, welche Art von Instanz es wäre.

Also ich frage mich, was der beste Weg ist, mit dieser Situation zu umgehen? Soll ich verschiedene Endpunkte erstellen? Wie:

.../rest/soexample/userinstance/create &

bin ich nicht sicher, wie ich ein noobie @ REST Dinge im Zusammenhang bin, wenn auch aktiv versuchen zu lernen. Vielen Dank!

+0

Sie könnten einen benutzerdefinierten Deserializer für die abstrakte Klasse schreiben, die programmatisch die JSON analysieren abhängig von den Feldern und analysieren den Körper als was auch immer konkrete Klasse, die Sie im Sinne hatten, haben würden. – IanGabes

+0

Danke für den Vorschlag. Das habe ich noch nie gemacht. Wo würde ich den benutzerdefinierten Deserializer platzieren? Wie würde ich es aus dem Endpunkt für ".../rest/soexample/instance/create" nennen? – erp

+0

REST ist eine nicht spezifische Art von Anwendung, es sagt mir nicht viel über die Server/Client-Technologie, die Sie verwenden. Ich fand eine Frage SO similiar bei Ihnen mit der Lösung, die ich im Sinn hatte: http://stackoverflow.com/questions/8210538/dynamic-polymorphic-type-handling-with-jackson ich in der Regel die Deserializer als setzen würde Öffentliche statische innere Klasse des Objekts, das Sie zu deserialisieren versuchen. – IanGabes

Antwort

16

Hier ist, was ich in der gleichen Fall tat

@JsonDeserialize(using = InstanceDeserializer.class) 
public abstract class Instance { 
    //.. methods 
} 

@JsonDeserialize(as = UserInstance.class) 
public class UserInstance extends Instance { 
    //.. methods 
} 

@JsonDeserialize(as = HardwareInstance.class) 
public class HardwareInstance extends Instance { 
    //.. methods 
} 

public class InstanceDeserializer extends JsonDeserializer<Instance> { 
    @Override 
    public Instance deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { 
     ObjectMapper mapper = (ObjectMapper) jp.getCodec(); 
     ObjectNode root = (ObjectNode) mapper.readTree(jp); 
     Class<? extends Instance> instanceClass = null; 
     if(checkConditionsForUserInstance()) { 
      instanceClass = UserInstance.class; 
     } else { 
      instanceClass = HardwareInstance.class; 
     } 
     if (instanceClass == null){ 
      return null; 
     } 
     return mapper.readValue(root, instanceClass); 
    } 
} 

Sie mit Anmerkungen versehen Instance mit @JsonDeserialize(using = InstanceDeserializer.class) die Klasse, um anzuzeigen, auf die abstrakte Klasse deserialisieren verwendet werden. Sie müssen dann, um anzuzeigen, dass jedes Kind Klasse deserialisiert werden as selbst, sonst werden sie die übergeordnete Klasse Deserializer verwenden und Sie werden eine StackOverflowError bekommen.

Schließlich setzen Sie innerhalb der InstanceDeserializer die Logik zur Deserialisierung in die eine oder andere Kindklasse (checkConditionsForUserInstance() zum Beispiel).

+0

Was sollte die Logik in der Methode checkConditionsForUserInstance() sein? Erhalten wir diese Instanzinformationen in ctxt? –

+1

Nein, es ist nur eine Methode, die Sie selbst vornehmen, um zu unterscheiden, in welche Klasse Sie de Json deserialisieren möchten. – carcaret

+1

Ok. Meine Situation ist, dass ich bin nicht sicher über die Instanz Klassen, wie ich ein SDK schreibe und Klassen werden von Entwicklern für die Schnittstelle in SDK implementiert werden.Irgendeine Idee, wie man in diesem Szenario damit umgeht, wo ich die Klasse nicht kenne, aber ich muss den Json in den Schnittstellentyp konvertieren? –

Verwandte Themen