Lombok: Support JavaFX properties

Created on 30 Oct 2016  路  29Comments  路  Source: projectlombok/lombok

JavaFX expands upon the JavaBean concept and uses properties for bindings (see http://docs.oracle.com/javase/8/javafx/properties-binding-tutorial/binding.htm).

When defining a property, you are instructed to write the following code:

// Define a variable to store the property
private DoubleProperty amountDue = new SimpleDoubleProperty();

// Define a getter for the property's value
public final double getAmountDue(){return amountDue.get();}

// Define a setter for the property's value
public final void setAmountDue(double value){amountDue.set(value);}

// Define a getter for the property itself
public DoubleProperty amountDueProperty() {return amountDue;}

The current @Getter and @Setter are not compatible, since

@Getter @Setter private DoubleProperty amountDue = new SimpleDoubleProperty();

results in getting and setting a DoubleProperty and not the wrapped double. The getter for the property itself should also be renamed from getXXX to XXXProperty.

Can Lombok add support for this? Ideally you would have an annotation for those 3 methods for a single field, with an option to disable the wrapped value get and set and leave only the XXXProperty since getting and setting the amount is for backwards compatibility.

Example:

@Property DoubleProperty amountDue = new SimpleDoubleProperty();

would generate the first code block posted.

@Property(valueMethods=false) DoubleProperty amountDue = new SimpleDoubleProperty();

would generate only the getter for the property itself.

Addendum:

The getter and setter methods are final by convention. An option finalMethods=false could be useful if someone wants to avoid the convention.

Most helpful comment

I created a simple implementation which currently works in eclipse.
https://github.com/rgra/lombok/tree/Issue1222

@FxBean
public class Test {
private IntegerProperty idProperty = new SimpleIntegerProperty(this, "id");
private LongProperty LongProperty = new SimpleLongProperty(this, "Long");
private FloatProperty FloatProperty = new SimpleFloatProperty(this, "Float");
private DoubleProperty DoubleProperty = new SimpleDoubleProperty(this, "Double");
private ObjectProperty objectProperty = new SimpleObjectProperty<>(this, "objectProperty");
private ListProperty listProperty = new SimpleListProperty<>(this, "list");
private MapProperty mapProperty = new SimpleMapProperty<>(this, "map");
private SetProperty setProperty = new SimpleSetProperty<>(this, "set");
}

This will generate getters for the properties itself and Getters and Setters for the values itself.
List/Map/Set will have the matching Observable Types.
For ObjectProperties the Generic Type is used for the value getters/setters.

All 29 comments

Duplicate of #521.

Since this got some update, can anyone tell me how requests work here? Does it need some amount of upvotes to be looked at or is it random?

Moreover, I would suggest that the @Property annotation generates

  • a getter for a property only if the property implements the ReadOnlyProperty interface
  • a setter for a property only if the property implements the WritableValue interface

If a class is tagged with @Property I would suggest that all fields implementing either ReadOnlyProperty, WritableValue, or both should be handled as JavaFX properties.

Indeed there are a few refinements that would need to be done. I'm actually thinking that the annotation should be @FXProperty for one. I don't know if there's a point in going into details until there is a formal response.

This seems like a perfect fit for Lombok. Would this be difficult to implement?

@rzwitserloot at one point you were considering this but since then none of the JavaFx related issues seem to get any response.

@gtnarg I think you mean the Google Group thread.

@omega09 - you are correct - I think I mistakenly referenced @rzwitserloot

I created a simple implementation which currently works in eclipse.
https://github.com/rgra/lombok/tree/Issue1222

@FxBean
public class Test {
private IntegerProperty idProperty = new SimpleIntegerProperty(this, "id");
private LongProperty LongProperty = new SimpleLongProperty(this, "Long");
private FloatProperty FloatProperty = new SimpleFloatProperty(this, "Float");
private DoubleProperty DoubleProperty = new SimpleDoubleProperty(this, "Double");
private ObjectProperty objectProperty = new SimpleObjectProperty<>(this, "objectProperty");
private ListProperty listProperty = new SimpleListProperty<>(this, "list");
private MapProperty mapProperty = new SimpleMapProperty<>(this, "map");
private SetProperty setProperty = new SimpleSetProperty<>(this, "set");
}

This will generate getters for the properties itself and Getters and Setters for the values itself.
List/Map/Set will have the matching Observable Types.
For ObjectProperties the Generic Type is used for the value getters/setters.

Thanks @rgra, but I could not get this to work. I built your fork and referenced the resulting jar in a project with your given test file. I get no compilation errors but also no methods are generated - not in the Outline view in eclipse and not in the autocomplete options. What am I missing?

@omega09 Here's the source I used which is working for me (when launching lombokized eclipse in debug mode from within eclipse)
https://gist.github.com/rgra/6f52385979b8bebd357335f8e0d76876

Did you replace the lombok jar which is eclipse using and which your project is using?

@rgra

Did you replace the lombok jar which is eclipse using and which your project is using?

No...

So now this is working. There are a few things that need to be corrected. I don't know what's your preferred method here: that I point out each issue in this thread, that I fork your fork and commit my changes there, or that I create pull requests to yours.

For now I'll use the first method:

  • Getters and Setters are not generated for fields whose names don't end with "Property" (line 110). The field name should not matter to anything. In fact, the official tutorial I quoted in the first comment uses the field name amountDue. The correct way to check how to employ Getters and Setters is to check the interfaces the type implements, probably something like what Xylo suggested above. I did not fully think about it yet.
  • The Getter for the property should be named fieldName + "Property", as in the first comment (line 130 and friends). Currently it starts with "get".
  • The Getter and Setter methods should probably be final by default (lines 139 & 242).
  • Annotation should be applicable to individual fields (line 85 and consequences).
  • Not sure if FxBean is the best name considering they are called "properties" now, but will leave that for more input.

Thanks again for starting this.

@omega09 Sorry my post might have been misleading.
I implemented it because I needed it myself for an example.
The implementation is neither correct nor complete. I just wanted to show that it's easy to do.
Please fork it and make the adjustments you find important youself :)

