I'm trying to create an extension function whose implementation uses a Spring bean. It didn't seem possible to do this by defining the extension function at the top level of a package. I tried this:
@Component
class Converter {
companion object {
@Autowired
lateinit var transformer: Transformer
fun Class1.convert(): Class2 {
return Class2 (this, transformer.transform(someStringProperty))
}
}
}
where transform
is a function that transforms some string to another string, and Class1
is some class that has a someStringProperty
property. My hope was that other classes could import pkg.Converter.Companion.convert
and then be able to use x.convert()
where x
is an object of type Class1
.
The syntax works, and using x.convert()
in other classes compiles fine. But it results in an exception at run time: kotlin.UninitializedPropertyAccessException: lateinit property transformer has not been initialized
It looks like Spring isn't autowiring the variable because it's in a companion object and not an actual component object.
Annotating the companion object with @Component
didn't work.
I don't think moving Class1.convert
directly inside Converter
would work, because then using x.convert()
would need an instance of the Converter
object, and I don't see how to do this with the extension function syntax.
Is there any way to accomplish this, or do I have to give up on the extension function syntax?
@Bean is just for the metadata definition to create the bean(equivalent to tag). @Autowired is to inject the dependancy into a bean(equivalent to ref XML tag/attribute).
The list object call the extension function (MutableList<Int>. swap(index1: Int, index2: Int):MutableList<Int>) using list. swap(0,2) function call. The swap(0,2) function pass the index value of list inside MutableList<Int>.
Kotlin @Autowired constructor injection This annotation instructs the Spring framework to inject the owner dependency into the Car bean.
Enabling @Autowired Annotations The Spring framework enables automatic dependency injection. In other words, by declaring all the bean dependencies in a Spring configuration file, Spring container can autowire relationships between collaborating beans. This is called Spring bean autowiring.
The extension function can use the file scope private variable and in the component's @PostConstruct method, assign "this" to the private variable. This design adds a dependency from component to the extension function, now they are both binding to the same private variable. But if they both are in the same problem, I think it is tolerable and there seems no other better way.
@Component
public class ClassOne {
var value = Random.nextInt()
@PostConstruct
private fun init() {
c1 = this
}
}
private lateinit var c1 : ClassOne
fun String.appendC1() : String {
return this + c1.value
}
And its test code:
@RunWith(SpringRunner::class)
@ContextConfiguration(classes = [ClassOne::class])
class DependencyInjectionTest {
@Autowired
lateinit var autowiredConfiguration : ClassOne
@Test
fun testAccessComponentInExtension() {
Assert.assertEquals(autowiredConfiguration.value, c1.value)
}
}
It can't be done because, because there's no way of auto-wiring static fields in Spring, as explained here: Can you use @Autowired with static fields?
There are certain workarounds but the general recommendation is don't do it.
Having said that if you are really committed to make this solution work you might get aways with it by using a Singleton with parameters as shown in this blog post: https://medium.com/@BladeCoder/kotlin-singletons-with-argument-194ef06edd9e. Although frankly I think such a convoluted solution would completely defeat the purpose
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With