当前位置: 首页 > 知识库问答 >
问题:

如何声明另一个Jackson ObjectMapper而不影响原始bean的客户端?

华宪
2023-03-14

我有一个Spring启动应用程序,它公开了一个json REST API。为了将对象映射到json,它使用内置的jackson ObjectMapper,它是通过Spring Boot配置的。

现在我需要从yaml文件中读取一些数据,我发现一个简单的方法是使用Jackson——为此,我需要声明一个不同的ObjectMapper来将yaml转换为对象。我用一个特定的名称声明了这个新的映射器bean,以便能够将它注入我的服务中,处理从yaml文件读取的操作:

@Bean(YAML_OBJECT_MAPPER_BEAN_ID)
public ObjectMapper yamlObjectMapper() {
    return new ObjectMapper(new YAMLFactory());
}

但是我需要一种方法来告诉原始json ObjectMapper的所有其他“客户端”继续使用那个bean。所以基本上,我需要在原始bean上有一个@主注释。有没有一种方法可以实现这一点,而不必在我自己的配置中重新声明原始的ObjectMapper(我必须挖掘Spring引导代码来找到并复制其配置)?

我找到的一个解决方案是为ObjectMapper声明一个FactoryBean,并使其返回已经声明的bean,正如这个答案中建议的那样。我通过调试发现我原来的bean叫做"_halObjectMapper",所以我的factoryBean会搜索这个bean并返回它:

public class ObjectMapperFactory implements FactoryBean<ObjectMapper> {

    ListableBeanFactory beanFactory;

    public ObjectMapper getObject() {
        return beanFactory.getBean("_halObjectMapper", ObjectMapper.class);
    }
    ...
}

然后在我的配置类中,我将它声明为@主bean,以确保它是自动连接的首选:

@Primary
@Bean
public ObjectMapperFactory objectMapperFactory(ListableBeanFactory beanFactory) {
    return new ObjectMapperFactory(beanFactory);
}

不过,我对这个解决方案不是100%满意,因为它依赖于不在我控制之下的bean的名称,而且它看起来也像是一个黑客。有更清洁的解决方案吗?

谢谢!

共有3个答案

韩豪
2023-03-14

我相信为MVC层定义显式的主要对象映射器应该是这样工作的:

 @Primary
 @Bean
 public ObjectMapper objectMapper() {
     return Jackson2ObjectMapperBuilder.json().build();
 }

通过类型自动连线对象映射器将使用上述bean的所有bean。您的Yaml逻辑可以通过YAML_OBJECT_MAPPER_BEAN_ID自动连线。

戚育
2023-03-14

其他选项是将自定义映射器包装到自定义对象中:

@Component
public class YamlObjectMapper {
    private final ObjectMapper objectMapper;

    public YamlObjectMapper() {
        objectMapper = new ObjectMapper(new YAMLFactory());
    }

    public ObjectMapper getMapper() {
        return objectMapper;
    }
}

不幸的是,这种方法需要在注入YamlObjectMapper之后调用getMapper

柴兴修
2023-03-14

您可以定义两个ObjectMapperbean,并将其中一个声明为主bean,例如:

@Bean("Your_id")
public ObjectMapper yamlObjectMapper() {
    return new ObjectMapper(new YAMLFactory());
}

@Bean
@Primary
public ObjectMapper objectMapper() {
    return new ObjectMapper();
}

完成后,您可以将objectmapper bean与@Qualifier注释一起使用,例如:

@Autowired
@Qualifier("Your_id")
private ObjectMapper yamlMapper;

最新消息

您可以在运行时将ObjectMapper动态添加到Spring的bean工厂,例如:

@Configuration
public class ObjectMapperConfig {

    @Autowired
    private ConfigurableApplicationContext  context;

    @PostConstruct
    private void init(){
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ObjectMapper.class);
        builder.addConstructorArgValue(new JsonFactory());
        DefaultListableBeanFactory factory = (DefaultListableBeanFactory) context.getBeanFactory();
        factory.registerBeanDefinition("yamlMapper", builder.getBeanDefinition());
        Map<String, ObjectMapper> beans = context.getBeansOfType(ObjectMapper.class);
        beans.entrySet().forEach(System.out::println);
    }
}

上面的代码在不更改现有bean的情况下将一个新bean添加到上下文中(sysoutinit方法的末尾打印两个bean)。然后,您可以使用“yamlapper”作为限定符,将其自动连接到任何位置。

更新2(来自问题作者):

“更新”中建议的解决方案有效,下面是一个简化版本:

@Autowired
private DefaultListableBeanFactory beanFactory;

@PostConstruct
private void init(){
    BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(YAMLMapper.class);
    beanFactory.registerBeanDefinition("yamlMapper", builder.getBeanDefinition());
}

 类似资料:
  • 我正在发送一个请求到一个服务器,它给了我一个200,没有身体(完全可以接受),但是我无法解决如何配置micronaut注释来处理这个问题。无论我尝试什么,它都试图将空响应解码为JSON(至少我认为这是它正在做的,因为它给出了一个意想不到的错误,而不是当身体出错时得到的正常杰克逊错误)。我在微型文档中找不到任何关于如何做到这一点的东西。

  • 我正在开发一个基于java服务器客户端的应用程序,并使用Netty(4.0.27。最终)进行TCP套接字连接。我面临客户端的问题。 在客户机中,我为多个客户机(100个并发客户机)使用一个引导程序和一个NioEventLoopGroup,并为每个新的客户机连接调用以下命令。 现在,完成工作后,每个客户机都调用ctx。断开()。调用它之后,所有客户端都会收到ChannelInactive,并且所有客

  • 我正在使用一个名为networkx的python包。我在这个包中编写了一些自定义函数。只要我不更新这个包,或者不更改conda环境,它就可以正常工作。但我确信这不是正确的做法。我的问题和这个问题很相似,但我用的是康达。 我想知道我可以使用康达来达到类似的结果吗?“开发模式”是什么意思?它只是这个包的文件夹吗?另外,如果我将它安装在我的项目构建器中,依赖于此包的包会发生什么?当我安装其他一些软件包时

  • 问题内容: 我想了解原始和对象引用变量的行为方式不同。我以Kathy Sierra的 OCA / OCP Java SE7中 的以下代码为例: 在上面的代码中,我获得了更改之前和之后的值。 基本变量case的输出为: 但是,在对象引用变量中,一旦更改了的值,我将获得不同的值 参考变量大小写的输出为: 书中提到在两种情况下都复制位模式并放置新副本。如果这是真的,那为什么我们会得到不同的行为呢? 问题

  • 你好,Iam在spring(IntelliJ IDEA终极版)中使用AspectJ风格的AOP时遇到了麻烦。不使用方面时,输出与预期相同。但是当我将方面类受众声明为Bean时,我得到了Macbeth类的NoSuchBeanDefinitionException。 2017年8月27日上午9:38:39 org.springframework.context.annotationconfigappl

  • 我想从我的Spring类中配置“事务性”bean,而不是用注释类实现本身。 问题:是否可以从类声明的事务性,或者考虑到上面的约束,是否有其他选择?