@rgra I see, I thought it was a first step towards implementing this feature into Lombok.

Looks like we're back to waiting for a formal review on this request.

I have a somewhat working implementation of this for Eclipse. A problem I'm facing is that I don't know how to check if the field type implements specific interfaces. Does this require resolution?

@omega09 If you talking about determining if a particular class instance implements an interface, you can use:

SomeInterface.class.isAssignableFrom(classThatMayOrMayNotImplementSomeInterface)

There's also a getInterfaces() method on the class object that returns an array of interface class objects the class implements.

@tpmoney We're dealing with the AST/Eclipse Node directly. Neither of those would work.

@omega09 if I'm not mistaken the NodeType we're dealing with should be FieldDeclaration. By calling getType().resolveBinding() on it you get an instance of ITypeBinding on which you can further invoke methods like getSuperclass() and getInterfaces(). With this information it should be possible to determine whether or not a field type implements a certain interface.

@f-cramer getType().resolveBinding() returns null if I remember correctly.

Is there any update or implementation for this? :)

I can upload my fork which is a partial work for Eclipse if you want.

I would really appreciate that! Thank you!

Ping. Any updates on this? Would love to help in any way I can 馃槃

Ping, too. I would be interested on this feature, too.

What we would need is at least a before and after image.

What would the code look like with @FxBean on it, and how would it look delomboked?

Oh, and there is no way to way to see if a field implements an interface. That needs resolution.

Hello, thank you for the fast reply. Here is one example for a Property and the three posible outcomes.

One:

@Getter @Setter @FxBean
private final LongProperty id = new SimpleLongProperty();

Would become:

public final LongProperty idProperty() {
    return this.id;
}
public final long getId() {
    return this.idProperty().get();
}
public final void setId(final long id) {
    this.idProperty().set(id);
}

Two:

@Getter @FxBean
private final LongProperty id = new SimpleLongProperty();

Would become:

public final ReadOnlyLongProperty idProperty() {
    return this.id;
}
public final long getId() {
    return this.idProperty().get();
}

Three:

@Setter @FxBean
private final LongProperty id = new SimpleLongProperty();

Would become:

public final WritableLongValue idProperty() {
    return this.id;
}
public final void setId(final long id) {
    this.idProperty().set(id);
}

This three cases have to be implemented for the folowing Property-Types:

DoubleProperty
FloatProperty
IntegerProperty
ListProperty
LongProperty
MapProperty
ObjectProperty
SetProperty
StringProperty

For more information about FX-Properties you could read this:
https://wiki.openjdk.java.net/display/OpenJFX/JavaFX+Property+Architecture

What we would need is at least a before and after image.

What would the code look like with @FxBean on it, and how would it look delomboked?

Hello, are you working on the issue or is more information needed? Greatings.

+1

Duplicate of #521

Was this page helpful?
0 / 5 - 0 ratings