KMM library and context - kotlin-multiplatform

I am doing kmm library.
I would like to be able to have something like that:
In commonMain
expect class UploadManager() {
fun execute()
}
In androidMain:
actual class UploadManager() {
fun execute(){
WorkManager.getInstance(context).enqueue(WorkRequestManager().getWorkRequest())
}
}
How can I get context in android part of shared module?

Related

Error trying to call Java method from Rascal

I am trying to call a Java method from Rascal, but I'm getting this error:
Cannot link method com.mypackage.Teste because: class not found
Rascal code:
#javaClass{com.mypackage.Teste}
java void testeJava();
Java code:
package com.mypackage;
public class Teste {
public void testeJava() {
System.out.println("it worked");
}
}
The com.mypackage package is inside my src folder, along with all of the Rascal code. I've also tried to use src.com.mypackage.Teste as well, but had the same result.
What am I doing wrong?
The class needs one constructor that has one argument of the IValueFactory type. You will often store this in a field, as it is the way to respond to the function call. (Build IValues with this factory)
package com.mypackage;
import io.usethesource.vallang.IValueFactory;
public class Teste {
private final IValueFactory vf;
public Tests(IValueFactor vf) {
this.vf = vf;
}
public void testeJava() {
System.out.println("it worked");
}
}

Calling injected services from class instances

I'm writing an Angular2 app. Consider a class Cat which I instantiate many instances of, which has an API method to write itself out:
class Cat {
constructor(private name: string) { }
public write() {
Api.write(this); // <== how do I do this?
}
}
The Cat#write method needs to access an API service wrapped around Http:
#Injectable()
class Api {
constructor(private http: Http) { }
write(data) {
this.http.post(...);
}
}
The (perhaps trivially simple) problem I have is how to access API#write from within my Cat class. Since I need the Cat constructor to pass in the name, I can't use it for injection. So how do I make the API#write available to it? Is there some way to access the singleton instance of Api? In that case, who would be in charge of instantiating the singleton instance?
I played around with a static API class but this obviously doesn't work, since injection is into instances, not static classes.
What basic design pattern am I missing here?
I've been struggling with this for a while as well. I did come up with sort of a solution, but it feels hacky.
I use a singleton AppInjector instance. It is set only once, in the constructor of AppComponent (the bootstrapped component). It is used to resolve dependencies for objects to create.
This AppInjector looks something like this:
export class AppInjector {
private static _INJECTOR: Injector;
public static set INSTANCE(injector: Injector) {
if (!this._INJECTOR) {
this._INJECTOR = injector;
}
}
public static get INSTANCE() : Injector {
return this._INJECTOR;
}
}
And the contructor of the AppComponent looks like this:
constructor(injector: Injector) {
AppInjector.INSTANCE = injector;
}
Now if you have added your Api in the bootstrap function of your application:
bootstrap(AppComponent, [Api]);
You will be able to get this singleton from within the Cat instance like this:
class Cat {
public get _api() : Api {
return AppInjector.INSTANCE.get(Api);
}
constructor(private name: string) { }
public write() {
this._api.write(this);
}
}
Again, this by no means feels like the right solution, and probably against a lot of guidelines in Angular2, but I understand your problem, and would also like a better solution than this, but it works fine now for as it is, and I can happily continue coding

Bind list of objects using Guice + Kotlin

