Is there a way to dynamically implement API interface classes in kotlin with bytebuddy? (Mixins pattern) - kotlin

Let me summerize what I am trying to achieve. Basically I want a way to have a set of interfaces which server an an api that external plugins use to interact with the engine.
Here is how I currently have things setup.
class Engine : ApiEngine {
override fun start() {
println("Starting Engine")
}
override fun stop() {
println("Stopping Engine.")
}
}
interface ApiEngine {
fun start()
fun stop()
}
This is cumbersome and I have seen some other solutions using ASM and injecting the interface dynamically into the "Engine" class. I have seen something like this in another source but never could fully figure out how to do.
#Implements("ApiEngine")
class Engine {
#Export("start")
fun start() {
println("Starting Engine")
}
#Export("stop")
fun stop() {
println("Stopping Engine.")
}
}
interface ApiEngine {
#Import("start")
fun start()
#Import("stop")
fun stop()
}
My question is, in ByteBuddy, is it possible to effively make Engine implement ApiEngine so that it an instance of Engine() can be cast to ApiEngine for API usage?

This is very much possible. You can for example integrate Byte Buddy as a build tool where you generate interfaces upon discovery. Simply implement the Plugin interface and match types based on your annotation being present.
As a next step, you would need to instrument those types to implement an additional interface using the DynamicType.Builder DSL that Byte Buddy provides you. If your methods always match their signature, there is nothing more to be done since Byte Buddy automatically detects those overrides. If the method signatures can vary, you would need to implement the interface methods using MethodCall to implement a delegation to the actual implementation.

Related

Mocking Gradle javaexec calls with mockK

Currently a beginner with mockK as it relates to developing Gradle plugin code in Kotlin. Suppose I have this class:
abstract class MyDomainObjectClass #Inject constructor(private val execOps: ExecOperations) {
abstract val mainClass: Property<String>
fun run() {
execOps.javaexec {
// ...
}
}
}
What I want to do is to construct a MyDomainObjectClass (normally constructed using something like ObjectFactory.newInstance()) in such a way that I can pass in a mocked ExecOperations, so that I can verify that the javaexec call is called exactly once (with the verification possibly involving mainClass, if I can find a way to involve it).
Is there a way I can satisfy all these requirements, or am I better off with a constructed mock of MyDomainObjectClass (stubbing in mainClass in the process)?

Is it a good idea to place the code of instance a class in a interface in Kotlin?

The Code A is from the project android/architecture-components-samples.
The author place the code of instance a class DefaultServiceLocator in the interface ServiceLocator.
In my mind , normally a interface should not include any implement code.
Is it a good idea to place the code of instance a class in a interface in Kotlin?
Code A
interface ServiceLocator {
companion object {
private val LOCK = Any()
private var instance: ServiceLocator? = null
fun instance(context: Context): ServiceLocator {
synchronized(LOCK) {
if (instance == null) {
instance = DefaultServiceLocator(
app = context.applicationContext as Application,
useInMemoryDb = false)
}
return instance!!
}
}
/**
* Allows tests to replace the default implementations.
*/
#VisibleForTesting
fun swap(locator: ServiceLocator) {
instance = locator
}
}
...
}
open class DefaultServiceLocator(val app: Application, val useInMemoryDb: Boolean) : ServiceLocator {
...
}
In my mind , normally a interface should not include any implement code.
Welcome back from hibernation ;) Yes, you could achieve the same with interface + abstract class but you can have default implementation also as part of the interface for some time now in many languages. Which way you go is up to you, but if you have only one abstract class implementing your interface then it is often handy to be able to merge this into one file for sake of ease of future maintenance.
As per kotlin interfaces documentation:
Interfaces in Kotlin can contain declarations of abstract methods, as well as method implementations. What makes them different from abstract classes is that interfaces cannot store state. They can have properties but these need to be abstract or to provide accessor implementations.
So... there's no problem in using method implementations on the interfaces. That feature might offer you extra power (if you like and need to use it).

Function interface in Kotlin 1.4

