Mario Zagar opened SPR-15940 and commented

Using: - spring-framework 5.0.0.RC3 (also tested wth 1.5.6.RELEASE, problem also present) - kotlin-stdlib 1.1.4-3

Following test fails when autowiring kotlin Collection @Autowired lateinit var beans : Collection.

When using java.util.Collection autowiring works as expected.

Not really sure if this is kotlin issue or spring issue.

Here's the test:

package spring.autowire.test

import org.assertj.core.api.Assertions
import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.test.context.ContextConfiguration
import org.springframework.test.context.junit4.SpringRunner

interface FirstInterface
interface SecondInterface
interface ThirdInterface

class Bean1 : FirstInterface, SecondInterface, ThirdInterface
class Bean2 : FirstInterface, SecondInterface, ThirdInterface
class Bean3 : FirstInterface, SecondInterface, ThirdInterface
class Bean4 : FirstInterface, SecondInterface, ThirdInterface

@Configuration
open class TestSpringConfig {
    @Bean open fun bean1() : Bean1 = Bean1()
    @Bean open fun bean2() : FirstInterface = Bean2()
    @Bean open fun bean3() : SecondInterface = Bean3();
    @Bean open fun bean4() : ThirdInterface = Bean4();
}

@RunWith(SpringRunner::class)
@ContextConfiguration(classes = arrayOf(TestSpringConfig::class))
class KotlinAutowireTest {
    @Autowired
    lateinit var beans : Collection<SecondInterface> // test passes if I use java.util.Collection<SecondInterface>

    @Test
    fun test() {
        Assertions.assertThat(beans)
                .extracting{it.javaClass.name}
                .containsOnly(
                        "spring.autowire.test.Bean1",
                        "spring.autowire.test.Bean2",
                        "spring.autowire.test.Bean3",
                        "spring.autowire.test.Bean4"
                )
    }
}

Test output:

java.lang.AssertionError: 
Expecting:
  <["spring.autowire.test.Bean1", "spring.autowire.test.Bean3"]>
to contain only:
  <["spring.autowire.test.Bean1",
    "spring.autowire.test.Bean2",
    "spring.autowire.test.Bean3",
    "spring.autowire.test.Bean4"]>
but could not find the following elements:
  <["spring.autowire.test.Bean2", "spring.autowire.test.Bean4"]>

Affects: 5.0 RC3

1 votes, 3 watchers

Comment From: spring-projects-issues

Sébastien Deleuze commented

I had a look to this repro test and found that MutableCollection is working as expected while indeed Collection (the Kotlin one) ones returns 2 beans. After comparing both cases, I found that the difference of behavior comes from GenericTypeAwareAutowireCandidateResolver#checkGenericTypeMatch which could behave differently because of Kotlin declaration-site variance: - Collection is declared as interface Collection<out E> - MutableCollection is declared as interface MutableCollection<E>

Juergen Hoeller I have added a unit test in this branch to compare Kotlin MutableCollection and Collection, do you have any thoughts about this behavior being related to our generics comparison algorythm having to be tuned to support Kotlin declaration-site variance or if the issue could be on Kotlin side?

Comment From: sdeleuze

Duplicate of #22313.