【问题标题】:Lifecycle of Jackson ObjectMapper in Spring杰克逊 ObjectMapper 在 Spring 的生命周期
【发布时间】:2021-01-23 09:24:26
【问题描述】:

环境:

我用的是spring boot 2.3.3.RELEASE版本


问题

我使用@JsonComponent 注解注册了自定义反序列化器。

在一些模块和测试中我@Autowirejacksons ObjectMapper

问题 1:我不能在 @JsonComponent 中使用 @Autowire ObjectMapper,否则 @JsonComponent 将被完全忽略(没有错误消息)

问题 2:我想在 @JsonComponent 中拥有相同的 ObjectMapper 实例(或至少具有相同配置的 OM),我可以通过 Autowire 在其他组件中获得该实例


示例

由于我不想对某些字段进行自定义反序列化,因此我使用 ObjectMapper 在我的自定义反序列化程序中使用 convertValue()

我注意到,我不能 @Autowire 我的任何反序列化器中的 ObjectMapper,否则不会为我的应用程序中自动装配的其他 ObjectMapper 获取配置(因此反序列化器未正确注册)

我正在使用 (ObjectMapper) jsonParser.getCodec(); 获取反序列化器中的 ObjectMapper

但是这个 ObjectMapper 配置不正确(意味着例如类/方法上的注释被忽略)。

我想反序列化我的对象如下:

@Test
void testDeserializeFoo() throws IOException {
    ObjectMapper om = new ObjectMapper(); // this is obtained by jsonParser in deserializer but it behaves the same, since the ObjectMapper lacks the configuration
    InputStream is = getClass().getResourceAsStream("/json/foo.json");
    JsonNode fooNode = om.readTree(is);
    Foo foo =  om.convertValue(fooNode, Foo.class);
    log.info("Foo: " + foo);
}

Foo的构造函数用@JsonCreator注解。

问题是,我从自定义反序列化器中的解析器获得的 ObjectMapper 忽略了此注释。这会导致以下错误消息:

类型的类型定义无效 Foo: 参数 #0 没有属性名称,不可注入:不能用作 Creator [构造函数 福, 注释:{界面 com.fasterxml.jackson.annotation.JsonCreator=@com.fasterxml.jackson.annotation.JsonCreator(mode=DEFAULT)}]

是否可以在我的自定义解串器中拥有与 Autowired 时在其他组件中使用的相同的 ObjectMapper 实例?


编辑

可能的解决方案/测试:

我正在像这样测试我的反序列化器:

private JsonParser getJsonParser(String resource) throws IOException {
        InputStream src = getInputStream(resource);
        return objectMapper.createParser(src);
}
    
@Test
void testDeserializeFoo() throws IOException {
    JsonParser parser = getJsonParser("/json/foo.json");
    Foo foo = deserializer.deserialize(parser, null);
    System.out.println(foo);
}

问题在于 getParser() 方法中的 objectMapper 一直是一个新实例。现在我使用自动装配的 objectMapper。但这有什么影响呢?


结论:

我想在我的 JsonComponents(自定义反序列化器)中使用与 Autowired ObjectMapper(由 spring 在其他组件中提供)相同的 ObjectMapper 实例,或者至少是具有相同配置的 ObjectMapper。

我的意思是:在类、方法、字段/注册模块和 JsonComponents 上启用 Jackson 功能/注释配置

谁能解释一下:

  • 如何以及何时在 Spring 中配置 ObjectMapper(何时 注释配置(JsonCreator、JsonProperty)、Feature application.yml 中的配置(如接受大写),自定义 在 ObjectMapper 上注册的 JsonComponents 等
  • 这个 objectMapper 实例的生命周期是什么?
  • 什么是 ContextConfiguration 的生命周期, 反序列化配置?
  • Spring 和 Jackson 上下文如何相互关联?

我在寻找相关主题,其他相关答案:

  • Spring 和 Jackson 的上下文不同(但为什么,这是什么意思?)
  • 您需要一个 HandlerInstantiator 来自动装配(我假设这在我的 Spring 版本中已经是默认设置,这也不能解释为什么在其中一个反序列化器中自动装配 ObjectMapper 时我的自定义反序列化器没有被拾取而没有任何错误消息)

【问题讨论】:

  • 我读了你的问题大约 3 次,但仍然不知道你在问什么或试图实现什么。看起来您想向 Jackson 注册一些东西,这也将使用 jackson aka 循环依赖项。
  • 好的,我会尽量让这一点更清楚。我稍后会编辑它。尽管底部的问题应该很清楚,与上面的问题无关。
  • @ManuelWaltschek 更清晰,更专注。您似乎想在一篇文章中提出多个问题。
  • 您是否尝试过创建一个返回已配置ObjectMapper 实例的bean?
  • @LHCHIN 是的,正如 svr 在答案中所说,这仍然会导致未解决的循环依赖/引用。

标签: java json spring spring-boot jackson


【解决方案1】:

一般来说,您可以使用 Jackson2ObjectMapperBuilder 和 build() 来生成应用了所有最近设置的新对象映射器实例。默认的 ObjectMapper 由 JackonAutoConfiguration 中的 JackonsObjectMapperConfiguration 提供。所有 jackson2 对象映射器构建器实例都是由 JacksonAutoConfiguration 中的 JacksonObjectMapperBuilderConfiguration 创建的。配置对象映射器的详细信息可以找到here

如果您不喜欢 JacksonAutoConfiguration 中的标准默认设置,您可以使用 Jackson2ObjectMapperBuilderCustomizerConfiguration 进一步自定义 jackson2 对象映射器构建器

查看此answer - 它会回答您的其他问题

即将发布 - 在使用 jackson2objectbuilder/build 或自动装配对象映射器时,使用 JsonComponent 注释进行注释的 ser/deser 时遇到同样的问题。所有这些注释都由 JacksonAutoConfiguration 中定义的 JsonComponentModule bean 扫描,并注册到默认对象映射器和 jackson2 对象映射器构建器创建的所有实例。所以不可能同时使用未构建的对象映射器和注册 ser/deser。你说得对,spring 抑制了异常( beancurrentlyincreationexception ),并且 json 组件模块未注册对象映射器的消息 unresolvale 循环引用。

除了在 spring managed 之外创建一个新的对象映射器之外,我没有找到任何解决方案。

【讨论】:

  • 谢谢,这就是我要找的!所以我可以在 Jackson2ObjectMapperBuilderCustomizerConfiguration 类型的 Configuration 中创建一个 Bean 来为自动配置的实例添加额外的配置?
  • “除了在 spring 管理之外创建一个新的对象映射器之外,我没有找到任何解决方案。”那么我该怎么做呢?在 Deserializer 中使用 Jackson2ObjectMapperBuilder 和 build(),或者我可以在单例 @Component(静态实例)中执行此操作吗?
  • 欢迎您 - 创建您自己的 Jackson2ObjectMapperBuilderCustomizerConfiguration bean 将允许进一​​步配置 jacksonObjectMapper 未构建实例。您仍然无法构建实例,因为 JacksonAutoConfiguration 将扫描 JsonComponentModule - 所以您最终会得到循环引用。我能够根据需要创建静态类 ObjectMapper 变量,而无需进行任何自定义。
猜你喜欢
  • 1970-01-01
  • 2019-04-16
  • 2021-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多