Kotlin delegation to expression instead of fixed reference - java

Suppose I have a very intricate specification defined as an interface:
interface Spec {
fun sayHello()
}
And a standard implementation:
class Impl(private val msg: String) : Spec {
override fun sayHello() {
println(msg)
}
}
Now suppose that I want to create a class that implements this specification and delegates to an implementation, but the exact delegate object is mutable throughout the object's lifetime. Here's an example:
class Derived(var target: Spec) : Spec by target
The problem with the above example is that the constructor argument target is set as the delegate object when the constructor is called. The delegate is then accessed by the class directly instead of performing a property access. (This has been confirmed by looking through the bytecode produced by Kotlin.)
So, even if the property target is modified after the class is constructed, the delegate does not change.
Can anybody provide a method for performing this delegation in Kotlin without having to write out every single method?
An ideal solution would also allow for delegation to something as general as a lambda or other expression that would be evaluated and used as the delegate whenever the delegate is needed throughout the lifetime of the object.

Right now there is no way to do that. See Kotlin issue KT-5870
Currenlty Kotlin evaluates expression for delegate in class initializer

You can add a level of indirection:
class Holder(var impl: Spec) : Spec {
override fun sayHello() = impl.sayHello()
}
class Derived(target: Spec,
private val holder: Holder = Holder(target)) : Spec by holder {
fun changeTarget(newTarget: Spec) {
holder.impl = newTarget
}
}
Unfortunately holder must be a constructor parameter in order to be used with the delegation construct (as for Kotlin v1.0), so it complicates the primary constructor.

Related

How to override method with inherited class in Kotlin?

