Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support JavaFX properties #1222

Closed
omega09 opened this issue Oct 30, 2016 · 29 comments
Closed

Support JavaFX properties #1222

omega09 opened this issue Oct 30, 2016 · 29 comments

Comments

@omega09
Copy link

omega09 commented Oct 30, 2016

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.

@xylo
Copy link

xylo commented Jan 11, 2017

Duplicate of #521.

@omega09
Copy link
Author

omega09 commented Jan 12, 2017

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?

@xylo
Copy link

xylo commented Jan 12, 2017

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.

@omega09
Copy link
Author

omega09 commented Jan 23, 2017

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.

@gtnarg
Copy link

gtnarg commented Feb 18, 2017

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.

@omega09
Copy link
Author

omega09 commented Feb 18, 2017

@gtnarg I think you mean the Google Group thread.

@gtnarg
Copy link

gtnarg commented Feb 18, 2017

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

@rgra
Copy link
Contributor

rgra commented Feb 26, 2017

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<String, String> 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.

@omega09
Copy link
Author

omega09 commented Feb 27, 2017

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?

@rgra
Copy link
Contributor

rgra commented Feb 27, 2017

@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?

@omega09
Copy link
Author

omega09 commented Feb 27, 2017

@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.

@rgra
Copy link
Contributor

rgra commented Feb 28, 2017

@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 :)

@omega09
Copy link
Author

omega09 commented Feb 28, 2017

@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.

@omega09
Copy link
Author

omega09 commented Mar 7, 2017

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?

@tpmoney
Copy link

tpmoney commented Apr 14, 2017

@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.

@omega09
Copy link
Author

omega09 commented Apr 14, 2017

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

@f-cramer
Copy link

@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.

@omega09
Copy link
Author

omega09 commented Dec 22, 2017

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

@ahofmeister
Copy link

Is there any update or implementation for this? :)

@omega09
Copy link
Author

omega09 commented Feb 5, 2018

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

@ahofmeister
Copy link

ahofmeister commented Feb 6, 2018

I would really appreciate that! Thank you!

@aalmiray
Copy link

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

@matthias24
Copy link

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

@rspilker
Copy link
Collaborator

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?

@rspilker
Copy link
Collaborator

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

@matthias24
Copy link

matthias24 commented Nov 14, 2018

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:

BooleanProperty
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

@matthias24
Copy link

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.

@ivanjd
Copy link

ivanjd commented Feb 8, 2019

+1

@rspilker
Copy link
Collaborator

rspilker commented May 21, 2019

Duplicate of #521

@rspilker rspilker marked this as a duplicate of #521 May 21, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests