我如何从jackson的一个自定义反序列化器中调用默认的反序列化器

我在Jackson的自定义反序列化程序中遇到问题。 我想访问默认序列化程序来填充我反序列化的对象。 在人口之后,我会做一些自定义的事情,但首先我想用默认的jackson行为反序列化对象。

这是我目前的代码。

public class UserEventDeserializer extends StdDeserializer<User> { private static final long serialVersionUID = 7923585097068641765L; public UserEventDeserializer() { super(User.class); } @Override @Transactional public User deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { ObjectCodec oc = jp.getCodec(); JsonNode node = oc.readTree(jp); User deserializedUser = null; deserializedUser = super.deserialize(jp, ctxt, new User()); // The previous line generates an exception java.lang.UnsupportedOperationException // Because there is no implementation of the deserializer. // I want a way to access the default spring deserializer for my User class. // How can I do that? //Special logic return deserializedUser; } } 

我需要的是一种初始化默认解序器的方法,以便在开始我的特殊逻辑之前,可以预先填充我的POJO。

当从自定义的反序列化器中调用反序列化时,无论我如何构造序列化器类,它都会从当前上下文中调用方法。 由于我的POJO中的注释。 这显然会导致堆栈溢出exception。 我尝试初始化一个beandeserializer但过程是非常复杂的,我没有设法find正确的方法来做到这一点。 我也尝试重载注释introspector无济于事,认为这可能会帮助我忽略DeserializerContext中的注释。 最后它接缝我可能有一些成功使用JsonDeserializerBuilders虽然这需要我做一些神奇的东西来从春季的应用程序上下文的保留。 我将不胜感激任何可能导致我一个更干净的解决scheme,例如我怎样才能构build一个反序列化上下文而不读取JsonDeserializer注释。

由于StaxMan已经build议你可以通过编写BeanDeserializerModifier并通过SimpleModule注册来完成。 下面的例子应该工作:

 public class UserEventDeserializer extends StdDeserializer<User> implements ResolvableDeserializer { private static final long serialVersionUID = 7923585097068641765L; private final JsonDeserializer<?> defaultDeserializer; public UserEventDeserializer(JsonDeserializer<?> defaultDeserializer) { super(User.class); this.defaultDeserializer = defaultDeserializer; } @Override public User deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { User deserializedUser = (User) defaultDeserializer.deserialize(jp, ctxt); // Special logic return deserializedUser; } // for some reason you have to implement ResolvableDeserializer when modifying BeanDeserializer // otherwise deserializing throws JsonMappingException?? @Override public void resolve(DeserializationContext ctxt) throws JsonMappingException { ((ResolvableDeserializer) defaultDeserializer).resolve(ctxt); } public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException { SimpleModule module = new SimpleModule(); module.setDeserializerModifier(new BeanDeserializerModifier() { @Override public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) { if (beanDesc.getBeanClass() == User.class) return new UserEventDeserializer(deserializer); return deserializer; } }); ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(module); User user = mapper.readValue(new File("test.json"), User.class); } } 

有几个方法可以做到这一点,但要做到这一点,需要更多的工作。 基本上你不能使用子类,因为信息默认的反序列化器需要从类定义中构build。

所以你最可能使用的是构造一个BeanDeserializerModifier ,通过Module接口注册(使用SimpleModule )。 你需要定义/重写modifyDeserializer ,并且对于你想添加你自己的逻辑(types匹配)的特定情况,构build你自己的解串器,传递给你的默认解串器。 然后在deserialize()方法中,您可以委托调用,获取结果Object。

或者,如果您必须实际创build并填充对象,则可以这样做,并调用deserialize()第三个参数的deserialize()重载版本; 反序列化的对象。

另一种可能的方式(但不是100%肯定)将指定的Converter对象( @JsonDeserialize(converter=MyConverter.class) )。 这是一个新的jackson2.2功​​能。 在你的情况下,转换器不会实际转换types,但简化修改对象:但我不知道是否会让你做到你想要的,因为默认的反序列化器会先被调用,只有你的Converter

对我来说更简单的解决scheme是添加另一个ObjectMapper bean,并使用它反序列化对象(感谢https://stackoverflow.com/users/1032167/varren评论); – 在我的情况下,我有兴趣要么反序列化id(一个int)或整个对象https://stackoverflow.com/a/46618193/986160

 import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import org.springframework.context.annotation.Bean; import java.io.IOException; public class IdWrapperDeserializer<T> extends StdDeserializer<T> { private Class<T> clazz; public IdWrapperDeserializer(Class<T> clazz) { super(clazz); this.clazz = clazz; } @Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); mapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, true); mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE); mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); return mapper; } @Override public T deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException { String json = jp.readValueAsTree().toString(); // do your custom deserialization here using json // and decide when to use default deserialization using local objectMapper: T obj = objectMapper().readValue(json, clazz); return obj; } } 

对于需要通过自定义反序列化器的每个实体,我们需要在Spring Boot App的全局ObjectMapper bean中对其进行configuration(例如对于Category ):

 @Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); mapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, true); mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE); mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); SimpleModule testModule = new SimpleModule("MyModule") .addDeserializer(Category.class, new IdWrapperDeserializer(Category.class)) mapper.registerModule(testModule); return mapper; } 

我不喜欢使用BeanSerializerModifier因为它强制在中心ObjectMapper声明一些行为改变,而不是在自定义反序列化器本身中,实际上它是用JsonSerialize注释实体类的并行解决scheme。 如果你觉得它类似的方式,你可能会喜欢我的答案在这里: https : //stackoverflow.com/a/43213463/653539

沿着TomášZáluský的build议 ,在使用BeanDeserializerModifier是不可取的情况下,您可以使用BeanDeserializerFactory自己构造一个默认的反序列化器,尽pipe需要一些额外的设置。 在上下文中,这个解决scheme看起来是这样的:

 public User deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { ObjectCodec oc = jp.getCodec(); JsonNode node = oc.readTree(jp); User deserializedUser = null; DeserializationConfig config = ctxt.getConfig(); JsonDeserializer<Object> defaultDeserializer = BeanDeserializerFactory.instance.buildBeanDeserializer(ctxt, User.class, config.introspect(User.class)); if (defaultDeserializer instanceof ResolvableDeserializer) { ((ResolvableDeserializer) defaultDeserializer).resolve(ctxt); } JsonParser treeParser = oc.treeAsTokens(node); config.initialize(treeParser); if (treeParser.getCurrentToken() == null) { treeParser.nextToken(); } deserializedUser = (User) defaultDeserializer.deserialize(treeParser, context); return deserializedUser; }