Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin: Access a public field from a Java class that also overrides a public getter of the same name

Tags:

java

kotlin

I have a Java class (which I cannot edit, because it's auto-generated by Thrift) defined like this:

public class TheirException extends Throwable {
  public String message;

  public TheirException(String message) {
    this.message = message;
  }

  public String getMessage() {
    return this.message;
  }
}

However, if I try to get message from Kotlin, getMessage() is not available and produces an Unresolved reference error. Trying to use the messagefield produces the following error:

Error:(470, 30) Kotlin: Overload resolution ambiguity:
public final var message: String! defined in com.example.TheirException
public open val message: String? defined in com.example.TheirException

However, if I instead do:

(exception as Throwable).message

it resolves fine.

Why is casting to Throwable necessary here, why is getMessage() not available, and what is causing the ambiguity?

like image 378
Adam Millerchip Avatar asked Oct 28 '22 17:10

Adam Millerchip


1 Answers

The ambiguity is caused by the fact that message is public. Kotlin translates every getter to a property even if there are no backing fields. If you add another function to this class:

public String getSecondMessage() {
  return "second message"; // Note that this getter does not rely on a field
}

You can access it like this in Kotlin:

TheirException("message").secondMessage

If message is public and there is a getMessage() function Kotlin creates 2 getters and on the call site you newer know which to use. In your example the 2 getters would have the same behavior but that is not always the case.

When you cast your class to a Throwable you explicitly tell the compiler that this class has the signature of a Throwable, which means you define that there should be only one message getter, this resolves the ambiguity. Note here that Kotlin has its own definition of a Throwable (this will be important later).

Now you might ask why there is no getMessage() function. This is because you are casting to Throwable and not java.lang.Throwable. The Kotlin definition of Throwable has no getMessage()

like image 68
functionaldude Avatar answered Nov 15 '22 06:11

functionaldude