kotlinkotlin-java-interopkotlin1.4

Can I use property syntax for a Java setter without a corresponding getter?


I have a Java class with a setter, but no getter for a property.

class Person {
  private String name;
  public void setName(String name) { this.name = name; }
}

I'd like to use .name= to assign to it from Kotlin

fun example() {
  val p = Person()
  p.name = "example"
}

I get an error unresolved reference: name trying to compile the Kotlin. The error goes away if I add a getter, but can I use the setter as a property without defining a getter in Java? I know I can still call p.setName("example") from kotlin.

The above is the MCVE. The real world code is a Java builder with setters but not getters which I'd like to use from Kotlin, like

val widget = WidgetBuilder().apply {
  width = 1  // instead I need .setWidth(1)
  height = 2
  weight = 3
  name = "my widget"
}.build()

Solution

  • No, the Kotlin compiler only recognizes it as a property if there is a getter with equal or greater visibility as the setter. This is because there is no such thing in Kotlin as a property with no getter. (See last sentence in this section.)

    Note that, if the Java class only has a setter, it isn't visible as a property in Kotlin because Kotlin doesn't support set-only properties.

    You can manually write extension properties for this class that make the property access syntax available to you, although some would probably consider it an anti-pattern to have a non-functional getter for a property. But you can control the visibility of your extension properties, so it may be fine.

    var WidgetBuilder.width: Int
        @Deprecated("Getter is unsupported.", level = DeprecationLevel.ERROR)
        get() = error("unsupported")
        set(value) { setWidth(value) }
    

    And alternative for a builder would be to make a single extension function with all the parameters you might set on it, along with default values. Then you can use named arguments to get syntax somewhat similar to your example with apply.

    FWIW, I just use the chained method calls as intended when working with Java builders.