I am exploring and actively using generics in production with Kotlin.
Kotlin + generics is a big puzzle for me, so maybe you can explain and help me understand how it works here, compared to Java.
I have class AbstracApiClient (not really abstract)
class AbstracApiClient {
open protected fun makeRequest(requestBuilder: AbstractRequestBuilder) {
// ...
}
}
AbstractRequestBuilder (not really abstract):
open class AbstractRequestBuilder {
...
}
ConcreteApiClient that inherits AbstractApiClient that should override makeRequest with ConcreteRequestBuilder inherited from AbstractRequestBuilder:
class ConcreteApiClient: AbstractApiClient() {
protected override fun makeRequest(requestBuilder: ConcreteRequestBuilder) {
// ...
}
}
class ConcreteRequestBuilder: AbstractRequestBuilder()
As I would have more concrete API clients. I would like to make an abstraction that I can pass inherited concrete requests builders and override `make requests method.
I tried using it as it is but wouldn't work
I tried this notation protected open fun <R: ApiRequestBuilder> make request(request builder: R) but it won't match overriding function which I want it to be: protected override fun make request(request builder: ConcreteRequestBuilder)
What other options do I have? Am I missing something here?
Note: I cannot use interface or abstract classes in this scenario, so ideally I would like to find a way with inheritance and functions overriding.
You can't override a method with more specific argument types, because it breaks Liskov's substitution principle:
val client: AbstractApiClient = ConcreteApiClient()
client.makeRequest(AbstractRequestBuilder())
As you can see above, the ConreteApiClient implementation has to be able to handle all possible inputs of the parent class, because it could be accessed through the parent class's API.
To do what you want, you need to restrict the parent class itself via generics:
open class AbstractApiClient<R : AbstractRequestBuilder> {
open protected fun makeRequest(requestBuilder: R) {
// ...
}
}
class ConcreteApiClient: AbstractApiClient<ConcreteRequestBuilder>() {
protected override fun makeRequest(requestBuilder: ConcreteRequestBuilder) {
// ...
}
}
This way, any instance of AbstractApiClient<R> has to show which type of request builder it accepts (in the type argument). It prevents the above issue because now the parent type also carries information:
// doesn't compile
val client: AbstractApiClient<AbstractRequestBuilder> = ConcreteApiClient()
// this compiles
val client: AbstractApiClient<ConcreteRequestBuilder> = ConcreteApiClient()
I tried this notation protected open fun <R: ApiRequestBuilder> make request(request builder: R)
Now regarding this attempt, it doesn't work because if you make the method generic (not the class) it means every implementation of the method has to handle all kinds of R (NOT one R per implementation). Putting the generic on the class allows to specify the generic argument once per instance of the class.

Kotlin Conflicting overloads: public open fun statements()

I have an interface Persistable which looks like this, the <T extends Statement<T>> List<Statement<T>> is to allow it to support both BoundedStatements and SimpleStatements in data stax 4.x driver.
public interface Persistable {
<T extends Statement<T>> List<Statement<T>> statements();
}
This java interface is inherited by Kotlin class A such that
data class UpdateRule(
private val something: S) : Persistable {
override fun statements(): List<Statement<BoundStatement> {
return PutKeyValue(Function(orgId, serviceId), JsonUtil.toJson(rule)).statements() //this returns BoundStatement
}
}
However, this gives the error Conflicting overloads.This code seems to work in Java(although with a warning), but in Kotlin it does not allow at all, how can I resolve this while also making sure parent interface remains generic to both Bound and Simple Statement?
You seem to misunderstand what the generics in Persistable mean. As it is written right now, you are supposed to implement the statements method so that it can handle any kind of T that extends Statement<T>. The generics there doesn't mean "implement this by choosing a kind of statement that you like".
It only produces a warning in Java because Java's generics is broken. Because of type erasure, List<Statement<BoundStatement> and List<Statement<T>> both erase to the same type - List, so the method in UpdateRule does implement the method in the interface if you consider the erasures. OTOH, type erasure isn't a thing in Kotlin (at least not in Kotlin/Core).
To fix this, you can move the generic type parameter to the interface:
public interface Persistable<T extends Statement<T>> {
List<Statement<T>> statements();
}
data class UpdateRule(private val something: S) :
Persistable<BoundStatement> {
override fun statements(): List<BoundStatement> =
PutKeyValue(Function(orgId, serviceId), JsonUtil.toJson(rule)).statements()
}
Notice how when we are implementing the interface, we can now specify the specific T that we are implementing for.
In Java just like in Kotin, the value of the type parameter of a generic method is determined by the caller of the method, and can be different at every call of the method, even on the same instance.
In your specific case, with the Java interface declared like this, statements() is supposed to be implemented in such a way that the caller can choose which type of statement will be returned by a given call to this method. This is not the case in your implementation, and that's why Kotlin doesn't allow it. As pointed out by #Sweeper, Java is broken in this respect and might let you get away with a warning.
This is different when using a generic class or interface. If you define the type parameter at the class/interface level, then the value of that type parameter is determined at construction time of the class, or can be fixed by subclasses. For a given instance, all calls to the method will return a well known type, which is (I believe) what you want here.
You can do this in Java:
public interface Persistable<T extends Statement<T>> {
List<Statement<T>> statements();
}
And then in Kotlin:
data class UpdateRule(
private val something: S
) : Persistable<BoundStatement> {
override fun statements(): List<BoundStatement> {
return PutKeyValue(Function(orgId, serviceId), JsonUtil.toJson(rule)).statements() //this returns BoundStatement
}
}

How can I use Kotlin default methods with Spring Data repository interfaces?

Consider the following repository interface declaration:
interface KotlinUserRepository : Repository<User, String> {
fun findById(username: String): User
fun search(username: String) = findById(username)
}
I'm declaring a default interface method search(…) that defaults to invoking findById(…).
Starting my application fails with:
org.springframework.data.mapping.PropertyReferenceException: No property Search found for type User!
How can I use Kotlin default methods with Spring Data repository interfaces and prevent PropertyReferenceException?
TL;DR
Kotlin 1.1/1.2 compiles default methods to abstract interface methods in the first place. It's not possible to use Kotlin's default methods in Spring Data repository interfaces.
Explanation
Kotlin allows default interface methods with a Java runtime version 1.6. JVM-level default interface methods were introduced with Java 1.8. This causes Kotlin to use a different approach to compile default interface methods than Java does.
The code from KotlinUserRepository compiles to:
interface KotlinUserRepository extends Repository {
User findById(String username);
User search(String username);
#Metadata(…)
public static final class DefaultImpls {
public static User search(KotlinUserRepository $this, String username) {
Intrinsics.checkParameterIsNotNull(username, "username");
return $this.findById(username);
}
}
}
The method search(…) compiles to an abstract interface method. The implementation bit compiles to a class DefaultImpls which reflects the default method signature. A class wanting to implement KotlinUserRepository is required to implement search(…). Using the interface in a pure Kotlin environment will let the Kotlin compiler create the implementation bits.
Spring Data repositories work with proxies underneath. Every method on a repository must be either:
Implemented by the store-specific repository.
Implemented by a custom implementation.
A Java 8 default method.
Be annotated with a query annotation.
Fit the method naming scheme to allow query derivation.
In this case, search(…) is not implemented by any custom code according to how you'd implement a Java interface. Spring Data attempts to derive a query and considers search(…) as property of the User domain class. Lookup fails and throws PropertyReferenceException.
This is a known limitation.
References
DATACMNS-1223 - Kotlin interface default methods are considered query methods.
KT-4779 - Generate default methods for implementations in interfaces.
As Ben pointed out, you can now (Kotlin 1.2.40+) use #JvmDefault.
interface BatchRepository : PagingAndSortingRepository<Batch, Long> {
fun getAllByOrderByPriorityAscNameAsc(): List<Batch>
#JvmDefault
fun getForAdmin() = getAllByOrderByPriorityAscNameAsc()
}
You will need to enable the option in you build.gradle using something like this:
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
kotlinOptions {
freeCompilerArgs = ['-Xenable-jvm-default']
}
}
I just tested it on Kotlin 1.2.41 and it works.
FWIW Kotlin extension methods worked nicely for me here, 1 .kt file:
interface FooRepository : JpaRepository<FooDb, UUID>
object FooRepositoryExtensions {
fun FooRepository.doFoo(something: String): FooDb {
// do whatever you want here, the 'FooRepository' instance is available via `this`
}
The recently released Kotlin 1.2.40 now supports an experimental feature enabling compilation of Kotlin default methods to Java 8 default methods via the #JvmDefault annotation and setting of the feature flag: Xenable-jvm-default
https://blog.jetbrains.com/kotlin/2018/04/kotlin-1-2-40-is-out/#more-5922
I haven't tried it out yet, but your example theoretically should work like so:
interface KotlinUserRepository : Repository<User, String> {
fun findById(username: String): User
#JvmDefault
fun search(username: String) = findById(username)
}

Can a Kotlin interface cache a value?

I really like using default implementations for interfaces in Kotlin, especially for common patterns like Observable. Here's my interface,
interface Observable<T>{
// How do I cache this?
val observers: MutableList<Observer<T>>
get() = LinkedList<>()
fun addObserver(o:Observer<T>){
observers.add(o)
}
fun removeObserver(o:Observer<T>){
observers.remove(o)
}
fun notifyObservers(u:T){
for (o in observers){
o.update(u)
}
}
}
The interface refers to a list of observers, but the get() call is returning a new LinkedList() each time. How can I cache the value of observers so that it's only created once? I've tried using kotlin-lazy, but either can't get the syntax right, or it's not meant for interfaces. My IDE complains "Delegated properties are not allowed in interfaces."
UPDATE
Based on Yoav's answer, I've change my interface to
interface Observable<T>{
val observers: MutableList<Observer<T>>
}
And then in the implementing class,
class MyObservable : Observable<String>
private val _observers = LinkedList<Observer<String>>()
override val observers: MutableList<Observer<String>>
get() = _observers
Any tips to make this more succinct?
According to Kotlin docs:
Interfaces in Kotlin are very similar to Java 8. They can contain
declarations of abstract methods, as well as method implementations.
What makes them different from abstract classes is that interfaces
cannot store state.
Interface can't hold any state as they are fully abstract. Perhaps you should use an abstract class in order to cache the values?
See this question for more information about the reason for interfaces being stateless.
An interface is a contract specifying what its implementer promises to
be able to do. It does not need to specify state because state is an
implementation detail and only serves to constrain implementers in how
this contract is fulfilled. If you want to specify state you might
want to rethink you use of interfaces and look at abstract base
classes instead.
While you cannot create stateful variables on an interface directly, you can achieve the same result by defining a companion object containing a cache and do a dynamic lookup on this. Using your example:
interface Observable<T>{
// How do I cache this?
val observers: MutableList<Observer<T>>
get() = cache.computeIfAbsent(this) { mutableListOf<Observer<T>>() } as MutableList<Observer<T>>
fun addObserver(o:Observer<T>){
observers.add(o)
}
fun removeObserver(o:Observer<T>){
observers.remove(o)
}
fun notifyObservers(u:T){
for (o in observers){
o.update(u)
}
}
companion object {
val cache = WeakHashMap<Observable<*>, MutableList<*>>()
}
}
If you want a more efficient cache, you can use a library like Caffeine.
After thinking about this some more, I discovered a nice pattern. First I tried the direct approach:
interface A {
val prop = compute() // Nope: Property initializers are not allowed in interfaces
/*...*/
}
As you mentioned, it can be done using a custom accessor but must be recomputed each time:
interface A {
val prop get() = compute() // OK, but recomputed each time someProperty is read
/*...*/
}
Then I thought, perhaps we can use a delegated property instead? But this is not allowed either:
interface A {
val prop by { compute() } // Not allowed: Delegated properties are not allowed in interfaces
/*...*/
}
Finally, I found you can achieve the same result by creating a property extension with a delegate:
interface A { /*...*/ }
val A.prop by lazy { compute() }
From a usage standpoint, you just import the extension and can access a.prop as usual.

How to create new instance of Scala class with context bound via Java reflection using only zero argument constructor?

I am writing client code in Scala that needs to interface with a framework in Java. The framework is responsible for creating object instances of classes specified via an API, which it does using reflection. For example:
public class ReflectionUtil {
public static <T> T newInstance(Class<T> aClass) {
T result;
try {
Constructor<T> meth = aClass.getDeclaredConstructor(new Class[]{});
meth.setAccessible(true);
result = meth.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
return result;
}
}
The classes of the object instances I want to create are implemented in Scala and are paramerterised on a type that has a context bound on it. For example:
class OrderedValue[A](var value: A)(implicit ord: Ordering[A]) {
def get: A = value
def set(x: A) = { value = x }
def cmp(that: OrderedValue[A]): Int = ord.compare(this.value, that.value)
}
I run into a problem when I pass this class to the Java framework to construct new instances as the framework makes the assumption that the class will have a zero-argument constructor available. For example, the following code will result in a NoSuchMethodException from within newInstance:
def main(args: Array[String]) {
val a: OrderedValue[Int] = ReflectionUtil.newInstance(classOf[OrderedValue[Int]])
val b: OrderedValue[Int] = ReflectionUtil.newInstance(classOf[OrderedValue[Int]])
a.set(3)
b.set(5)
println(a.cmp(b))
}
An attempt at resolving this issue is to add a zero-argument constructor to OrderedValue however there is no reasonable value for the implicit parameter ord. Setting it to null will result in a NullPointerException within cmp:
def this() = this(null.asInstanceOf[A])(null.asInstanceOf[Ordering[A]])
Another approach is to subclass a particular concrete value of OrderedValue. For example:
class OrderedIntValue(val v: Int) extends OrderedValue[Int](v) {
def this() = this(null.asInstanceOf[Int])
}
val a: OrderedValue[Int] = ReflectionUtil.newInstance(classOf[OrderedValue[Int]])
This will work but is not ideal as it is not always convenient or possible to know the concrete type of OrderedValue. For example, newInstance may be called within a scope that is also parameterised on a type (i.e. we don't know that it's specifically an Int).
So my question is: given that context bounds (i.e. type classes) are a very useful, and now commonly used, feature within Scala, and given I can not change the internals of the Java framework that I am interfacing with, has anyone encountered or developed an approach that can make this all work?
Implicit arguments are filled in by the Scala compiler at the compile time. If you want to instantiate classes using reflection you will have to specify those arguments manually. There is just no way around it. So you can either have context bounds or no-argument constructors.
I found that the easiest way of calling Scala code from Java is to write an intermediate Scala layer with the Scala equivalent of POJOs. No implicits, no closures in signatures, no Companion object, no complicated type inference, etc. (of course, you can use these internally). I also try to replace most scala Collections types in signatures with java.util Collections.
Yes, it is ugly, tedious and not very flexible, but at least it removes a lot of syntax nightmare from the Java side.

Categories

Resources