Obtain Micronaut ResourceLoader in Method Call - kotlin

I'm trying to get ahold of a ResourceLoader for a utility method by using injections, but I keep getting the following error:
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property resourceResolver has not been initialized
#Singleton
class Injections {
#Inject
lateinit var resourceResolver: ResourceLoader
}
val inj = Injections()
fun <T> parseYaml(filePath: String): T {
if (!inj.resourceResolver.getResource(filePath).isPresent) {
throw IllegalArgumentException("Could not find file '$filePath'")
}
val inputStream = inj.resourceResolver.getResourceAsStream(filePath).get()
return Yaml().load(inputStream) as T
}
I don't need to be using injections to make this happen, I just need to access a ResourceResolver from the parseYaml method.

I don't need to be using injections to make this happen
You kind of do need to be using injections. That is why your code makes use of #Inject.
The problem is you are creating a new instance of Injections instead of using the one provided by the container, so your instance won't be initialized the way you want it to be. Instead of val inj = Injections() if you #Inject the Injections instance into whatever bean(s) need access to it, that will work.

Related

Why does Mockito throw an "InvalidUseOfMatchersException" at for this code?

I am writing a test for a Spring-Boot project written in Kotlin 1.5. This piece of code does fail at test runtime with an InvalidUseOfMatchersException and I struggle to figure out why:
#SpringBootTest
#AutoConfigureMockMvc
internal class ControllerTest {
#Autowired
lateinit var mockMvc: MockMvc
#MockBean
lateinit var mockedAuthFilter: AuthFilter
#BeforeEach
fun setup() {
assertNotNull(mockedAuthFilter)
`when`(
mockedAuthFilter.shouldProceed(
any(HttpServletRequest::class.java),
any(AuthConfig::class.java)
)
).thenReturn(true)
}
#Test
fun `This call should return without an error`() {
mockMvc.perform(get("/api/entities")).andDo(print()).andExpect(status().isOk)
}
}
All I can find in the web for this error is that you tried an argument matcher on a basic type - but that is not the case here. Have you faced this problem and how did you solve it?
From my understanding the failure comes from a masked nullpointer exception caused by the shouldProceed method itself which doesn't allow a call with nulled arguments, which kind of happens internally in Mockito during the setup of the mocked instance after any() returns.
The solution was to not use Mockito with Kotlin, but the MockK test utility instead.

kotlinx.serialization: inject local parameter

I need to inject a local value to a class constructor during deserialization. For example, look at the following class.
#Serializable
class SomeClass(val local: Context, val serialized: String)
I want the field local to be skipped during serialization and substituted with some predefined local value during deserialization.
The reason behind is that I'm going to transfer models through network, but operations on these models rely on a local context which I want to inject.
Because I haven't find any standard ways to achieve it, I've decided to make use of contextual serialization. So I have written the serializer:
class ContextualInjectorSerializer<T>(private val localValue: T) : KSerializer<T> {
override val descriptor = SerialDescriptor("ValueInjection", StructureKind.OBJECT)
override fun deserialize(decoder: Decoder): T {
decoder.beginStructure(descriptor).endStructure(descriptor)
return localValue
}
override fun serialize(encoder: Encoder, value: T) {
encoder.beginStructure(descriptor).endStructure(descriptor)
}
}
And used it this way:
// Context is marked with #Serializable(with = ContextSerializer::class)
val json = Json(JsonConfiguration.Stable, SerializersModule {
contextual(Context::class, ContextualInjectorSerializer(context))
})
// serialize/deserialize
Surprisingly, it works pretty fine on JVM. However, when I compiled it to JS and tested, I got TypeError: Cannot read property 'siteId' of undefined. Here siteId is a field of Context which I try to access.
Is there a standard way to inject local parameters? What's wrong with my trick?

Why use #singleton instead using simply object

