Kotlin Reflection Issue - java

I have these methods declared in Java libraries:
Engine.java:
public <T extends EntitySystem> T getSystem(Class<T> systemType)
Entity.java:
public <T extends Component> T getComponent(Class<T> componentClass)
Now, I use these methods A LOT, and I would really like to use MyComponent::class (i.e. kotlin reflection) instead of the more verbose javaClass<MyComponent>() everywhere.
My EntitySystem and Component implementations are written in Kotlin.
So I thought I would create extension functions that take KClasses instead, but I am not quite sure how to make them work.
Something along the lines of...
public fun <C : Component> Entity.getComponent(type: KClass<out Component>): C {
return getComponent(type.javaClass)
}
But this does not work for several reasons: The compiler says type inference failed, since javaClass returns Class<KClass<C>>. And I need Class<C>. I also don't know how to make the method properly generic.
Can anyone help me create these methods?

In current Kotlin (1.0), the code would be simpler as:
public inline fun <reified C : Component> Entity.getComponent(): C {
return getComponent(C::class)
}
And can be called:
val comp: SomeComponent = entity.getComponent()
Where type inference will work, reify the generic type parameter (including any nested generic parameters) and call the method, which then uses the type parameter as a class reference.

You should use the extension property java instead of javaClass.
Additionally You can improve your API with reified type parameters and rewrite your code like:
public inline fun <reified C : Component> Entity.getComponent(): C {
return getComponent(C::class.java)
}

Related

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
}
}

Kotlin List vs java.util.List generic type inside Java code

I'm stuck with strange behavior while migrating my project to kotlin.
It's occurred while i tried to generate dagger injectors. The problem in java or dagger, someone can't resolve kotlin List from generic type
Example:
interface CacheEntity<Result> {
fun onResult(result: Result)
fun getUpdatableData(): Observable<Result>
}
class CacheRepository< Result, Entity:CacheEntity<Result> >(
val entity: Entity) {
// do some operations with Entity
fun doSome() {
entity.getUpdatableData()
entity.onResult(...)
}
}
class UserRepository: CacheEntity<User> {
override fun onResult(result: User) {}
override fun getUpdatableData(): Observable<User> {}
}
Now if i'm tring to create cached user repository instance, everything it's ok
Then this code translates to application using dagger injections
val cachedUserRepo = CacheRepository<User, UserRepository>(UserRepository())
But! If i'm trying to result the list of data
class OrdersRepository: CacheEntity<List<Order>> {
// overrides CacheEntity methods
}
val cachedOrdersRepo = CacheRepository<List<Order>, OrdersRepository>(OrdersRepository())
Everything is fine, but not in dagger-generated java code:
MyComponent.java
private CacheRepository<List<Order>, OrdersRepository> cachedOrdersRepository;
error while building
error: type argument OrdersRepository is not within bounds of type-variable Entity
private Provider<CachedRepository<List<Order>, OrdersRepository>> cachedOrdersRepository;
^
where Entity,Result are type-variables:
Entity extends CacheEntity<Result> declared in class CacheRepository
Result extends Object declared in class CacheRepository
Java code contains java.util.List which is incompatible with kotlin.collections.List,
but dagger module class written in kotlin and returns valid kotlin kotlin.collections.List
#Module
object RepoModule {
#JvmStatic
#Provides
fun provideCacheOrdersRepository(): CacheRepository<List<Order>, OrdersRepository> {
return CacheRepository(OrdersRepository())
}
}
So, how to solve this? I have a couple ideas, but i don't like this:
Rewrite dagger module in java, it worked before i converted to kotlin
Forced using java.util.List, but it's a very bad idea
This is related to the bytecode conversion of a Kotlin list and the wildcards added in the signature, making it a java.util.List<? extends T> instead of a java.lang.List<T>.
To fix it without switching to an invariant type (e.g. MutableList) you should use #JvmSuppressWildcards on the the List type:
e.g.
class OrdersRepository: CacheEntity<List<#JvmSuppressWildcards Order>>
I've added just one fragment of your full code, you should check your list usages and use #JvmSuppressWildcards on them.
Ok, i've found quick solution: Using MutableList<T> solves this problem, and it seams compatible with java.util.List<T> by unknown reason.

The intersection of Java generics and Scala is...not going well

