2
votes

Here I found many similar questions, but not one solution did not help me because of the specifics of my problem. I have the following class hierarchy:

com.package.ParentInterface.java

public interface ParentInterface {
    void setMessages(Collection<String> var1);
}

com.package.ParentClass.java

public class ParentClass {
    protected Collection messages;

    public void setMessages(Collection messages)
    {
        this.messages = messages;
    }
}

com.package.ChildClass.java

public class ChildClass extends ParentClass implements ParentInterface {
}

com.package.KotlinClass.kt

class KotlinClass: ChildClass()

In the last Kotlin class I have following error: `Class 'KotlinClass' is not abstract and does not implement base class member public abstract fun setMessages(var1: (Mutable)Collection!): Unit defined in com.package.ChildClass.

When I accept the proposal of generating a method implementation using the IDE, I have:

override fun setMessages(var1: MutableCollection<String>?) { }

and I get the following error on the generated method:

Accidental override: The following declarations have the same JVM signature (setMessages(Ljava/util/Collection;)V):

  • public open fun setMessages(messages: (MutableCollection..Collection<*>?)): Unit defined in com.package.KotlinClass
  • public open fun setMessages(var1: MutableCollection?): Unit defined in com.package.KotlinClass

And I can only change KotlinClass, because other classes are classes of a third-party library in Java. Help someone, please, I have already spent a lot of time on this problem.

2
Your ParentClass uses a raw Collection (i.e. one without a type argument). That's a language features meant exclusively for backwards compatibility with pre-generics code and you should absolutely avoid using it. I wouldn't be surprised if Kotlin reacted very badly to such code, as it basically breaks the type system.Joachim Sauer
If you have third-party library that uses a raw generic, you should seriously(!) consider upgrading or replacing it. --- What is a raw type and why shouldn't we use it?Andreas
Is that the real code you're using or just code for demonstration? Because ChildClass extends ParentClass implements ParentInterface seems like an error. ParentClass implements ParentInterface seems more valid to me. And removing the implements ParentInterface from ChildClass would solve the problem.Lino
@LinosaysReinstateMonica, it's code for demonstration. However, it fully describes the real hierarchy of a third-party library. I just simplified it by putting out the main problem.Stanislau Listratsenka
And to answer the question: I don't think it's possible to implement/extend two methods with different signatures which are the same after type erasure. Not on the JVM, anyway (as the signatures are the same by the time the JVM sees them). Kotlin could probably allow it on other platforms, but only by sacrificing some interoperability, so I don't expect they will.gidds

2 Answers

2
votes

Alright, the answer is actually not as strict as it may seem - yes and no. You can overcome this limitation with pure kotlin but you will loose some functionality in the process/may introduce some unwanted but obvious errors in the process, so you should really investigate where this method is used before proceeding, because you need to basically "cut off" this method entirely in order to fix compilation errors.

So in your specific case I know you develop Atlassian plugin for Jira on Kotlin. That is kind of essential, because we know that this method can be avoided in your case.

The problem class is: com.atlassian.jira.web.action.JiraWebActionSupport

it implements interface: com.atlassian.jira.util.ErrorCollection

and the culprit method is: void setErrorMessages(Collection<String> var1);

ParentClass is webwork.action.ActionSupport

and it contains protected Collection errorMessages;

and that's how you can cut off this dead limb:

open class SpecificAction : JiraWebActionSupport() {
    override fun setErrorMessages(p0: MutableCollection<String>?) = TODO()
    ...
}

In your case Java override is of course more preferable, as you don't loose anything and don't introduce potential errors, but if you need only kotlin and sure that you don't/won't use this method - this little dirty hack will help.

0
votes

I had a similar issue to this one however it was in how the class inherentence was being worked out. it involved a function getInfo being defined with both nullable and nonullable arguments

class ChangeFormNPC(input: ByteBuffer, flags: Flags.Int, context: ESSContext) : ess.GeneralElement(), ChangeFormData {
override fun getInfo(analysis: resaver.Analysis?, save: ess.ESS?): String { return ""}
}

what i mean by this is that in the above class definition ess.GeneralElement() was where the problem was occurring

in that other class

open class GeneralElement protected constructor() : Element {
open fun getInfo(analysis: Analysis, save: ESS): String { return "" }
}

error message observed

<somepath>\ChangeFormNPC.kt: (42, 5): Accidental override: The following declarations have the same JVM signature (getInfo(Lresaver/Analysis;Less/ESS;)Ljava/lang/String;):
    fun getInfo(analysis: Analysis, save: ESS): String defined in ess.ChangeFormNPC
    fun getInfo(analysis: Analysis?, save: ESS?): String defined in ess.ChangeFormNPC

the confusing part (at least to me at the time) was that it showed the same function with different null-able properties.

the fix was to add the nullable specifier to the arguments of getinfo in the GeneralElement class. This made the getinfo functions equal and removed the error.