projectlombok / lombok

Very spicy additions to the Java programming language.
https://projectlombok.org/
Other
12.86k stars 2.38k forks source link

[FEATURE] Kotlin style properties in Java? #3612

Open sndcrde opened 8 months ago

sndcrde commented 8 months ago

Hi,

Am curious if it's feasible to develop a Lombok annotation to provide Kotlin-style properties in Java. That is, the dev would normally use the property's name to access it instead of getter/setter methods. But if the dev defines a custom getter/setter method then it will be called while the property is still accessed by its name.

See https://kotlinlang.org/docs/properties.html#getters-and-setters for more info how it's done in Kotlin.

Would be nice to have Kotlin-like properties in Java as they make code clearer and easier to read, removing mundane function calls when really there's no need for them.

Regards,

colonelpopcorn commented 1 month ago

This could be really nice. An example would probably look like this:

With Lombok

public class PropertyAccessExample {
    private String someProperty;
    public PropertyAccessExample() {}

    @Getter
    public String getSomeProperty() {
        return this.someProperty;
    }

    @Setter
    public void setSomeProperty(String someProperty) {
        this.someProperty = someProperty;
    }
}

public class PropertyAccessExampleTest {
    public static void main(String[] args) {
        PropertyAccessExample example = new PropertyAccessExample();
        example.someProperty = "Hello world!";
        System.out.println(example.someProperty);
    }
}

Vanilla Java

public class PropertyAccessExample {
    private String someProperty;
    public PropertyAccessExample() {}

    public String getSomeProperty() {
        return this.someProperty;
    }
    public void setSomeProperty(String someProperty) {
        this.someProperty = someProperty;
    }
}

public class PropertyAccessExampleTest {
    public static void main(String[] args) {
        PropertyAccessExample example = new PropertyAccessExample();
        example.setSomeProperty("Hello world!");
        System.out.println(example.getSomeProperty());
    }
}
sndcrde commented 1 month ago

I see it this way:

  1. The dev marks some property with an annotation to indicate that the property should be treated Kotlin-like, for example, @KotlinStyleProperty
  2. The dev uses property's name instead of getter/setter methods to get/set its value
  3. Lombok provides the default getter/setter methonds where the getter/setter logic is mundane (that is, only gets or sets the property's value)
  4. The dev provides CUSTOM getter/setter methods where the getter/setter logic is different from the default one, for example, see the setSomePropertyTwo() method below
  5. Lombok translates the use of property's name into respective getter/setter calls

With reference to the above, "With Lombok" example could look like the following (more or less):


public class PropertyAccessExample {
    // somePropertyOne doesn't need any getter and setter methods defined
    // as they simply get and set somePropertyTwo's value, so the default
    // getter and setter will be provided by lombok automatically
    //

    @KotlinStyleProperty
    // another possability:  @KotlinStyleProperty(public getter, public setter)
    private String somePropertyOne;

    @KotlinStyleProperty
    private String somePropertyTwo;
    // Let's assume that for this example somePropertyTwo doesn't need a CUSTOM getter,
    // since its logic is to simply return somePropertyTwo's value, hence no getter needs to
    // be defined, the default getter will be provided by lombok
    //
    // @Getter
    // public String getSomePropertyTwo() {
    //     return this.someProperty;
    // }

    // However the logic for setting somePropertyTwo's value  is complex (and is different from the default setter),
    // hence a custom setter method needs to be defined.
    //
    @Setter
    public void setSomePropertyTwo(String somePropertyTwoValue) {
        System.out.println("setSomePropertyTwo() method is called!");

        tempValue = {
            ... // do some complex processing here
        }
        this.somePropertyTwo = tempValue;
    }

    public PropertyAccessExample() {}

}

public class PropertyAccessExampleTest {
    public static void main(String[] args) {
        PropertyAccessExample example = new PropertyAccessExample();

        example.somePropertyOne = "Hello world from somePropertyOne!";
        System.out.println(example.somePropertyOne);

        // setSomePropertyTwo() method will be called here
        example.somePropertyTwo = "Hello again from somePropertyTwo!";
        System.out.println(example.somePropertyTwo);

    }
}