REST Jackson JsonDeserialize,升级后的StackOverflowError

Ale*_*ndr 5 java rest json jackson deserialization

在以前版本的jackson(1.9.2)中,以下代码运行良好:

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 }
}
Run Code Online (Sandbox Code Playgroud)

在我们迁移到最后一个jackson版本(Wildfly 8.2提供的1.9.13)后,我们得到了一个例外:

com.fasterxml.jackson.databind.JsonMappingException:无法构造RoleDto的实例,问题:抽象类型需要映射到具体类型,具有自定义反序列化器,或者使用其他类型信息进行实例化

好的,就像在jackson使用的新包装一样,我们将它们升级为:

import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer;
Run Code Online (Sandbox Code Playgroud)

解串器现在可见(先前的异常消失了),但是,我们得到了StackOverflowError异常.com.fasterxml.jackson.databind.ObjectMapper读取值(第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);
    }
Run Code Online (Sandbox Code Playgroud)

我们去了线: result = deser.deserialize(jp, ctxt);

结果导致无限循环和StackOverflowError.

建议的方法之一是将我们自己的SomeSharedDeserializer实现为:

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

但我们的课程已生成.作为我尝试使用的另一种解决方案

ObjectMapper mapper = new ObjectMapper();
mapper.readValue(jp, getImplementation());
Run Code Online (Sandbox Code Playgroud)

但得到了相同的结果 - StackOverflow异常.

我们该如何解决?我们可以使用一些反序列化器,传递它的JsonParser实例,生成的类实现基接口而没有StackOverflowError吗?

Ale*_*ndr 1

您可以在这里找到完整的描述和尝试来找到解决方案。已找到以下解决方案:

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();
Run Code Online (Sandbox Code Playgroud)