REST Jackson JsonDeserialize,升级后出现 StackOverflowError
REST Jackson JsonDeserialize, StackOverflowError after upgrade
在之前版本的 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 }
}
我们迁移到最后一个jackson版本(Wildfly 8.2提供的1.9.13)后出现异常:
com.fasterxml.jackson.databind.JsonMappingException: Can not construct
instance of RoleDto, problem: abstract types either need to be mapped
to concrete types, have custom deserializer, or be instantiated with
additional type information
好的,因为在 jackson 中使用了新的软件包,我们将它们升级为:
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer;
反序列化器现在可见(之前的异常消失了),
但是,我们得到 WhosebugError 异常。 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);
}
我们去行:result = deser.deserialize(jp, ctxt);
它导致无限循环和 WhosebugError 结果。
推荐的方法之一是实现我们自己的 SomeSharedDeserializer 为:
ObjectCodec oc = jp.getCodec();
JsonNode node = oc.readTree(jp);
//here manually create new object and return it
但是我们的classes是生成的。作为另一种解决方案,我尝试使用
ObjectMapper mapper = new ObjectMapper();
mapper.readValue(jp, getImplementation());
但得到了相同的结果 - Whosebug 异常。
我们该如何解决?我们可以使用一些反序列化器,将 JsonParser 实例传递给它,生成实现基本接口且没有 WhosebugError 的 class 吗?
Here 你可以找到完整的描述和试验来找到解决方案。
已找到以下解决方案:
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();
在之前版本的 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 }
}
我们迁移到最后一个jackson版本(Wildfly 8.2提供的1.9.13)后出现异常:
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of RoleDto, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
好的,因为在 jackson 中使用了新的软件包,我们将它们升级为:
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer;
反序列化器现在可见(之前的异常消失了), 但是,我们得到 WhosebugError 异常。 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);
}
我们去行:result = deser.deserialize(jp, ctxt);
它导致无限循环和 WhosebugError 结果。
推荐的方法之一是实现我们自己的 SomeSharedDeserializer 为:
ObjectCodec oc = jp.getCodec();
JsonNode node = oc.readTree(jp);
//here manually create new object and return it
但是我们的classes是生成的。作为另一种解决方案,我尝试使用
ObjectMapper mapper = new ObjectMapper();
mapper.readValue(jp, getImplementation());
但得到了相同的结果 - Whosebug 异常。
我们该如何解决?我们可以使用一些反序列化器,将 JsonParser 实例传递给它,生成实现基本接口且没有 WhosebugError 的 class 吗?
Here 你可以找到完整的描述和试验来找到解决方案。 已找到以下解决方案:
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();