C'è un altro angolo per affrontare questo problema più genericamente per gli oggetti che sarebbero deserializzato usando il BeanDeserializer, creando un BeanDeserializerModifier
e registrandolo con il tuo mapper. BeanDeserializerModifier
è una sorta di alternativa alla sottoclasse BeanDeserializerFactory
e ti dà la possibilità di restituire qualcosa di diverso dal normale deserializzatore che verrebbe utilizzato, o di modificarlo.
Quindi, prima creare un nuovo JsonDeserializer
che può accettare un altro deserializzatore durante la sua costruzione e quindi conservare su quel serializzatore. Nel metodo deserialize, puoi verificare se ti viene passato un JsonParser
che punta attualmente a un JsonToken.START_ARRAY
. Se non si è passati a JsonToken.START_ARRAY
, è sufficiente utilizzare il deserializzatore predefinito passato a questa deserializzazione personalizzata al momento della creazione.
Infine, assicurarsi di implementare ResolvableDeserializer
, in modo che il deserializzatore predefinito sia correttamente collegato al contesto utilizzato dall'utente deserializzatore personalizzato.
class ArrayAsNullDeserialzer extends JsonDeserializer implements ResolvableDeserializer {
JsonDeserializer<?> mDefaultDeserializer;
@Override
/* Make sure the wrapped deserializer is usable in this deserializer's contexts */
public void resolve(DeserializationContext ctxt) throws JsonMappingException {
((ResolvableDeserializer) mDefaultDeserializer).resolve(ctxt);
}
/* Pass in the deserializer given to you by BeanDeserializerModifier */
public ArrayAsNullDeserialzer(JsonDeserializer<?> defaultDeserializer) {
mDefaultDeserializer = defaultDeserializer;
}
@Override
public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
JsonToken firstToken = jp.getCurrentToken();
if (firstToken == JsonToken.START_ARRAY) {
//Optionally, fail if this is something besides an empty array
return null;
} else {
return mDefaultDeserializer.deserialize(jp, ctxt);
}
}
}
Ora che abbiamo il nostro gancio deserializzatore generici, creiamo un modificatore che può usarlo. Questo è facile, basta implementare il metodo modifyDeserializer
nel BeanDeserializerModifier. Verrà passato il deserializzatore che sarebbe stato utilizzato per deserializzare il bean. Ti passa anche il BeanDesc che verrà deserializzato, quindi puoi controllare qui se vuoi o meno gestire [] come null per tutti i tipi.
public class ArrayAsNullDeserialzerModifier extends BeanDeserializerModifier {
@Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
if (true /* or check beanDesc to only do this for certain types, for example */) {
return new ArrayAsNullDeserializer(deserializer);
} else {
return deserializer;
}
}
}
Infine, è necessario registrare il BeanDeserializerModifier con l'ObjectMapper. Per fare questo, crea un modulo e aggiungi il modificatore nel setup (i SimpleModules non sembrano avere un aggancio per questo, sfortunatamente). Puoi leggere ulteriori informazioni sui moduli altrove, ma ecco un esempio se non hai già un modulo da aggiungere a:
Module m = new Module() {
@Override public String getModuleName() { return "MyMapperModule"; }
@Override public Version version() { return Version.unknownVersion(); }
@Override public void setupModule(Module.SetupContext context) {
context.addBeanDeserializerModifier(new ArrayAsNullDeserialzerModifier());
}
};
Ok! Grazie, ho pensato che sarebbe stato il caso ... non si può mai essere facile! Ti capita di sapere di un buon tutorial su come scriverne uno? – dardo
nessuna possibilità di correggere l'input originale, giusto? o, nel peggiore dei casi, se è l'unico caso, che ne è di una stringa sostituita da "[]" a "{}" – stivlo
Vorrei poterlo fare, è una chiamata al servizio web di cui non ho il controllo, da un campo di battaglia cattivo sito Web dell'azienda 2. – dardo