Я пытаюсь написать тестовый пример интеграции с Spring Boot Test.Spring Boot test case не использует пользовательскую услугу преобразования
Я настроить ConversionService
знать о новых java.time
типов:
@Configuration
public class ConversionServiceConfiguration {
@Bean
public static ConversionService conversionService() {
final FormattingConversionService reg = new DefaultFormattingConversionService();
new DateTimeFormatterRegistrar().registerFormatters(reg);
return reg;
}
}
а затем ожидать, что она работает:
@Component
class MyServiceConfig {
@Value("${max-watch-time:PT20s}")
private Duration maxWatchTime = Duration.ofSeconds(20);
}
При работе в нормальном SpringApplication.run
это, кажется, работает хорошо. Однако, в моем тесте:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT, classes= {
MyServiceMain.class,
AttachClientRule.class
})
public class MyTest {
@Inject
@Rule
public AttachClientRule client;
@Test(expected=IllegalArgumentException.class)
public void testBad() throws Exception {
client.doSomethingIllegal();
}
}
она взрывается:
Вызванная: org.springframework.beans.factory.UnsatisfiedDependencyException: Ошибка при создании боба с именем 'AttachClientRule': Неудовлетворенная зависимость выражается через параметр конструктора 0:
Ошибка создания компонента с именем «MyServiceConfig»: недопустимая зависимость, выраженная через поле «maxWatchTime»: не удалось преобразовать значение типа [java.lang.String] в требуемый тип [java.time.Duration];
nested exception is java.lang.IllegalStateException: Невозможно преобразовать значение типа [java.lang.String] в требуемый тип [java.time.Duration]: не найдено подходящих редакторов или стратегии конверсии;
Вглядываясь глубоко в кишках TypeConverterDelegate
, что делает фактическое преобразование, по-видимому, чтобы захватить ConversionService
, используемый с поля на DefaultListableBeanFactory
. Настройка наблюдения на котором установлено, что поле, я нахожу AbstractApplicationContext.refresh()
метод:
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh(); // <--- MyServiceConfig initialized here
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory); // <--- DefaultListableBeanFactory.conversionService set here!!!
// Last step: publish corresponding event.
finishRefresh();
Так @Value
инъекции происходит до того, как ConversionService
применяется к BeanFactory
. Нет буено!
Я обнаружил, что, кажется, обходной путь:
@Configuration
public class ConversionServiceConfiguration implements BeanFactoryPostProcessor {
@Bean
public static ConversionService conversionService() {
final FormattingConversionService reg = new DefaultFormattingConversionService();
new DateTimeFormatterRegistrar().registerFormatters(reg);
return reg;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.setConversionService(conversionService());
}
}
Это заставляет инициализацию произойти раньше, но не чувствует, как правильное решение (по крайней мере, это не документированным как таковой).
Где я пошла не так? Spring 4.3.0, Spring Загрузочный 1.4.0M3
EDIT
И теперь я обнаружил еще один путь к сбою! Не делая тот же класс конфигурации реализации EnvironmentAware
:
@Override
public void setEnvironment(Environment environment) {
((AbstractEnvironment) environment).setConversionService(conversionService());
}
Я считаю, что PropertySourcesPropertyResolver
использует неправильно (по умолчанию) ConversionService
. Это сводит меня с ума!
Вызванный: java.lang.IllegalArgumentException: Невозможно преобразовать значение [PT15s] от типа источника [String] целевого типа [Продолжительность] в org.springframework.core.env.PropertySourcesPropertyResolver.getProperty (PropertySourcesPropertyResolver.java:94) на org.springframework.core.env.PropertySourcesPropertyResolver.getProperty (PropertySourcesPropertyResolver.java:65) в org.springframework.core.env.AbstractPropertyResolver.getProperty (AbstractPropertyResolver.java:143) в org.springframework.core.env.AbstractEnvironment.getProperty (AbstractEnvironment.java:546) в com.mycorp.DoSomething.go (DoSomething.java:103)
Спасибо, но это не похоже, чтобы помочь. –