[英]How can I use @WebMvcTest for a Controller that uses an autowired ConversionService?
[英]How to Autowired in ConversionService in springboot
试图在springboot中访问模型中的ConversionControl,没有运气。
@Component
public class CityHelperService {
@Autowired
ConversionService conversionService;// = ConversionServiceFactory.registerConverters();
public City toEntity(CityDTO dto){
City entity = conversionService.convert(dto, City.class);
return entity;
}
public CityDTO toDTO(City entity){
CityDTO dto = conversionService.convert(entity, CityDTO.class);
return dto;
}
}
它显示以下错误:
Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.lumiin.mytalk.model.CityModel com.lumiin.mytalk.controllers.CityController.cityModel;
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cityModel' defined in file : Unsatisfied dependency expressed through constructor argument with index 1 of type [com.lumiin.mytalk.dao.CityHelperService]: : Error creating bean with name 'cityHelperService': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.springframework.core.convert.ConversionService com.lumiin.mytalk.dao.CityHelperService.conversionService;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.core.convert.ConversionService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)};
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cityHelperService': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.springframework.core.convert.ConversionService com.lumiin.mytalk.dao.CityHelperService.conversionService;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.core.convert.ConversionService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
从最后一个嵌套异常来看,显然没有可用的ConversionService
bean:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.core.convert.ConversionService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
查看Spring 文档显示,您应该声明一个ConversionService
bean。 在 XML 配置中,它看起来像这样:
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="example.MyCustomConverter"/>
</set>
</property>
</bean>
并且由于您使用的是 Spring Boot,我假设您正在以编程方式创建上下文,因此您应该创建一个使用@Bean
注释的方法,该方法返回一个ConverstionService
,如下所示( 在此处解释):
@Bean(name="conversionService")
public ConversionService getConversionService() {
ConversionServiceFactoryBean bean = new ConversionServiceFactoryBean();
bean.setConverters(...); //add converters
bean.afterPropertiesSet();
return bean.getObject();
}
不完全同意接受的答案,因为会有一个名为mvcConversionService
的默认ConverstionService
,所以你会得到重复的 bean exception 。 而是addConverter
到FormatterRegistry
,这里是部分答案的链接:
ConversionService / FormattingConversionServiceFactoryBean 的 Java Config 等效项
此外,您还需要(在某些情况下)为ConversionService
定义至少一个空Component
,如下所示:
@Component @Primary
public class MyConversionService extends DefaultConversionService implements ConversionService {
// an empty ConversionService to initiate call to register converters
}
这是为了强制 spring 容器发起调用:
class WebMvcConfigurerAdapter {
...
public void addFormatters(FormatterRegistry registry) {
//registry.addConverter(...);
}
}
现有的答案对我不起作用:
WebMvcConfigurerAdapter.addFormatters
进行自定义(或简单地使用@Component
注释转换器)仅适用于 WebMvc 上下文,我希望我的自定义转换器在任何地方都可用,包括在任何 bean 上的@Value
注入。ConversionService
bean(通过ConversionServiceFactoryBean
@Bean
或@Component
)会导致 Spring Boot 用您定义的自定义 bean 替换SpringApplication
bean 工厂上的默认ApplicationConversionService
,这可能基于DefaultConversionService
(在AbstractApplicationContext.finishBeanFactoryInitialization
中)。 问题是 Spring Boot 向DefaultConversionService
中的标准集添加了一些方便的转换器,例如StringToDurationConverter
,因此通过替换它会丢失这些转换。 如果您不使用它们,这对您来说可能不是问题,但这意味着该解决方案不适用于所有人。 我创建了以下@Configuration
类,它对我有用。 它基本上将自定义转换器添加到Environment
使用的ConversionService
实例(然后传递给BeanFactory
)。 这保持尽可能多的向后兼容性,同时仍将您的自定义转换器添加到正在使用的转换服务中。
@Configuration
public class ConversionServiceConfiguration {
@Autowired
private ConfigurableEnvironment environment;
@PostConstruct
public void addCustomConverters() {
ConfigurableConversionService conversionService = environment.getConversionService();
conversionService.addConverter(new MyCustomConverter());
}
}
显然,如果您希望该过程更加自动化,您可以将自定义转换器列表自动连接到此配置类中并循环它们以将它们添加到转换服务,而不是上面的硬编码方式。
为了确保在实例化任何可能需要将转换器添加到ConversionService
的 bean 之前运行此配置类,请将其添加为 spring 应用程序的run()
调用中的主要源:
@SpringBootApplication
public class MySpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(new Class<?>[] { MySpringBootApplication.class, ConversionServiceConfiguration.class }, args);
}
}
如果你不这样做,它可能会起作用,也可能不起作用,这取决于你的类最终在 Spring Boot JAR 中的顺序,这决定了它们被扫描的顺序。 (我发现这一点很困难:它在使用 Oracle JDK 本地编译时有效,但在我们使用 Azul Zulu JDK 的 CI 服务器上无效。)
请注意,要使其在@WebMvcTest
中工作,我还必须将此配置类与我的 Spring Boot 应用程序类结合到@ContextConfiguration
:
@WebMvcTest(controllers = MyController.class)
@ContextConfiguration(classes = { MySpringBootApplication.class, ConversionServiceConfiguration.class })
@TestPropertySource(properties = { /* ... properties to inject into beans, possibly using your custom converter ... */ })
class MyControllerTest {
// ...
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.