I freely admit to being a little out of my depth here. My formal training in type systems is a good few decades behind me. I’ve used generics in Java rather trivially once or twice, but they’re not something about which I can claim to have a deep and thorough understanding. I’m also a relative newcomer to Scala, so I’m not claiming a deep or thorough understanding of its type system either.
I set out to update my XML Calabash v2 implementation, written in Scala (2.12 today) to use Saxon 9.9. Saxon 9.9 introduces generics in a number of places. Fine by me. I can cope, I imagine.
Except, I can’t apparently.
The stumbling block is trying to implement a class that extends the ExtensionFunctionDefinition class. It has an inner class that extends the ExtensionFunctionCall class. That, in turn, has an abstract method, call, defined thusly in Java:
public abstract Sequence<?> call(
XPathContext context,
Sequence[] arguments
)
My first attempt to define this in Scala was:
override def call(
context: XPathContext,
arguments: Array[Sequence]
): Sequence[_]
but that doesn’t compile: “trait Sequence takes type parameters”.
Which is true:
public interface Sequence<T extends Item<?>>
(Item, btw, is:
public interface Item<T extends Item<?>>
extends GroundedValue<T>
which I find slightly confusing for other reasons)
For my second attempt, I tried:
override def call(
context: XPathContext,
arguments: Array[Sequence[_]]
): Sequence[_]
But that, I’m told, doesn’t override anything. Hark, the compiler says:
[error] (Note that Array[net.sf.saxon.om.Sequence]
does not match Array[net.sf.saxon.om.Sequence[_]]:
their type parameters differ)
And here we seem to be at an impasse. I can just implement the damned thing in Java, of course, but is this an actual limitation in Scala or in my understanding?
I was lying before, by the way, about my first attempt. My first attempt was actually:
override def call(
context: XPathContext,
arguments: Array[Sequence[_ <: Item[_ <: Item[_]]]]
): Sequence[_ <: Item[_ <: Item[_]]]
which I crafted by bluntly copying Java into Scala and letting IntelliJ IDEA translate it. I had failed to work out what to do with the recursive nature of the Item declaration.
Try
override def call(context: XPathContext, arguments: Array[Sequence[_ <: Item[_]]]): Sequence[_] = ???
This here definitely compiles (and thereby confirms that Dmytro Mitin's proposal works):
// ExtensionFunctionCall.java
public interface ExtensionFunctionCall {
Sequence<?> call(String ctx, Sequence[] args);
}
// Item.java
public interface Item<T extends Item<?>> {}
// Sequence.java
public interface Sequence<T extends Item<?>> {}
// Impl.scala
class Impl extends ExtensionFunctionCall {
override def call(
ctx: String,
args: Array[Sequence[_ <: Item[_]]]
): Sequence[_] = ???
}
By the way, it's not just Scala's problem. If you forget Scala for a second, and try to implement it in Java, you get essentially the same errors:
class ImplJava implements ExtensionFunctionCall {
public Sequence<?> call(
String ctx,
Sequence<?>[] args
) {
return null;
}
}
gives:
ImplJava.java:1: error: ImplJava is not abstract and does not override abstract method call(String,Sequence[]) in ExtensionFunctionCall
class ImplJava implements ExtensionFunctionCall {
^
ImplJava.java:2: error: name clash: call(String,Sequence<?>[]) in ImplJava and call(String,Sequence[]) in ExtensionFunctionCall have the same erasure, yet neither overrides the other
public Sequence<?> call(
^
2 errors
Now, this is really mystifying, I have no idea how to write down this type in Java. I'm not sure whether it's even expressible in Java without reverting to 1.4-style. The Sequence[] thing is just evil, or, to quote this wonderful article linked by Dmytro Mitin:
Raw Types are bad. Stop using them
I think Sequence with no type parameters in java translates into Sequence[Foo] where Foo is the highest possible super-type (Item in this case).
So, I would expect something like this to work:
override def call(context: XPathContext, arguments: Array[Sequence[Item[_]]]): Sequence[_] = ???

Force More Specific Subclass Type with Generics in Kotlin

I am working on a library that has a few interfaces that are related to each other.
Main example is ViewModel<M: Model, W: Widget>. Then we have an interface for Model and interface for Widget.
The widget interface has a method that takes in a ViewModel object and then uses it to configure itself.
abstract fun configure(viewModel: ViewModel<M: Model, W: Widget>)
I am looking for a way to make that method require the subclass implementation of ViewModel, instead of just the interface.
So a ContainerWidget would need this method: fun configure(viewModel: ContainerViewModel)
The library I am emulating is using Swift and does this with their associated type keyword, which says you can tell us the type later.
Does anyone know an option like that for Kotlin?
Thanks a lot for the help.
abstract class WLViewModel<DataModel : WLDataModel, WidgetType : WLWidget>(val dataModel: DataModel) {
abstract fun configure(view: WidgetType)
}
interface WLWidget {
var viewModel: WLViewModel<WLDataModel, WLWidget>
fun <M, O : WLDataModel, T : WLWidget> configure(viewModel: M) where M : WLViewModel<O, T>
}
interface WLDataModel
fun WLWidget.create(viewModel: WLViewModel<WLDataModel, WLWidget>) {
configure(viewModel)
}
I don't think there's a good way, I'm afraid.
The traditional Java approach fudges it by using recursive type parameters.  You could give your WLWidget interface a type parameter of the actual subclass, like WLWidget<T : WLWidget<T>>, and then make all the knock-on changes.  But that's ugly and doesn't handle all cases.  (See these other questions for more info.)
There have been discussions about adding self types to Kotlin, which would probably be a better match for your case, but they're not here yet.

How to avoid kotlin factory class method by subtype?

i have a question about kotlin:
Imagine you have this:
sealed class Graph : Serializable
data class Graph1() : Graph() {}
data class Graph2() : Graph() {}
And you want to have a factory class that given a subtype of Graph gives you a GraphView.
So, you have something similar to
interface GraphViewFactory{
fun get(data: Graph1):GraphView
fun get(data: Graph2):GraphView
}
And also you have the implementation for that.
Is possible in kotlin avoid this method explosion of interface having one per graphtype using inline and reified? I'm trying to but i'm not being able.
On the one hand, kotlin interface (I think) does not allow inline functions, on the other hand even without the interface i'm not able to auto cast parameter T as reified to one of the specific subtype class inside the factory class.
You wouldn't have to keep creating methods (though you may want to depending on how complex it is to create a GraphView), but the number of cases in your when will grow.
class GraphViewFactory {
fun get(data: Graph): GraphView {
return when {
is Graph1 -> TODO()
is Graph2 -> TODO()
else -> IllegalArgumentException()
}
}
}
Using reified types doesn't buy you anything here.

Categories

Resources