This feature will be coming Kotlin 1.4. Here is an excerpt from KotlinConf'19.
fun interface Action {
fun run()
}
fun runAction(a: Action) = a.run()
runAction{
println("Hello")
}
It looks nice, but I still don't know what it does.
What is the function interface? What is its practical value? What specific scenarios can it be used for?
This is about functional interfaces — interfaces with a Single Abstract Method (also called SAM interfaces).
To understand the point, I'll need to cover a little history…  In Java, lambdas were added relatively recently.  Before that, you implemented callbacks and similar by implementing a suitable interface.  For example, if you wanted to be informed when an AWT component was actioned, you'd create an object which implemented the ActionListener interface.  That has a single method (called actionPerformed()); you'd put your code inside that method:
myButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Do something
}
});
When they added lambdas, they wanted to blend in with all the existing code, and change as little as possible, so they did it exactly the same way: the compiler infers which interface you're implementing, and creates an object implementing that interface.  You could write:
myButton.addActionListener(e -> {
// Do something
});
which is shorter — but it compiles down to pretty much the same as the first example.
So in Java, functions are not first-class objects; lambdas are simply a more concise way to implement functional interfaces.
In Kotlin, however, functions are first-class objects: you can write a lambda (or an anonymous function) on its own, assign it, pass it to functions, return it from functions, and so on — so there's no need for SAM interfaces at all!
For easier interoperability with Java, Kotlin lets you easily implement Java SAM interfaces, in the same way you do from Java:
myButton.addActionListener {
// Do something
}
But Kotlin <= 1.3 doesn't let you implement Kotlin interfaces that way; you need to implement those explicitly.  (I suspect this was partly to encourage developers to use proper functions, with all their other advantages, and not rely on the Java-style workaround.)
Your example illustrates this.  It has an interface (Action) with one abstract method (run()).  It has a function (runAction()) which takes an instance of that interface.  And it has some code which wants to call that function, passing just the code for the run() method.
In Kotlin <= 1.3, you'd have to do the latter explicitly, e.g.:
runAction(object : Action {
override fun run() {
println("Hello")
}
})
But from Kotlin 1.4, you can mark the interface as fun interface, and use the Java-style shortcut, as in your example.
(You may or may not think this is a good thing…)

Final methods in kotlin interfaces

As the title states, I am looking for a way to implement a final (method that cannot be overridden) in a kotlin interface.
So here is my code:
interface NewsItemState {
final fun delete(newsItem: NewsItem) {
validateCanDelete(newsItem)
deleteNewsItem(newsItem)
}
fun validateCanDelete(newsItem: NewsItem)
fun deleteNewsItem(newsItem: NewsItem)
}
And here is my use case:
I want the delete function to be final so that it cannot be
overridden in the implementations of the interface.
I want the
validateCanDelete and deleteNewsItem methods to be overridden in
the implementations of the interface.
Now, I know that this is not possible at the moment and that adding final to a method is not allowed in the interface. I also know that I can achieve this by replacing the interface with an abstract class.
However, I was wondering if there is a way of implementing the same functionality in an interface because my final method is not going to have any "state managing" logic.
While it's not possible to have final methods in interfaces, it's absolute OK to define extension methods for interface types.
interface NewsItemState {
fun validateCanDelete(newsItem: NewsItem)
fun deleteNewsItem(newsItem: NewsItem)
}
fun NewsItemState.delete(newsItem: NewsItem) {
validateCanDelete(newsItem)
deleteNewsItem(newsItem)
}

override and implement fn from class in interface

I want to override toString() in an interface and have objects that implement that interface to default to using that method (eg: not shadowed)
interface SingletonObjectTrait {
fun toString(): String = this.javaClass.simpleName
}
Is there a straightforward way to define such an interface, preferably with minimal configuration at implementation
object MyEvent: SomeEventLogic(), SomeEventType, SingletonObjectTrait
class SomeEventLogic {}
interface SomeEventType {}
That's not possible, I'm afraid.
Method implementations in interfaces work much like default methods in Java: they're used only if the implementing class doesn't have an implementation already.  But every class already inherits toString() from Any, so the default would never be used.
In fact, the compiler has a specific error for this — if you try to implement toString() in an interface, it says:
An interface may not implement a method of 'Any'
I can't see a good way around this.
As Erik says, one option is to change the interface to an abstract class; but of course that's not viable if any implementations already extend another class.
Another option might be to implement a different method in the interface, and in the comments instruct implementing classes to override toString() and call that method.  Not automatic, but less work for implementers, and less repetition.
There isn't a great way to do this other than using maybe an annotation processor to add the missing override at compile time (by adding an annotation to the interface that you detect and you generate the overrides in the implementation class). This would work, but may be biting off more than you want to, and is likely out of scope of an answer here on Stack Overflow (seek "how to write an annotation processor for Java or Kotlin" and "KAPT" for the one engine that supports Kotlin processors).
Back to your code and why it will not work as-is:
An interface cannot have a method with a signature that matches any of the methods in Any class. And if you try to override one of them you will get a compilation error.
An interface may not implement a method of 'Any'
The minimal code to do something like you want is:
interface SingletonObjectTrait {
fun asString(): String = this.javaClass.simpleName
}
open class SomeEventLogic {}
interface SomeEventType {}
object MyEvent: SomeEventLogic(), SomeEventType, SingletonObjectTrait {
override fun toString(): String = asString() // hope they don't forget to call this!
}
There is no guarantee the implementer will call the trait asString() function but at least you can share the functionality with a one-liner in the implementing class.