I'm writing a JavaFX application in Kotlin with the following controller definition:
class MainController {
#Inject private lateinit var componentDescriptors: List<ComponentDescriptor>
/* More code goes here */
}
I'm using Guice for Dependency management. And I'm trying to inject the list of class instances loaded via java.util.ServiceLoader. My problem is to define a binding that will inject the list of loaded object instances into the declared field. I tried annotation based provisioning:
internal class MyModule: AbstractModule() {
override fun configure() { }
#Provides #Singleton
fun bindComponentDescriptors(): List<ComponentDescriptor> =
ServiceLoader.load(ComponentDescriptor::class.java).toList()
}
and multibinding extension (switched List to Set in field definition of corse):
internal class MyModule: AbstractModule() {
override fun configure() {
val componentDescriptorBinder = Multibinder.newSetBinder(binder(), ComponentDescriptor::class.java)
ServiceLoader.load(ComponentDescriptor::class.java).forEach {
componentDescriptorBinder.addBinding().toInstance(it)
}
}
}
but both of these approaches leads to the same error:
No implementation for java.util.List<? extends simpleApp.ComponentDescriptor> was bound.
while locating java.util.List<? extends simpleApp.ComponentDescriptor>
for field at simpleApp.MainController.componentDescryptors(MainController.kt:6)
while locating simpleApp.MainController
1 error
at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1042)
at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1001)
at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1051)
at com.gluonhq.ignite.guice.GuiceContext.getInstance(GuiceContext.java:46)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:929)
at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:971)
at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:220)
at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:744)
at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2707)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2527)
... 12 more
I'm starting to suspect that it somehow related to Kotlin gerenic variance and Guice strict type checking. But I don't know how to declare the binding so Guice will know what to inject into this field.
Yes, it happens because of variance but there's a way to make it work.
class MainController {
#JvmSuppressWildcards
#Inject
private lateinit var componentDescriptors: List<ComponentDescriptor>
}
By default Kotlin generates List<? extends ComponentDescriptor> signature for the componentDescriptors field. The #JvmSuppressWildcards makes it generate a simple parameterized signature List<ComponentDescriptor>.
#Michael gives the correct answer and explanation. Here's an example of one strategy for unit testing a Set multibinding for those that like to test their modules:
class MyModuleTest {
#JvmSuppressWildcards
#Inject
private lateinit var myTypes: Set<MyType>
#Before fun before() {
val injector = Guice.createInjector(MyModule())
injector.injectMembers(this)
}
#Test fun multibindings() {
assertNotNull(myTypes)
assertTrue(myTypes.iterator().next() is MyType)
}
}
#Michael comment is working. If you want to do the injection in constructor, you need do something like
class MainController #Inject consturctor(
private var componentDescriptors: List<#JvmSuppressWildcards ComponentDescriptor>
) {}

In Dart, how do I get code completion when using noSuchMethod?

I'd like to use noSuchMethod to reduce boilerplate when writing a lot of similar methods. But then the API is worse for my library's users because code completion no longer works. I tried this but I get warnings about unimplemented methods:
class ThingMixin {
foo();
bar();
noSuchMethod(Invocation inv) {
...
}
}
Is there a workaround?
The trick is to define the API in a separate class:
abstract class ThingApi {
foo();
bar();
}
class ThingMixin implements ThingApi {
noSuchMethod(Invocation inv) {
...
}
}
(Note that noSuchMethod cannot call super if you want it to work as a mixin.)

Dagger Modules with constructor arguments?

In Guice, I had full control over when Modules were constructed, and used some Modules with constructor arguments that I installed.
In Dagger however, the method of referencing other Modules is through the #Module includes annotation, and doesn't present me with the same method of creating Modules to install.
Is it possible to create a sane ObjectGraph from multiple Modules that have constructor arguments? Especially one that will work with dagger-compiler, and not run into a cyclical graph?
If you have multiple modules with that use the same object then maybe you should separate that object into its own module. For example, a lot of the Modules use the Application context so I have the following module:
#Module
public class ContextModule {
private final Context mContext;
public ContextModule(Context context) {
mContext = context;
}
#Provides
public Context provideContext() {
return mContext;
}
}
So now in other modules when when I need a context object I just include the module.
For example:
#Module(entryPoints = { MyFragment.class }, includes = { ContextModule.class })
public class ServicesModule {
#Provides
public LocationManager provideLocationManager(Context context) {
return (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
}
#Provides
public Geocoder provideGeocoder(Context context) {
return new Geocoder(context);
}
}
Then when I construct the object graph I end up with only one module that takes the application context as its argument.
ObjectGraph.create() takes a variable list of modules (Varargs) so you are able to do this:
ObjectGraph objectGraph = ObjectGraph.create(new ProductionModule(context), new OverridingTestModule());
Take a look at Dagger's InjectionTest.java (see test "moduleOverrides" there): https://github.com/square/dagger/blob/master/core/src/test/java/dagger/InjectionTest.java

Resources