Kotlin Conflicting overloads: public open fun statements() - java

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

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.

Java GenericClass< ? extends Interface> as a Parameter

public interface A {}
public interface B {}
public class Test implements A{}
public class Test2 {}
I made a method which checks if a class implements an interface. I want my method to only accept generic interfaces and not all class objects.
method
public static boolean containsInterface(Class clazz, Class intf)
{
try
{
Validate.isTrue(intf.isInterface());
if(clazz.isInterface())
return JavaUtil.isClassExtending(intf, clazz);
for(Class c : ClassUtils.getAllInterfaces(clazz))
{
if(JavaUtil.isClassExtending(intf, c))
return true;
}
}
catch(Throwable t)
{
t.printStackTrace();
}
return false;
}
Since Test.class & Test2.class are not interfaces on the 2d parameter I want it to have a compile error since the 2d parameter must be an interface class
containsInterface(Test.class, Test.class);
containsInterface(Test.class, Test2.class);
acceptable use of my method
containsInterface(Test2.class, A.class);
containsInterface(Test.class, B.class);
what I tried
public static boolean containsInterface(Class clazz, Class<? extends Interface> intf)
I currently check if the class in the parameter is an interface then throw an exception. I would rather force people to not be able to call the method to begin with if it's not an interface
I am aware of Annotations and Enum objects are available to use as a class signature to make sure people are using the parameters right but, I can't seem to find the one for the interface itself.
I was told generics do not support interfaces or abstract classes type is this true even in jre 9-13+
You cannot force argument to be ANY interface implementation using type control system. The same would apply if you would like to eg force only Class<?> with abstract modifier. I am not sure if that is really needed as doing simple type isInterface assert is
Straigthforward
Clean
Robust
Easy to understand
Error prone
Testable
JDK Engineers does not care about that either. As an perfect example of such mechanism would be used (but there is none) is JDK Dynamic Proxy creation. You can create only create proxy of an interface (or set of) but not of class.
I don't think that it is just worth of the effort to write own preporocessors. Moreover it would be not universal - as you assume that runtime type must be know at compile time - what about dynamically loaded classes etc?
Intefaces in java has no super class that you can use in generic mode.
If you try get the super class of an interface with reflection returns null.
public static void main (String [] args) {
System.out.println(A.class.getSuperclass());
}
interface A {}
Output:
null

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.

Name Clash, override fail, on a class implementing two interfaces with same erasure

I am creating a class that overrides a method signature whose erasure is identical between 2 implemented interfaces, but with a minor difference in regards of the generic type (one is a method-inferred type, the other an inferred-class type). I am looking for a neat solution. I CAN ONLY edit the inherited class, not the original legacy interfaces.
To show the case, I made up an abstract sample, to understand the problem:
I got a Developer legacy parent class:
public class Developer<C>{
Rate<C> getRate(Taxes<C> tax){ /*...*/ }
}
I also got a Rentable legacy interface, with an almost identical signature
public interface Rentable {
<C> Rate<C> getRate(Taxes<C> taxes);
}
As a developer is not rentable, in my model, I create an special
developer which is both a Developer, and Rentable material.
public class OutsourcableDeveloper<C>
extends Developer<C>
implements Rentable{
#Override
public Rate<C> getRate(Taxes<C> taxes){ /*...*/}
}
and then I got the infamous
Name clash: The method getRate(Developer.Taxes) of type
OutsourcableDeveloper has the same erasure as
getRate(Developer.Taxes) of type Rentable but does not override it
How can I get rid of it, so OutsourcableDeveloper.getRate() hides
both Developer and Rentable. getRate()?
It seems a bit illogical to fail a common override but then disallowing extending both signatures as the erasures are equal.
Does it really matters so much the fact that one of the supertypes infers type from de method and the other from the class specially when I'm not going to call any super in my implementation? Is there perhaps a trick to overcome the issue given this simplification?
EDIT: I opened a more abstract, less solution-oriented to my actual problem, question to discuss the inheritance design problem which I believe is the correlated essence of the actual issue I am having: Why can't I extend an interface "generic method" and narrow its type to my inherited interface "class generic"?
EDIT2: Previous question lead me to the answer posted here
Well they are actually not equal. Because any Rentable-Instance allows any typeparameter T to be given, while the OutsourcableDeveloper restricts it.
Of course you can assume that in your case it is easy to use the
<C> Rate<C> getRate(Taxes<C> taxes);
Version of the interface. But expect how confused a developer could be, if he wants to subclass OutsourceableDeveloper. From the definition of Developer he can assume that the Method getRate is fixed to C but actually it can suddenly take any value. -> allowing this would lead to confusion.
What i can offer you is the following code-example, which may be suitable for your case. Although it definitely will be inconvenient to use it. But as you forward all methods to the OursourcableDeveloperRentable it is possible. The comments should explain how it works.
//This class itself can be added to any Developer-lists
public class OutsourcableDeveloper<C> extends Developer<C> {
public final OutSourcableDeveloperRentable RENTABLE_INSTANCE = new OutSourcableDeveloperRentable();
#Override
public Rate<C> getRate(final Taxes<C> taxes) {
// Simply forward to the more general getRate instance.
return this.RENTABLE_INSTANCE.getRate(taxes);
}
public void exampleBehaviourA() {
//Example for how you can make both objects behave equally.
}
// This class can be added to the lists requiring a Rentable
// And the original value can be retrieved by both classes.
public class OutSourcableDeveloperRentable implements Rentable {
public final OutsourcableDeveloper<C> PARENT_INSTANCE = OutsourcableDeveloper.this;
//This method is the one to implement because it is more general than
//the version of OutsourcableDeveloper.
#Override
public <T> Rate<T> getRate(final Taxes<T> taxes) {
// Do your work.
return null;
}
public void exampleBehaviourA() {
//Just an example - Maybe for you it makes for sence to
//forward the method of Oursoursable-Developer to here.
//Then all Behaviour would be found in this class.
OutsourcableDeveloper.this.exampleBehaviourA();
}
}
}
Ok, I found a way to solve it. It's clumpsy, but it's the easier one if the architecture is not very complex, inspired by my Why can't I extend an interface "generic method" and narrow its type to my inherited interface "class generic"? own answer:
public class OutsourcableDeveloper<C>
extends Developer<C>
implements Rentable{
/* This might not be needed if we don't need to extract C from taxes parameter */
final Class<C> currencyClass;
public OutsourcableDeveloper(Class<C> currencyClass){ this.currencyClass = currencyClass;}
#Override
public Rate<C> getRate(#SuppressWarnings("rawtypes") Taxes taxes){
try{
C taxesCurrency = (C) currencyClass.cast(taxes.getCurrency()); //IF actually needed getting the typed instance
return new Rate<C>(taxesCurrency); //Or whatever processing
} catch (ClassCastException e){
throw new UnsupportedOperationException("OutsourcableDeveloper does not accept taxes in a currency that its not hims");
}
}
}
It is also possible to play with "extends Developer" without the generic type, so it is implictly raw. but we loose typing for the non-conflicting methods as well

Kotlin Reflection Issue

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

Categories

Resources