In Kotlin, a common use for object is using it for singletons, like:
object MyObject {
...
}
However, when using micronaut framework, the official documentation recommends using something like this:
#Singleton
class V8Engine : Engine {
override var cylinders = 8
override fun start(): String {
return "Starting V8"
}
}
Why can't I use simply object instead of using annotation #Singleton with a class?
With a #Singleton, Micronaut can automatically manage dependencies between beans. If you go with the other class in https://docs.micronaut.io/latest/guide/ioc.html#beans, translated to Kotlin:
#Singleton
class Vehicle(private val engine: Engine) {
public fun start() = engine.start()
}
It can't be just an object because takes a parameter.
This parameter is discovered by Micronaut to be the singleton instance of V8Engine, which needs that to be a #Singleton and not an object.
Of course, in this case you could just directly use V8Engine in Vehicle; but it's easier to change e.g. if you want Engine not to be a singleton anymore.
Why can't I use simply object instead of using annotation #Singleton
with a class?
You can use object instead of using #Singleton with a class. Micronaut won't manage instances for you, but that is allowed.

How to inject dependency using koin in top level function

I have top-level function like
fun sendNotification(context:Context, data:Data) {
...//a lot of code here
}
That function creates notifications, sometimes notification can contain image, so I have to download it. I`m using Glide which is wrapped over interface ImageManager, so I have to inject it. I use Koin for DI and the problem is that I cannot write
val imageManager: ImageManager by inject()
somewhere in my code, because there is no something that implements KoinComponent interface.
The most obvious solution is to pass already injected somewhere else imageManager as parameter of function but I dont want to do it, because in most cases I dont need imageManager: it depends on type of Data parameter.
Easiest way is to create KoinComponent object as wrapper and then to get variable from it:
val imageManager = object:KoinComponent {val im: ImageManager by inject()}.im
Btw its better to wrap it by some function, for example I use
inline fun <reified T> getKoinInstance(): T {
return object : KoinComponent {
val value: T by inject()
}.value
}
So if I need instance I just write
val imageManager:ImageManager = getKoinInstance()
or
val imageManager = getKoinInstance<ImageManager>()
I did it in this way
fun Route.general() {
val repo: OperationRepo by lazy { GlobalContext.get().koin.get() }
...
}

How to write a package-level static initializer in Kotlin?

A previous question shows how to put a static initializer inside a class using its companion object. I'm trying to find a way to add a static initializer at the package level, but it seems packages have no companion object.
// compiler error: Modifier 'companion' is not applicable inside 'file'
companion object { init { println("Loaded!") } }
fun main(args: Array<String>) { println("run!") }
I've tried other variations that might've made sense (init on its own, static), and I know as a workaround I can use a throwaway val as in
val static_init = {
println("ugly workaround")
}()
but is there a clean, official way to achieve the same result?
Edit: As #mfulton26's answer mentions, there is no such thing as a package-level function really in the JVM. Behind the scenes, the kotlin compiler is wrapping any free functions, including main in a class. I'm trying to add a static initializer to that class -- the class being generated by kotlin for the free functions declared in the file.
Currently there is no way to add code to the static constructor generated for Kotlin file classes, only top-level property initializers are getting there. This sounds like a feature request, so now there is an issue to track this: KT-13486 Package-level 'init' blocks
Another workaround is to place initialization in top-level private/internal object and reference that object in those functions that depend on the effect of that initialization. Objects are initialized lazily, when they are referenced first time.
fun dependsOnState(arg: Int) = State.run {
arg + value
}
private object State {
val value: Int
init {
value = 42
println("State was initialized")
}
}
As you mentioned, you need a property with something that would run on initialisation:
val x = run {
println("The package class has loaded")
}
I got around it by using a Backing Property on the top-level, under the Kotlin file. Kotlin Docs: Backing Properties
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null) {
_table = HashMap() // Type parameters are inferred
// .... some other initialising code here
}
return _table ?: throw AssertionError("Set to null by another thread")
}