2015-09-24 11 views
10

Ho una classe astratta denominata Instance e quindi due implementazioni di quello, UserInstance e HardwareInstance. Il problema che sto avendo è che quando chiamo il resto dell'endpoint per un @POST nel database, idealmente volevo che fosse come .../rest/soexample/instance/create dove l'istanza è passata all'endpoint REST. Se Instance non fosse astratto con più di un'implementazione, andrebbe bene, ma visto che ho 2 ho un errore Jackson.databind.Deserializzazione Jackson su più tipi

"problema: tipi astratti sia bisogno di essere mappati a tipi concreti, hanno deserializzatore personalizzati, o essere istanziati con informazioni di tipo addizionale"

Dopo guardando una soluzione a questo ho trovato un SO risposta che ha detto potrei usare qualcosa come:

@JsonDeserialize(as=UserInstance.class)

Ma sembra del genere isonly utile se c'è un'implementazione della classe astratta. Supponendo che non posso chiamarlo due volte poiché non ci sarebbe modo di decidere quale tipo di istanza sarebbe.

Quindi mi chiedo quale sia il modo migliore per gestire questa situazione? Dovrei creare diversi endpoint? Come:

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

io non sono troppo sicuro come sono un paio di cose noobie @ REST correlati, anche se attivamente cercando di imparare. Grazie!

+0

È possibile scrivere un deserializzatore personalizzato per quella classe astratta, che dovrebbe analizzare a livello di codice il JSON a seconda dei campi e analizzare il corpo come qualsiasi classe concreta che avevate in mente. – IanGabes

+0

Grazie per il suggerimento. Non l'ho mai fatto prima. Dove posizionare il deserializzatore personalizzato? Come lo chiamerei dall'interno dell'endpoint per '.../rest/soexample/instance/create'? – erp

+0

REST è un tipo di applicazione non specifico, non mi dice molto su quale tecnologia server/client si sta utilizzando. Ho trovato una domanda simile alla tua con la soluzione che avevo in mente: http://stackoverflow.com/questions/8210538/dynamic-polymorphic-type-handling-with-jackson Generalmente inserisco il deserializzatore come classe interna statica pubblica dell'oggetto che stai tentando di deserializzare. – IanGabes

risposta

16

Ecco quello che ho fatto nella tua stessa causa:

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

di annotare Instance con @JsonDeserialize(using = InstanceDeserializer.class) per indicare la classe da utilizzare per deserializzare la classe astratta. È necessario quindi indicare che ciascuna classe secondaria verrà deserializzata, as, altrimenti utilizzerà il deserializzatore della classe padre e otterrà un valore StackOverflowError.

Infine, all'interno dello InstanceDeserializer si mette la logica per deserializzare in una o un'altra classe figlio (ad esempio checkConditionsForUserInstance()).

+0

Quale dovrebbe essere la logica nel metodo checkConditionsForUserInstance()? Riceviamo queste informazioni di istanza in ctxt? –

+1

No, è solo un metodo che ti fai distinguere in quale classe vuoi deserializzare de Json. – carcaret

+1

Ok. la mia situazione è che non sono sicuro delle classi di istanze mentre sto scrivendo un SDK e le classi saranno implementate dagli sviluppatori per l'interfaccia presente nell'SDK.Qualche idea su come affrontarlo in questo scenario, in cui non sono a conoscenza della classe, ma devo convertire Json nel tipo di interfaccia? –