Nella versione precedente di Jackson (1.9.2) il seguente codice ha funzionato bene:REST Jackson JsonDeserialize, StackOverflowError dopo l'aggiornamento
import org.codehaus.jackson.map.JsonDeserializer;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.map.DeserializationContext;
...
@JsonDeserialize(using = RoleDeserializer.class)
public interface RoleDto {}
public class RoleDeserializer extends SomeSharedDeserializer<RoleDto> {}
public class SomeSharedDeserializer<T> extends JsonDeserializer<T> {
@Override
public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException
{
return jp.readValueAs(getImplementation());
}
public Class<? extends T> getImplementation(){ ... returns some generated implementation of RoleDto }
}
Dopo abbiamo migrato l'ultima versione di Jackson (1.9.13 fornito da wildfly 8.2) abbiamo ottenuto un'eccezione:
com.fasterxml.jackson.databind.JsonMappingException: non possono costruire istanza di RoleDto di problemi: tipi astratti sia bisogno di essere mappati di tipi concreti, hanno deserializzatore personalizzato o essere istanziato con informazioni ulteriore tipo
Ok, come a Jackson nuovi pacchetti sono usati, li abbiamo trasferiti in:
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer;
Il deserializzatore è visibile ora (l'eccezione precedente è andato), Tuttavia, otteniamo Eccezione StackOverflowError. Il com.fasterxml.jackson.databind.ObjectMapper legge il valore (linea 3023):
DeserializationContext ctxt = createDeserializationContext(jp, cfg);
JsonDeserializer<Object> deser = _findRootDeserializer(ctxt, valueType);
// ok, let's get the value
if (cfg.useRootWrapping()) {
result = _unwrapAndDeserialize(jp, ctxt, cfg, valueType, deser);
} else {
result = deser.deserialize(jp, ctxt);
}
Andiamo alla linea: result = deser.deserialize(jp, ctxt);
Essa provoca al ciclo infinito e StackOverflowError di conseguenza.
Uno dei modi che è raccomandato è quello di implementare la nostra SomeSharedDeserializer come:
ObjectCodec oc = jp.getCodec();
JsonNode node = oc.readTree(jp);
//here manually create new object and return it
Ma le nostre classi sono generati. Come altra soluzione ho provato a usare
ObjectMapper mapper = new ObjectMapper();
mapper.readValue(jp, getImplementation());
Ma ho ottenuto lo stesso risultato - eccezione StackOverflow.
Come possiamo risolvere il problema? Possiamo usare un deserializzatore, per passarlo istanza JsonParser, classe generata che implementa l'interfaccia di base e senza StackOverflowError?