Uploaded image for project: 'Spring Framework'
  1. Spring Framework
  2. SPR-15940

When using kotlin Collection then @Autowire Collection<SomeInterface> does not work correctly

    Details

    • Type: Bug
    • Status: Open
    • Priority: Major
    • Resolution: Unresolved
    • Affects Version/s: 5.0 RC3
    • Fix Version/s: Waiting for Triage
    • Component/s: Core:DI
    • Labels:
    • Last commented by a User:
      true

      Description

      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<SecondInterface>.

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

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

      Here's the test:

      KotlinAutowireTest.kt

      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"]>
      

        Activity

        Hide
        sdeleuze Sébastien Deleuze added a comment -

        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?

        Show
        sdeleuze Sébastien Deleuze added a comment - 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?

          People

          • Assignee:
            sdeleuze Sébastien Deleuze
            Reporter:
            mzagar Mario Zagar
            Last updater:
            Sébastien Deleuze
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Days since last comment:
              10 weeks, 2 days ago