2015-01-23 5 views
5

In der vorherigen Version von Jackson (1.9.2) der folgende Code hat gut funktioniert:REST Jackson JsonDeserialize, Stackoverflow nach Upgrade

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 } 
} 

Nachdem wir in den letzten jackson Version (1.9.13 von Wildfly bereitgestellt migriert 8.2) bekamen wir eine Ausnahme:

com.fasterxml.jackson.databind.JsonMappingException: nicht Instanz RoleDto, Problem konstruieren kann: abstrakte Typen müssen entweder konkrete Typen zugeordnet werden, benutzerdefinierte Deserializer haben oder sein instanziiert mit zusätzliche Typinformationen

Ok, wie in neue Pakete jackson verwendet werden, aufgerüstet wir sie:

import com.fasterxml.jackson.databind.DeserializationContext; 
import com.fasterxml.jackson.databind.JsonDeserializer; 
import com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer; 

Der Deserializer jetzt sichtbar ist (die vorhergehende Ausnahme ist weg), Aber wir bekommen StackOverflowError-Ausnahme Der com.fasterxml.jackson.databind.ObjectMapper liest Wert (Linie 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); 
    } 

Wir sind auf die Linie gehen: result = deser.deserialize(jp, ctxt);

Es bewirkt Endlosschleife und Stackoverflow als Ergebnis.

Einer der Art und Weise, die empfohlen wird, ist unsere eigenen SomeSharedDeserializer zu implementieren:

ObjectCodec oc = jp.getCodec(); 
JsonNode node = oc.readTree(jp); 
//here manually create new object and return it 

Aber unsere Klassen erzeugt werden. Als eine andere Lösung habe ich versucht,

ObjectMapper mapper = new ObjectMapper(); 
mapper.readValue(jp, getImplementation()); 

zu verwenden, aber das gleiche Ergebnis - StackOverflow Ausnahme.

Wie können wir es beheben? Können wir einen Deserializer verwenden, um die JsonParser-Instanz zu übergeben, eine generierte Klasse, die die Basisschnittstelle implementiert, und ohne StackOverflowError?

Antwort

1

Here können Sie eine vollständige Beschreibung und Versuche finden, um eine Lösung zu finden. Die folgende Lösung wurde gefunden:

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();