DEV Community

Cover image for [Tiny] Injecting Dependency With Default Value in Spring: What Could Go Wrong?
Petr Filaretov
Petr Filaretov

Posted on

[Tiny] Injecting Dependency With Default Value in Spring: What Could Go Wrong?

If you are writing applications in Kotlin, you may be using default value Kotlin feature. Be careful though when you use default values for injected dependencies in Spring applications. It may lead to unexpected behaviour, and Spring will not even warn you.

Here is an example.

We have Ford Prefect who depends on humans:

@Component
class FordPrefect(
    private val humans: List<Human>,
) {
    @PostConstruct
    fun init() {
        log.info("humans: $humans")
    }

    companion object {
        private val log = LoggerFactory.getLogger(FordPrefect::class.java)
    }
}
Enter fullscreen mode Exit fullscreen mode

Where a human is defined as

interface Human
Enter fullscreen mode Exit fullscreen mode

And then we have a couple of humans who depend on Ford:

@Component
class ArthurDent(
    private val fordPrefect: FordPrefect,
) : Human {
    override fun toString() = "Arthur"
}

@Component
class TrishaMcMillan(
    private val fordPrefect: FordPrefect,
) : Human {
    override fun toString() = "Trisha"
}
Enter fullscreen mode Exit fullscreen mode

If you start the spring application with these three components, it will fail with UnsatisfiedDependencyException due to the circular dependency, which is expected:

┌─────┐
|  arthurDent defined in file [/.../ArthurDent.class]
↑     ↓
|  fordPrefect defined in file [/.../FordPrefect.class]
└─────┘  
Enter fullscreen mode Exit fullscreen mode

However, the situation changes if you add the default value for humans property:

private val humans: List<Human> = emptyList(),
Enter fullscreen mode Exit fullscreen mode

Now the application starts without any problem or warning. And it prints an empty list of humans:

INFO 6380 --- [           main] gDependencyWithDefaultValueApplicationKt : Starting SpringDependencyWithDefaultValueApplicationKt using Java 17.0.8.1 with PID 6380 (...)
INFO 6380 --- [           main] gDependencyWithDefaultValueApplicationKt : No active profile set, falling back to 1 default profile: "default"
INFO 6380 --- [           main] d.p.s.d.defaultvalue.FordPrefect         : humans: []
INFO 6380 --- [           main] gDependencyWithDefaultValueApplicationKt : Started SpringDependencyWithDefaultValueApplicationKt in 1.179 seconds (process running for 2.067)
Enter fullscreen mode Exit fullscreen mode

I bet you do not expect such a thing. By setting the default value you probably expect humans to be set with an empty list when no beans of Human are available. Or fail as in the previous scenario due to the circular dependency. However, this is not what is happening.

Actually, if you delete both ArthurDent and TrishaMcMillan components, the application will start and the output will be exactly the same - now as expected.

So, remember this and be careful when you are setting default values for injected dependencies.

The full source code is available on GitHub.


Dream your code, code your dream.

Top comments (0)