2015-01-23 12 views
5

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?

risposta

1

Here è possibile trovare una descrizione completa e prove per trovare una soluzione. La seguente soluzione è stata trovata:

import com.fasterxml.jackson.core.JsonParser; 
import com.fasterxml.jackson.databind.BeanDescription; 
import com.fasterxml.jackson.databind.DeserializationConfig; 
import com.fasterxml.jackson.databind.DeserializationContext; 
import com.fasterxml.jackson.databind.JsonDeserializer; 
import com.fasterxml.jackson.databind.ObjectMapper; 
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 
import com.fasterxml.jackson.databind.cfg.DeserializerFactoryConfig; 
import com.fasterxml.jackson.databind.deser.BeanDeserializerFactory; 
import com.fasterxml.jackson.databind.deser.ResolvableDeserializer; 
import com.fasterxml.jackson.databind.type.SimpleType; 
... 
    public abstract class RestDtoDeserializer<T> extends JsonDeserializer<T> 
    { 
     @Override 
     public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException 
     { 
      DeserializationConfig config = ctxt.getConfig(); 
      SimpleType simpleType = SimpleType.construct(getImplementationClass()); 
      BeanDescription beanDesc = config.introspect(simpleType); 
      BeanDeserializerFactory instance = new BeanDeserializerFactory(new DeserializerFactoryConfig()); 
      JsonDeserializer deserializer = instance.buildBeanDeserializer(ctxt, simpleType, beanDesc); 
      ((ResolvableDeserializer)deserializer).resolve(ctxt); 
      return (T) deserializer.deserialize(jp, ctxt); 
     } 

     public abstract Class<? extends T> getImplementationClass(); 
Problemi correlati