Skip to content

ReactiveWebServerApplicationContext.getHttpHandler() causes early bean initialization #14666

@artembilan

Description

@artembilan

The config is like this:

@EnableIntegration
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public DirectChannel channel1() {
        return new DirectChannel();
    }

    @Bean
    public DirectChannel channel2() {
        return new DirectChannel();
    }

    @Bean // remove this bean to fix Transformer creation
    public JavaTimeModule timeModule() {
        return new JavaTimeModule();
    }

    /**
     * This method depends on object mapper, which is not yet configured (with module above) when
     * Spring DI is trying to instantiate transformer.
     *
     * Useful debug points:
     * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory#getBeansOfType(Class, boolean, boolean)}
     * {@link org.springframework.integration.config.annotation.TransformerAnnotationPostProcessor#createHandler(Object, Method, List)}
     *
     */
    @Bean
    @Transformer(inputChannel = "channel1", outputChannel = "channel2")
    public AbstractPayloadTransformer transformer(ObjectMapper dependency) {
        return new AbstractPayloadTransformer<Object, Object>() {
            @Override
            protected Object transformPayload(Object payload) {
                return payload;
            }
        };
    }
}

But Spring Integration is not relevant here at all.

The main point that we have some Jackson Module bean definition and other one depends on the ObjectMapper auto-configured in the mentioned JacksonAutoConfiguration.

The JacksonAutoConfiguration has the code like this:

@Bean
@ConditionalOnMissingBean
public Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder(
      List<Jackson2ObjectMapperBuilderCustomizer> customizers) {
   Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
   builder.applicationContext(this.applicationContext);
   customize(builder, customizers);
   return builder;
}

That customize() calls a

Collection<Module> moduleBeans = getBeans(this.applicationContext,
      Module.class);

eventually.

This is really inappropriate to call getBeansOfType() from the other bean definition: it's too early to instantiate all the beans in the application context.

I wonder why ObjectProvider<Module> is not used as a dependency for that jacksonObjectMapperBuilder bean definition...

For more info see spring-projects/spring-integration#2565

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions