Exception when I change to other scene in KorGE - kotlin

com.soywiz.korinject.AsyncInjector$NotMappedException: Class 'class ChooseCampaign (Kotlin reflection is not available)' doesn't have constructors RequestContext(initialClazz=class ChooseCampaign (Kotlin reflection is not available))
Above exception was threw when I compiled current code. And I dont know how fix it and what does it means.
My code:
textButton {
position(0, 128)
text = "Play"
onClick {
println("Play")
launchImmediately {
sceneContainer.changeTo<ChooseCampaign>()
}
}
}
How it fix?

When using Scenes in KorGE, you are using the korinject dependency injector indirectly.
And that injector requires manual mapping. If you are using Modules, you can configure those mappings at the Module.init method.
Check this sample: https://github.com/korlibs/korge-samples/blob/1771b7ca7f4440e1a368ff4b441e97bf62e08b8d/sample-scenes/src/commonMain/kotlin/main.kt#L15-L23
In your case, once you get the Injector instance, you can map a scene like this:
mapPrototype { ChooseCampaign(get()) }
You have to put as many get() as parameters your ChooseCampaign constructor has.
In the case you are not using modules, the place to put the mapping is different, and you need to get the Injector instance.
In your suspend fun main() = Korge { block, you have the Stage singleton injected. This is the root view that has a reference to the Views singleton.
So there you can just access the injector like this: this.views.injector
You can then map your scenes whenever you like, though I suggest you do to it at the beginning of the application.

Related

Null property provided by Gradle when using custom plugin

I'm trying to follow the Gradle custom plugin documentation to create a plugin that can be configured.
My plugin code:
interface MyExtension {
var myValue: Property<String>
}
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
val extension = project.extensions.create<MyExtension>("myExt")
}
}
in build.gradle.kts:
plugins {
`java-library`
}
apply<MyPlugin>()
the<MyExtension>().myValue.set("some-value")
Running this will give
Build file '<snip>/build.gradle.kts' line: 6
java.lang.NullPointerException (no error message)
Turns out the the<MyExtension>().myValue is null, so the set call fails. How do I do this correctly? Did I miss something in the documentation, or is it just wrong?
The documentation is not wrong. Properties can be managed by either you or by Gradle. For the latter, certain conditions have to be met.
Without managed properties
If you want to be completely in charge, you can instantiate any variables you declare yourself. For example, to declare a property on an extension that is an interface, it could look like this:
override fun apply(project: Project) {
val extension = project.extensions.create("myExt", MyExtension::class.java)
extension.myValue = project.objects.property(String::class.java)
}
Or you could instantiate it directly in the extension by making it a class instead:
open class MessageExtension(objects: ObjectFactory) {
val myValue: Property<String> = objects.property(String::class.java)
}
However, a property field is not really supposed to have a setter as the property itself has both a setter and a getter. So you should generally avoid the first approach and remove the setter on the second.
See here for more examples on managing the properties yourself.
With managed properties
To help you reduce boilerplate code, Gradle can instantiate the properties for you with what is called managed properties. To do use these, the property must not have a setter, and the getter should be abstract (which it implicitly is on an interface). So you could go back to your first example and fix it by changing var to val:
interface MyExtension {
val myValue: Property<String> // val (getter only)
}
Now Gradle will instantiate the field for you. The same thing works for abstract classes.
Read more about managed properties in the documentation here.

Dagger Dependency Injection in main function

I am calling a function in a class S3FileOperationsAdapter from the main function in my kotlin code. I am injecting the class S3FileOperationsAdapter in the main function file. So it looks like
class Runner {
#set:Inject
lateinit var s3FileOperationsAdapter: S3FileOperationsAdapter
fun main(args: Array<String>) {
s3FileOperationsAdapter.readFunction()
}
}
Now the issue is:
When I try to run the above code, I get the error Error: Main method is not static in class com.amazon.bram.sim.BatchJobRunner, please define the main method as:. This is understandable.
And we can only make a static function within an object in kotlin. So upon doing that, I cannot Inject the dependency, because Dagger does not support injection into Kotlin objects. So it feels like a deadlock.
My question is, I want to inject the dependency in this file anyhow so that I can call the respective function. And I am calling this function from the "fun main()" in kotlin. How can I achieve this? Has anyone ever faced this before?
In order to inject anything in Dagger, you must first create an instance of your component. Since no code at all will run before fun main(), this needs to be done during main itself (or in a field initializer).
After creating an instance of the component, you can ask it for an instance of S3FileOperationsAdapter directly.
fun main(args: Array<String>) {
// Create the component.
val component = DaggerMyComponent.create()
// or use the Component.Builder or Component.Factory you defined for MyComponent.
// Get an object from the component.
// This method should be defined in your component interface.
val adapter = component.s3FileOperationsAdapter()
// Use the object.
adapter.readFunction()
}
If your actual code is more complicated, with multiple injected objects and a longer main() function, this may be a bit unwieldy. In that case, you can extract your current main() into its own class and let Dagger provide that class in main().

