The Actual Different: Spring boot @ComponentScan vs @Import when involving ConditionalOnClass

367 Views Asked by At

Context

I know there are a lot of posts regarding the comparison between these two. All of them just focus on @Import works on single Config file while @ComponenentScan will scan all config, bean, service files.

I find something new, hope someone can give me a good explanation behind this:

Prerequisite Artifact:

  • org.springframework.boot.autoconfigure
  • org.springframework.boot.test
@SpringBootTest(classes = test1char.class)
@ComponentScan("org.springframework.boot.autoconfigure.jackson")
//@SpringBootTest(classes = test1char.class)
//@Import(org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration.class)
public class ObjectMapperTest {

    //cannot autowired: no such bean when using ComponenentScan
    // Can autowired when either using @Import 
    // or @SpringBootTest(classes = org.springframework.boot.autoconfigure.jackson.class)

    @Autowired
    ObjectMapper objectMapper;

    @Test
    void main() {
        var date = LocalDateTime.now();//LocalDateTime
        String s;
        try {
            s = objectMapper.writeValueAsString(date);
            System.out.println(s);
        }catch (JsonProcessingException e){
            System.out.println(e);
        }

       
    }
}

ObjectMapper bean producer class: org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration.class for reference


@AutoConfiguration
@ConditionalOnClass({ObjectMapper.class})
public class JacksonAutoConfiguration {

    .... omit
    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnClass({Jackson2ObjectMapperBuilder.class})
    static class JacksonObjectMapperConfiguration {
        JacksonObjectMapperConfiguration() {
        }

        @Bean
        @Primary
        @ConditionalOnMissingBean
        ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
            return builder.createXmlMapper(false).build();
        }
    }

Issue

Basically the ObjectMapper cannot autowired: no such bean when using ComponenentScan. But it can be autowired when either using @Import or @SpringBootTest(classes = org.springframework.boot.autoconfigure.jackson.class)

Note: test1char.class is just a dummy class so that it has a context while not using the default SpringBootApplication which has everything in class path

I know it must have something to do with ConditionalOnClass which requires some class in jar org.springframework.boot.autoconfigure.jackson to be in classpath. So I boldly guess only @Import and @SprngBoot and @SpringBootTest can load class or package to be in classpath? That's why quite often ObjectMapper cannot be autoconfigured in @SpringBootTest annotated integration test as we often forgot to add the jar to it.

Update

Hate to say with @EnableAutoConfiguration it works all good like below: @ComponentScan("org.springframework.boot.autoconfigure.jackson") @EnableAutoConfiguration

Update

Actually @EnableAutoConfiguration alone also works without @ComponentScan.

-- One who is always confused by SpringBoot config xD

Attachment: Condition Report output in Intellij when using @ComponenetScan

============================ CONDITIONS EVALUATION REPORT

Positive matches:

None

Negative matches:

None

Exclusions:

None

Unconditional classes:

None
0

There are 0 best solutions below