I am new to Scala and I need to have a scala wrapper for my Java API
I have three Java Interfaces
public interface Client<T> {
<T> Future<T> execute(App<T> app);
}
public interface App<T> extends Serializable{
T process(AppContext context) throws Exception;
}
public interface AppContext {
File getDirectory();
void deleteDirectory();
File createDirectory(String path);
}
Following is the Java code to create an App
public class RandomApp extends App<String> {
#Override
public String process(AppContext context) {
// Inorder to access the methods in AppContext I need to access
// it by the following way
appContext.createDirectory("some path");
return "random";
}
}
I want to have a Scala Wrapper for the Client Interface which in turn call the Java API. But I have some modifications for the new Scala API
object ScalaConverter {
implicit class ScalaWrapper(client: Client) {
def scalaClient = new ScalaClient(client)
}
}
class ScalaClient(client: Client) {
def execute[T](appContext: AppContext => T): Future[T] = {
// I am passing appContext as closure instead of passing in
// App because I want to take the advantage of Closures in Scala
// I basically want to create an App with this appContext and
// pass it to the execute method
// For example - but this is not working
var app = // Need to create this app with appContext
Future {
client.execute(app)
}
}
}
If I'm not mistaken, you just want to be able to create App objects from a function that takes a AppContext as parameter and returns a any object (let's say T).
As it's not really interesting to try to mirror the whole java API, just use it as it is, but add some extensions. And to do this you should use implicits.
To do this, I see two possibilities: either add an implicit class on the Client interface to add some functions to it, or add an implicit conversion from (AppContext => T) to App objects.
Let's got with the first solution, you have to embed the implicit class in an object (this can be a package object if you need automatic imports).
object ScalaConverter {
class ScalaApp[T](val block: AppContext => T) extends App[T] {
def process(context: AppContext): T = block(context)
}
implicit class ScalaClient(client: Client) extends AnyVal{
def execute[T](block: AppContext => T): Future[T] = {
client.execute(new ScalaApp(block))
}
}
}
Then, you just have to use your existing java Client object:
import ScalaConverter._
myJavaClient.execute { context =>
???
}
You should get the principle, I maybe made a mistake (did not tried to compile this)
Related
Assume we have the following suspend function:
suspend fun doSomething(): List<MyClass> { ... }
If I want to call this function in one of my existing Java classes (which I'm not able to convert to Kotlin for now) and get its return value I have to provide a Continuation<? super List<MyClass>> as its parameter (Obviously).
My question is, How can I implement one. Specially its getContext getter.
First, add org.jetbrains.kotlinx:kotlinx-coroutines-jdk8 module to your dependencies. In your Kotlin file define the following async function that corresponds to Java style of writing async APIs:
fun doSomethingAsync(): CompletableFuture<List<MyClass>> =
GlobalScope.future { doSomething() }
Now use doSomethingAsync from Java in the same way as you are using other asynchronous APIs in the Java world.
If you dont want to use org.jetbrains.kotlinx:kotlinx-coroutines-jdk8, I have a new idea.
Write below code in your kotlin project.
#JvmOverloads
fun <R> getContinuation(onFinished: BiConsumer<R?, Throwable?>, dispatcher: CoroutineDispatcher = Dispatchers.Default): Continuation<R> {
return object : Continuation<R> {
override val context: CoroutineContext
get() = dispatcher
override fun resumeWith(result: Result<R>) {
onFinished.accept(result.getOrNull(), result.exceptionOrNull())
}
}
}
I write it in my Coroutines class
Then you can call your suspend function like:
Coroutines coroutines = new Coroutines();
UserUtils.INSTANCE.login("user", "pass", coroutines.getContinuation(
(tokenResult, throwable) -> {
System.out.println("Coroutines finished");
System.out.println("Result: " + tokenResult);
System.out.println("Exception: " + throwable);
}
));
login() function is a suspend function.
suspend fun login(username: String, password: String): TokenResult
For your code, you can:
doSomething(getContinuation((result, throwable) -> {
//TODO
}));
Besides, you may want to run your callback code in different thread (e.g. Main thread), just use launch(Dispathers.Main) to wrap resumeWith()
Update: My friend has developed a plugin kotlin-jvm-blocking-bridge that can automatically generate blocking bridges for calling suspend functions from Java with minimal effort, also give it a try.
For coroutines 1.3.0 use this:
BuildersKt.launch(GlobalScope.INSTANCE,
Dispatchers.getMain(),//context to be ran on
CoroutineStart.DEFAULT,
(coroutineScope, continuation) -> suspendFunction(arguments)
);
For java < 8:
BuildersKt.launch(
GlobalScope.INSTANCE,
Dispatchers.getMain(),//context to be ran on
CoroutineStart.DEFAULT,
new Function2<CoroutineScope, Continuation<? super Unit>, Unit/*or your return type here*/>() {
#Override
public Unit/*or your return type here*/ invoke(CoroutineScope coroutineScope, Continuation<? super Unit> continuation) {
//do what you want
return Unit.INSTANCE; //or something with the defined type
}
}
);
My gradle file:
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.50"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0"
Kotlin uses static classes for extension functions, launch is an extension function, so it is defined in BuildersKt. The first parameter is the target of the extension function, the rest are the parameters from the extension functions.
I created interface class based on #Kenvix answer to make it compatible with old Android SDK (lower than API 24)
interface CoroutineCallback<RESULT> {
companion object {
#JvmOverloads
fun <R> call(
callback: CoroutineCallback<R>,
dispatcher: CoroutineDispatcher = Dispatchers.Default
): Continuation<R> {
return object : Continuation<R> {
override val context: CoroutineContext
get() = dispatcher
override fun resumeWith(result: Result<R>) {
callback.onComplete(result.getOrNull(), result.exceptionOrNull())
}
}
}
}
fun onComplete(result: RESULT?, error: Throwable?)
}
usage
class kotlinClass {
suspend doSomething(foo, bar) : FooBar {}
}
class javaClass {
void doSomething(){
kotlinClassObject.doSomething("foo", "bar", CoroutineCallback.Companion.call((fooBar, error) -> {
//do something with result or error
}));
}
}
now call suspend function from any java class by passing CoroutineCallback
Assume we have the following suspend function:
suspend fun doSomething(): List<MyClass> { ... }
If I want to call this function in one of my existing Java classes (which I'm not able to convert to Kotlin for now) and get its return value I have to provide a Continuation<? super List<MyClass>> as its parameter (Obviously).
My question is, How can I implement one. Specially its getContext getter.
First, add org.jetbrains.kotlinx:kotlinx-coroutines-jdk8 module to your dependencies. In your Kotlin file define the following async function that corresponds to Java style of writing async APIs:
fun doSomethingAsync(): CompletableFuture<List<MyClass>> =
GlobalScope.future { doSomething() }
Now use doSomethingAsync from Java in the same way as you are using other asynchronous APIs in the Java world.
If you dont want to use org.jetbrains.kotlinx:kotlinx-coroutines-jdk8, I have a new idea.
Write below code in your kotlin project.
#JvmOverloads
fun <R> getContinuation(onFinished: BiConsumer<R?, Throwable?>, dispatcher: CoroutineDispatcher = Dispatchers.Default): Continuation<R> {
return object : Continuation<R> {
override val context: CoroutineContext
get() = dispatcher
override fun resumeWith(result: Result<R>) {
onFinished.accept(result.getOrNull(), result.exceptionOrNull())
}
}
}
I write it in my Coroutines class
Then you can call your suspend function like:
Coroutines coroutines = new Coroutines();
UserUtils.INSTANCE.login("user", "pass", coroutines.getContinuation(
(tokenResult, throwable) -> {
System.out.println("Coroutines finished");
System.out.println("Result: " + tokenResult);
System.out.println("Exception: " + throwable);
}
));
login() function is a suspend function.
suspend fun login(username: String, password: String): TokenResult
For your code, you can:
doSomething(getContinuation((result, throwable) -> {
//TODO
}));
Besides, you may want to run your callback code in different thread (e.g. Main thread), just use launch(Dispathers.Main) to wrap resumeWith()
Update: My friend has developed a plugin kotlin-jvm-blocking-bridge that can automatically generate blocking bridges for calling suspend functions from Java with minimal effort, also give it a try.
For coroutines 1.3.0 use this:
BuildersKt.launch(GlobalScope.INSTANCE,
Dispatchers.getMain(),//context to be ran on
CoroutineStart.DEFAULT,
(coroutineScope, continuation) -> suspendFunction(arguments)
);
For java < 8:
BuildersKt.launch(
GlobalScope.INSTANCE,
Dispatchers.getMain(),//context to be ran on
CoroutineStart.DEFAULT,
new Function2<CoroutineScope, Continuation<? super Unit>, Unit/*or your return type here*/>() {
#Override
public Unit/*or your return type here*/ invoke(CoroutineScope coroutineScope, Continuation<? super Unit> continuation) {
//do what you want
return Unit.INSTANCE; //or something with the defined type
}
}
);
My gradle file:
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.50"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0"
Kotlin uses static classes for extension functions, launch is an extension function, so it is defined in BuildersKt. The first parameter is the target of the extension function, the rest are the parameters from the extension functions.
I created interface class based on #Kenvix answer to make it compatible with old Android SDK (lower than API 24)
interface CoroutineCallback<RESULT> {
companion object {
#JvmOverloads
fun <R> call(
callback: CoroutineCallback<R>,
dispatcher: CoroutineDispatcher = Dispatchers.Default
): Continuation<R> {
return object : Continuation<R> {
override val context: CoroutineContext
get() = dispatcher
override fun resumeWith(result: Result<R>) {
callback.onComplete(result.getOrNull(), result.exceptionOrNull())
}
}
}
}
fun onComplete(result: RESULT?, error: Throwable?)
}
usage
class kotlinClass {
suspend doSomething(foo, bar) : FooBar {}
}
class javaClass {
void doSomething(){
kotlinClassObject.doSomething("foo", "bar", CoroutineCallback.Companion.call((fooBar, error) -> {
//do something with result or error
}));
}
}
now call suspend function from any java class by passing CoroutineCallback
I'm currently designing database for a mobile application. Recently I found very useful function to access database in background:
private val IO_EXECUTOR = Executors.newSingleThreadExecutor()
fun ioThread(f : () -> Unit) {
IO_EXECUTOR.execute(f)
}
Besides that I figured out that don't need synchronization code as the database will be accessed only in one thread (i.e the thread used by SingleThreadExecutor).
The only issue is that the following methods have to be restricted to be invoked only through ioThread function (or using IO_EXECUTOR).
abstract class MyDatabase : RoomDatabase() {
companion object {
fun init(context: Context) { ... }
fun getInstance() { ... }
}
Is it possible to achieve this in Kotlin/Java?
UPDATE: for now I have this implementation but think there should be better ones
// App.kt file
private val IO_EXECUTOR = Executors.newSingleThreadExecutor()
private var IO_THREAD_ID: Long = -1L
private fun getIOThreadId(): Long {
if (IO_THREAD_ID == -1L)
IO_THREAD_ID = IO_EXECUTOR.submit(Callable<Long> { Thread.currentThread().id }).get()
return IO_THREAD_ID
}
fun notInIOThread() = Thread.currentThread().id != getIOThreadId()
fun ioThread(f : () -> Unit) {
IO_EXECUTOR.execute(f)
}
and then use notInIOThread() in init() and getInstance() functions
If you absolutely need to make sure that the code is running on the correct thread, you could make use of a custom thread and then checking Thread.currentThread() for the interface.
private interface MarkedIOThread // Marker interface
private val IO_EXECUTOR = Executors.newSingleThreadExecutor { r ->
return object : Thread(r), MarkedIOThread
}
fun notInIOThread(): Boolean = Thread.currentThread() !is MarkedIOThread
Yes, you can use android annotations`s Worker Thread annotation.
When you annotate a method or class with #WorkerThread, android will give you lint errors if you call it from the UI thread.
You can read more about the #WorkerThread here: https://developer.android.com/reference/android/support/annotation/WorkerThread
And more about android annotations here: https://developer.android.com/studio/write/annotations
I would suggest that you should check room library: https://developer.android.com/topic/libraries/architecture/room
It is very powerful, if you don't have any specific reason to create a database library, room is your best bet.
I assume you want the functions to be called only inside ioThread code block, otherwise there'd be a type error. First make them member functions of a class with user-code-inaccessible constructor so others cannot call it directly:
class MyDslClass internal constructor() {
fun init(context: Context) { ... }
fun getInstance() { ... }
}
And ioThread should be:
fun ioThread(f : MyDslClass.() -> Unit) {
val dsl = MyDslClass()
IO_EXECUTOR.execute { dsl.f() }
}
Then you can restrict calls to those functions only inside ioThread block.
fun main(args: Array<String>) {
ioThread {
getInstance() // Ok
}
// cannot call `getInstance` since I cannot construct a `MyDslClass`
}
I have a kotlin web request method that takes a function as a parameter.
Due to how one of my classes is set up, I need to keep it as a java class but I need to call the web request method from the java class.
I have a class called Lock that I am fetching from my database using Fuel
My kotlin method is as follows
fun fetchLocks(completion: (Array<Lock>) -> Unit) {
// asynchronous api calls that aren't relevant.
completion(locks)
}
I know that this method works and am able to call it from a kotlin file
FuelHelper().fetchLocks { locks ->
Do stuff with my locks
}
The issue I am having is getting the proper syntax in order to call this method in java.
new FuelHelper().fetchLocks();
The parameter java expects is (Function1<?super Lock[], Unit>)
I have tried for a while now and am unable to get past this. Any help would be appreciated.
Assuming that you are using java 8 syntax.
new FuelHelper().fetchLocks(locks -> {
...
});
Or without lambda
new FuelHelper().fetchLocks(new Function1<Lock[], Unit>() {
#Override
public Unit invoke(Lock[] locks) {
return null;
}
});
It's exactly what it says - You have to pass an object implementing interface Function1 (source from generated file Functions.kt):
/** A function that takes 1 argument. */
public interface Function1<in P1, out R> : Function<R> {
/** Invokes the function with the specified argument. */
public operator fun invoke(p1: P1): R
}
In your case you create an anonymous class the same way you do for all small listeners like onClicks etc.:
new FuelHelper().fetchLocks(new Function1<Lock[], Unit>() {
#Override
public Unit invoke(Lock[] locks) {
// handle locks
return null;
}
});
It has been a couple of days since I started with Groovy. But with all the reading and surfing, I haven't quite been able to figure out how to accomplish what I have in mind. So, please excuse me as a beginner. Would be much grateful for your help, as always.
What I want to achieve is this: I have a Java class, say ServiceClass that has some methods (getMethod(), postMethod() etc) to make some REST GET/POST requests (on its own, it works fine). Now, I want to expose a DSL so that the end-user may just say something like: callService ServiceClass method getMethod and I have the execution of ServiceClass.getMethod()
What I have been trying so far is this: I got a userCommand file placed somewhere, that for now just reads: callService ServiceClass
I have a sample.groovy that just does this now:
class Sample {
def srvc
def callService(srvc) {
this.srvc = srvc
"Calling $srvc"
}
}
I got an integrator.groovy file that has:
//necessary imports
class Integrator{
def sample = new Sample()
def binding = new Binding([
sample:sample,
ServiceClass: new ServiceClass(),
callService:sample.&callService ])
def shell = new GroovyShell(binding)
def runIt() {
shell.evaluate("userCommand")
}
}
And then to run it from my Java application, I am doing:
public static void main(String[] args) {
Integator i = new Integrator()
i.runIt();
}
But this is just not working. With the above syntax it says:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke method setVariable() on null object....
Could anyone please tell me how do I pass around parameters and create object instances?
Update: Consider the following userCommand file:
File userCommand:
callService ServiceClass getMethod
Which will be parsed by groovy as callService(ServiceClass).getGetMethod(). So you need a getProperty method which reroute the call to the correct method:
File Dsl.groovy:
class Dsl {
static void main(args) {
new Integrator().runIt()
}
}
class DslDelegate {
def service
def callService(service) {
this.service = service
this
}
def getProperty(String prop) {
if (prop == "getMethod") { service.getMethod() }
else { throw new RuntimeException("Unrecognized property '$prop'") }
}
}
class ServiceClass {
def getMethod() { "serviceClass getMethod" }
}
class Integrator{
def dslDelegate = new DslDelegate()
def binding = new Binding([
ServiceClass: new ServiceClass(),
callService:dslDelegate.&callService ])
def shell = new GroovyShell(binding)
def runIt() {
assert shell.evaluate(new File("userCommand")) ==
"serviceClass getMethod"
}
}
Note I renamed the Sample class, so it becomes a delegator to ServiceClass. Now it separates DSL/Service responsibilities.
You can do callService ServiceClass method getMethod too, but it requires more code.