Kotlin Multiplatform: IllegalStateException: Must be main thread

I'm using Koin 3.0.0-alpha-4 version and when I'm trying to use injected class by koin, then it throws exception for iOS side:
KotlinException=kotlin.IllegalStateException: Must be main thread, KotlinExceptionOrigin
I have a singleton class where I'm initializing objects using koin like that:
#ThreadLocal
object ObjectFactory : KoinComponent{
val appStateRepository: AppStateRepository by inject()
val appStateRepositoryDemo = AppStateRepository()
}
if I use appStateRepository inside background thread (Dispatchers.Default), which is injected by koin, then it throws exception IllegalStateException: Must be main thread, but if I use appStateRepositoryDemo than it works fine
Here is a method which I'm invoking from iOS to inject modules
fun initKoinIos(
userDefaults: NSUserDefaults,
doOnStartup: () -> Unit
): KoinApplication = initKoin {
module {
...
single { doOnStartup }
}
}
fun initKoin(appDeclaration: KoinAppDeclaration = {}) = startKoin {
appDeclaration()
modules(
platformModule,
networkModule,
useCaseModules,
repositoryModule,
commonUtils,
)
}
Here is the usage:
fun testRepoAccess() {
ObjFactory.appStateRepository.test() // Ok, here we are in main thread
CoroutineScope(Dispatchers.Default).launch {
ObjFactory.appStateRepositoryDemo.test() // Ok
ObjFactory.appStateRepository.test() // Not Ok, throws exception (Must be main thread)
}
}
Expected behavior
It should work for iOS like it works Android
Koin 3.0.0-alpha-4
Additional moduleDefinition
Coroutines 1.4.2-native-mt
UPDATE
I was using wrong Koin library name, now I'm using :
io.insert-koin:koin-core:3.0.1
and now I have another exception:
kotlin.native.IncorrectDereferenceException: illegal attempt to access non-shared org.koin.core.context.GlobalContext.KoinInstanceHolder#1c02ca8 from other thread
Koin on Kotlin/Native requires injection on the main thread, to avoid freezing Koin state. As a result, you can't actually inject directly from a background thread.
Adding a special inject method that would allow you to inject by switching to the main thread was intended to be added to Koin, but I'm pretty sure that never wound up in the code. Primarily because it's very rare that anybody has needed it.
So, anyway, you can't do that with Koin. You could try Kodein, but I wrote Koin's implementation to throw precisely because touching Koin from another thread will freeze everything inside it, and that may not be what you intend to do.
I know nobody likes non-answers, but why is ObjectFactory #ThreadLocal? I assume to keep it mutable, but if appStateRepository is a single, it would be frozen anyway.

Kotlin. Can I get all Objects that implements specific interface

I have something like:
interface Options {
fun load(conf: JsonObject)
}
object BasicOptions : Options { }
object PersonOptions : Options { }
object CarOptions : Options { }
then I would like to get all Objects that implements Options interface and call load forEach.
fun main(args: Array) {
configFuture.whenComplete { config ->
options.forEach { it.load(config) }
}
}
This is not supported by the language, this is why there are Dependency Injection, Registry, or Service Lookup solutions.
If all objects are registered in a Dependency Injection framework, you may be able to iterate all objects registered to the framework and find the instances of your Interface.
This is likely to be rather inefficient - so cache the results to avoid the extra overhead.
Another approach is to use custom class loader and add this custom functionality. The simplest way is probably using the Reflections library, to scan and load these classes. E.g.:
val reflections = Reflections("my.project.prefix")
val allClasses = reflections.getSubTypesOf(Options::class.java)
The simplest, and most commonly used solution would be simply maintain your own "registry" e.g. a static object holding the list of all instances. It will require manually adding any new class implementing the interface - but it will be simple, performant, and robust solution.
Of course, you can!
Using the Reflections library it's really easy:
First, you need to find all the java classes that implement your interface "Objects". Then you convert the java classes to kotlin classes (KClass).
KClass has the property objectInstance that is null if the class does not have an object instance... otherwise IS the singleton object instance.
So:
val reflections = Reflections(ConfigurationBuilder())
val jList = reflections.getSubTypesOf(Options::class.java)
val kList = jList.map { it.kotlin }
val oList = kList.map { it.objectInstance }.filterNotNull()
;-)
You can always use the Factory pattern for creating new instances of Options, that way you can have your own OptionsFactory and your own caching mechanism.
That OptionsFactory after instantiating an object keeps it in cache (could be in-memory cache or DB..etc), then anytime you can ask the factory for it's cached instances when needed.
This is fairly better when your Options objects are created in run-time/upon demand.

