如何在Jackson中从自定义反序列化器调用默认的反序列化器?
如何在Jackson中从自定义反序列化器调用默认的反序列化器?
我在Jackson的自定义反序列化器中遇到了问题。我想要访问默认的序列化器,以便填充我正在反序列化的对象。在填充之后,我将执行一些自定义操作,但首先我想要使用默认的Jackson行为对对象进行反序列化。\n这是我目前的代码:\n
public class UserEventDeserializer extends StdDeserializer{ 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; } }
\n我需要一种方法来初始化默认的反序列化器,以便在开始特殊逻辑之前预填充我的POJO。\n当从自定义反序列化器中调用deserialize方法时,无论我如何构造序列化器类,该方法似乎都是从当前上下文中调用的,这是因为我的POJO中存在注释。这会导致明显的堆栈溢出异常。\n我尝试过初始化BeanDeserializer,但这个过程非常复杂,我还没有找到正确的方法。我还尝试过重载AnnotationIntrospector,但没有成功,我认为它可能会帮助我忽略DeserializerContext中的注释。最后,我似乎通过使用JsonDeserializerBuilders取得了一些成功,尽管这要求我做一些魔法般的事情来获取Spring的应用程序上下文。我将非常感谢任何能够引导我走向更简洁解决方案的东西,例如,如何在不读取JsonDeserializer注释的情况下构造反序列化上下文。
问题的原因是用户想要在自定义的反序列化器中调用默认的反序列化器。解决方法是使用`jp.readValueAs(User.class)`来调用默认的反序列化器,然后对结果进行修改。
以下是整理后的文章:
在使用Jackson进行反序列化时,有时我们希望在自定义的反序列化器中调用默认的反序列化器。那么,如何实现呢?
在Stack Overflow上,有一个回答提供了一个简单可行的方法。用户可以使用`jp.readValueAs(User.class)`来调用默认的反序列化器,并对结果进行修改。下面是示例代码:
public User deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { User user = jp.readValueAs(User.class); // 对结果进行修改 return user; }
这个方法非常简单易懂,非常适合初学者使用。
然而,也有用户提到在Jackson 2.9.9版本中编译时会报错,提示`JsonParser.readTree()`方法不存在。经过分析发现,这只是一个简单的拼写错误,已经被修复了。
另外,有用户确认这个方法在Jackson 2.10版本中是可行的,非常感谢作者的分享。
有用户提到在某些情况下,这个方法会导致`StackOverflowError`,因为Jackson会再次使用同一个反序列化器对`User`进行反序列化。对此,作者解释说这取决于具体的使用场景。如果想要使用另一个已注册的反序列化器,并对结果进行修改,那么这个方法是可行的。但如果要使用相同的反序列化器,就需要像第一个回答中提到的那样,采取其他的解决方法来获取原始的反序列化器。
总之,通过调用默认的反序列化器并对结果进行修改,我们可以在自定义的反序列化器中实现特定的逻辑。这个方法简单易行,非常适合在Jackson中进行反序列化操作。
问题的原因是DeserializationContext.readValue()方法不存在,这是ObjectMapper的一个方法。解决方法是使用DeserializationContext的readValue()方法,该方法可以用于默认的反序列化器和任何自定义的反序列化器。
下面是一个示例代码,展示了如何在自定义的反序列化器中调用默认的反序列化器:
public class FooDeserializer extends StdDeserializer{ private static final long serialVersionUID = 1L; public FooDeserializer() { this(null); } public FooDeserializer(Class t) { super(t); } public FooBean deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { JsonNode node = jp.getCodec().readTree(jp); FooBean foo = new FooBean(); foo.setBar(ctxt.readValue(node.get("bar").traverse(), BarBean.class)); return foo; } }
上述代码中,deserialize()方法中使用了DeserializationContext的readValue()方法来调用默认的反序列化器。在调用readValue()方法之前,我们需要使用traverse()方法在JsonNode级别上遍历,以获取JsonParser,并将其传递给readValue()方法。
另外,如果你反序列化一个值类(如Date.class),可能需要调用nextToken()方法。
,上述解决方法非常优雅,可以将BarBean.class的反序列化委托给Jackson。这样做可以使你的反序列化器更加简洁、可重用和可测试。另外需要注意的是,在调用JsonNode.traverse(codec)方法时,应该传递已有的反序列化器codec。
问题的原因是需要在自定义的反序列化器中调用默认的反序列化器。解决方法是编写一个BeanDeserializerModifier,并通过SimpleModule进行注册。具体的代码如下所示:
public class UserEventDeserializer extends StdDeserializerimplements ResolvableDeserializer { private static final long serialVersionUID = 7923585097068641765L; private final JsonDeserializer> defaultDeserializer; public UserEventDeserializer(JsonDeserializer> defaultDeserializer) { super(User.class); this.defaultDeserializer = defaultDeserializer; } public User deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { User deserializedUser = (User) defaultDeserializer.deserialize(jp, ctxt); // Special logic return deserializedUser; } 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() { 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); } }
以上是解决问题的代码。另外还有一些其他问题和解决方法的讨论,但与问题本身无关。