为 ObjectMapper 创建多个 bean

Posted

技术标签:

【中文标题】为 ObjectMapper 创建多个 bean【英文标题】:creating multiple beans for ObjectMapper 【发布时间】:2018-09-04 14:57:06 【问题描述】:

我想,主要以日期格式区分。

我已经写了以下代码-

@Configuration
public class ObjectMapperConfig 

    @Primary
    @Bean
    public ObjectMapper createDefaultObjectMapper() 
        return new ObjectMapper();
    

    @Bean(name="AOMapper")
    public ObjectMapper createFacebookObjectMapper() 
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZZ"));
        return objectMapper;
    

    @Bean(name="BOMapper")
    public ObjectMapper createTwitterObjectMapper() 
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setDateFormat(new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy"));
        return objectMapper;
    

虽然我可以使用 @Qualifier 注释来使用 AOMapper 和 BOMapper,但其他仅使用 ObjectMapper 而没有 Qualifier 注释的第三方包无法获得默认的 ObjectMapper。

有出路吗?

更新:以下是我得到的异常

[com.myorg.service.xyz.client.XyzClient]: Factory method 'getUnstarted' threw exception; nested exception is java.lang.RuntimeException: java.io.UncheckedIOException: Cannot construct instance of `java.time.Instant` (no Creators, like default construct, exist): no String-argument constructor/factory method to deserialize from String value ('2018-03-19T22:56:33.339Z')
 at [Source: (ByteArrayInputStream); line: 1, column: 161] (through reference chain: com.myorg.service.xyz.client.WatchResult["updates"]->java.util.ArrayList[0]->com.myorg.service.xyz.client.Announcement["announceTime"]) (code 200)

我从上面了解到的是,不知何故,XyzClient 没有获得正确的默认 ObjectMapper,因此无法反序列化日期格式

【问题讨论】:

您能分享一下第三方软件包给出的错误吗? 这些包是专有的,不允许做任何更改。 但是您能否仅分享错误以了解错误的确切原因?我不要求做任何改变:) 您能否分享一下您在执行此操作时遇到了什么异常?这将显示您所做的努力... 没关系,您可以为相同的 Class 类型创建 n 个 bean。唯一的问题是,如果您尝试创建具有相同名称的 bean 或尝试将 bean 限定为相同的类类型或 bean 被类类型使用... 【参考方案1】:

问题是您的ObjectMapper 不知道如何反序列化Instant 类,您需要注册提供这些自定义序列化器/反序列化器的jackson 模块。这个模块被命名为jackson-datatype-jsr310,你可以用这个来导入它(当使用 maven 时):

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.9.4</version>
</dependency>

然后,当您创建对象映射器时,您必须注册 JavaTimeModule 模块。

objectMapper.registerModule(new JavaTimeModule());

所以你的方法应该类似于:

@Bean
@Primary
public ObjectMapper createDefaultObjectMapper() 
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerModule(new JavaTimeModule());
    return objectMapper;

【讨论】:

【参考方案2】:

您能否覆盖第三方库的 bean 并设置适当的 ObjectMapper。它是在第三方库中到处使用还是在一个可重复使用的地方使用?如果它在所有地方都使用,那么覆盖每个 bean 可能是不可行的。如果他们在一个地方使用它,您可能可以创建自己的 @Primary bean 来覆盖他们的默认值。

此外,从外观上看,您似乎正在以给定格式向这些第三方库发送日期。你不能标准化你给这些库日期的格式吗?

【讨论】:

那些包是专有的,不允许做任何改变。我也无法控制所有三个映射器的日期输入。默认的 objectMapper 使用它自己的默认格式,其他包也为其构建。我只是想了解是否可以在不接触包的情况下为 ObjectMapper 注入创建不同的变体。如果不是,我将使用ObjectMapper AOMapper = new ObjectMapper();,我相信当我的所有其他应用程序部分都使用注入的依赖项时,这并不理想。

以上是关于为 ObjectMapper 创建多个 bean的主要内容,如果未能解决你的问题,请参考以下文章

ObjectMapper 的两个实例

FullAuditedEntity、ObjectMapper:创建新条目或删除时的 CreatorUserId Null

JSON对象与字符串相互转化ObjectMapper

将 ObjectMapper 声明为 bean 有啥好处?

将 responseJSON 解析为 ObjectMapper

Swift 3 ObjectMapper - 将 URLSession 结果转换为 Map 对象失败