guice injection: difference among getBinding/getExistingBinding/getProvider and getInstance

I have a PropertiesModule that extends AbstractModule and contains application constants that I use throughout the project:
class PropertiesModule: AbstractModule(), Serializable {
companion object {
const val APP_NAME = "MyAppName"
...
}
override fun configure() {
...
}
}
Then I use the PropertiesModule to create the injector:
...
val injector = Guice.createInjector(
PropertiesModule(),
...
)
And later when I use the injector to get the property value, I have multiple choices. I could do:
val appName = injector.getInstance(
Key.get(String::class.java, Names.named(PropertiesModule.APP_NAME))
)
or
val appName = injector.getExistingBinding(
Key.get(String::class.java, Names.named(PropertiesModule.APP_NAME))
).provider.get()
or
val appName = injector.getProvider(
Key.get(String::class.java, Names.named(PropertiesModule.APP_NAME))
).get()
I read that in general getInstance should be avoided. But I'm not sure what is the difference among them.
If you've just created your Injector, use getInstance. Otherwise, try to get your object from a narrower injection.
getBinding and getExistingBinding are effectively both for reflective purposes:
[Binding is] a mapping from a key (type and optional annotation) to the strategy for getting instances of the type. This interface is part of the introspection API and is intended primarily for use by tools.
Though it would probably work to some degree, I'd recommend against getExistingBinding, if only because it has the counterintuitive behavior of not creating Just-In-Time bindings if they do not already exist, as described in the getExistingBinding docs:
Unlike getBinding(Key), this does not attempt to create just-in-time bindings for keys that aren't bound.
This method is part of the Guice SPI and is intended for use by tools and extensions.
getProvider(Class<T>) will procure a Provider<T> from the graph, which is like a single-key Injector that can only create or retrieve instances of a single key from the Injector. Think of it as creating a lambda that calls getInstance for a specific Key, and nothing more.
getInstance is the most important method on Injector, and I expect all Guice applications to call it at least once. If you've just created your Injector, you'll presumably want to either get an instance from it, or inject the #Inject fields of an object. The former happens with getInstance, and the latter with injectMembers. In my opinion, that's the best way to get the first object out of your graph.
However, and this is where the advice you heard comes in: You should probably not use the Injector after that first getInstance or injectMembers call. This is because the goal in Guice is to make independent components that express their dependencies narrowly so you can replace those dependencies easily. This is the major benefit of dependency injection. Though you have the options of stashing the Injector somewhere static, or injecting the Injector itself into your dependencies, that prevents you from knowing exactly what your class's dependencies are: with an Injector injection, you can inject anything in the world.
To demonstrate (please forgive my Kotlin inexperience):
class BadIdea #Inject constructor(injector: Injector) {
fun doSomething() {
// Bad idea: you don't express this dependency anywhere, and this code
// is nearly unusable without a real Guice Injector
val appName = injector.getInstance(
Key.get(String::class.java, Names.named(PropertiesModule.APP_NAME))
)
}
}
class WorseIdea {
fun doSomething() {
// Worse idea: same as the above, but now you rely on a static!
val appName = StaticInjectorHolder.getInjector().getInstance(
Key.get(String::class.java, Names.named(PropertiesModule.APP_NAME))
)
}
}
class GoodIdea #Inject constructor(#Named(PropertiesModule.APP_NAME) appName: String) {
fun doSomething() {
// Good idea: you express your dep, and anyone can call the constructor
// manually, including you in your unit tests.
}
}