Вопрос к знатокам Spring Boot.
Мне нужно заинжектить кастомный
ObjectMapper в свой компонент, но при этом я не хочу ломать дефолтный мэппер, созданный автоматически в
JacksonAutoConfiguration, потому как во всех остальных местах в приложении используется именно дефолтный вариант, дополненный настройками из
application.yml /
bootstrap.yml: всякие кастомные настройки сериализации/десериализации дат, enum-ов и т.п. То есть я не хочу трогать дефолтный вариант, потому что он уже правильно настроен на работу со стандартными опциями настроек.
Я создаю свой конфиг :
@Configuration
public class CustomMapperConfig {
@Bean(name = "myCustomMapper")
public ObjectMapper myCustomMapper() {
ObjectMapper mapper = new ObjectMapper();
//do some customizing
return mapper;
}
}
И хочу использовать различные реализации мэппера:
@Component
public class MyComponent {
@Autowired @Qualifier("myCustomMapper")
ObjectMapper myCustomMapper; // хочу использовать тут свой бин
@Autowired
ObjectMapper objectMapper;
// хочу тут использовать стандартный бин из автоконфига,
// но инжектится все равно моя кастомная реализация
}
Но в результате все места, где используется
ObjectMapper, начинают использовать именно мой кастомный бин.
Разницы нет - инжектить по имени, явно указывать
Qualifier или не указывать ничего вовсе - все равно будет использована моя собственная реализация.
Дело в том, что в
JacksonAutoConfiguration используется такая настройка:
@Bean
@Primary
@ConditionalOnMissingBean
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
return builder.createXmlMapper(false).build();
}
Несмотря на то, что тут указано
@Primary, в приоритете срабатывает
@ConditionalOnMissingBean: фреймворк видит, что у меня есть своя реализация и не выполняет создание из автоконфига.
Чтобы обойти это, я пробовал следующие варианты:
1) Заинжектить
JacksonAutoConfiguration -> в
CustomMapperConfig, чтобы задать явно порядок инициализации + установить низший приоритет своей реализации
@Configuration
@AllArgsConstructor
public class CustomMapperConfig {
private final JacksonAutoConfiguration autoConfiguration;
@Bean(name = "myCustomMapper")
@Order(Ordered.LOWEST_PRECEDENCE)
public ObjectMapper myCustomMapper() {
//...
}
}
Это не работает: да, инициализация классов проходит в нужном порядке, но мой метод создания все равно отрабатывает раньше, чем метод в
JacksonAutoConfiguration. Соответственно, следом опять отрабатывает поведение
@ConditionalOnMissingBean
2) Заинжектить дефолтный мэппер себе в конфиг и донастроить (такой вариант меня бы тоже устроил, - кастомная настройка не помешала бы дефолтному поведению в остальных местах):
вариант 1:@Configuration
@AllArgsConstructor
public class CustomMapperConfig {
private final ObjectMapper defaultMapper;
@Bean(name = "myCustomMapper")
public ObjectMapper myCustomMapper() {
//customize
return defaultMapper;
}
}
вариант 2:@Configuration
public class CustomMapperConfig {
@Bean(name = "myCustomMapper")
public ObjectMapper myCustomMapper(ObjectMapper defaultMapper) {
//customize
return defaultMapper;
}
}
В результате падает вот с такой ошибкой:
The dependencies of some of the beans in the application context form a cycle: customMapperConfig defined in file...
Можно конечно именно в своей конфигурации создавать бин ровно таким же образом, как это выполняется в автоконфигурации, фактически продублировав её, чтобы он потреблял все те же самые настройки, что и дефолтный. Но так делать очень бы не хотелось: это копипаста и хак библиотеки.
Можно ли как-то сохранить создание дефолтного бина из автоконфига? Или то, что там указано
@ConditionalOnMissingBean жестко превалирует над остальными настройками?