In my last article I gave an overview of the general functionality of JavaFX properties, this time I will explain how you can use JavaFX properties in your own classes.
Let us assume we want to implement a class Balloon with two properties: the radius, a double value, and the color which is of type javafx.scene.paint.Color. According to the conventions for JavaFX properties, the class needs to have these methods:
public class Balloon { public double getRadius() {...} public void setRadius(double newRadius) {...} public DoubleProperty radiusProperty() {...} public Color getColor() {...} public void setColor(Color newColor) {...} public ObjectProperty<Color> colorProperty() {...} }
Simple Implementation
The simplest implementation of this class will just create two private fields for the properties. The class would look like this:
public class Balloon { private final DoubleProperty radius = new DoubleProperty(this, "radius", 20); public double getRadius() { return radius.get(); } public void setRadius(double newRadius) { radius.set(newRadius); } public DoubleProperty radiusProperty() { return radius; } private final ObjectProperty<Color> color = new ObjectProperty<Color>(this, "color", Color.RED); public Color getColor() { return color.get(); } public void setColor(Color newColor) { color.set(newColor); } public ObjectProperty<Color> colorProperty() { return color; } }
Three arguments are passed to the constructores in the example above, a reference to the containing Object, the name of the property, and the initial value of the properties (20 and Color.RED). The first two values will be returned, if a user calls getBean() or getName() on the property. These values are not required by the properties themselves, they can be constructed without. But it is recommended to set these values for all public properties, because you never know if a user needs them. Only for local usage, for example private fields, you can safely omit them.
The getter and setter forward calls to the getter and setter of the property and the methods radiusProperty() and colorProperty() return the created properties.
This is the simplest implementation possible, I believe, but it has a disadvantage. It requires to create an Object for each property, even if advanced features like bindings are not used. This may not sound too bad, but one has to keep in mind that this is one Object per property. If your class contains a number of properties and you create several instances, the number of created property objects can become huge.
To reduce the memory consumption, we can introduce lazy initialization. Lazy initialization means, we do not create the properties immediately, but only once they are needed. So far I know of two patterns, which are general enough to be reused for all kinds of properties.
Rarely used properties
The first pattern works well for properties that are rarely used. With that I mean, that they usually keep their initial default value and a developer would rarely use the advanced features of bindings. For such a property, the following implementation can be used:
private static final double DEFAULT_RADIUS = 20; private DoubleProperty radius; public double getRadius() { return (radius != null)? radius.get() : DEFAULT_RADIUS; } public void setRadius(double value) { if ((radius != null) || (value != DEFAULT_RADIUS)) { radiusProperty().set(value); } } public DoubleProperty radiusProperty() { if (radius == null) { radius = DoubleProperty(this, "radius", DEFAULT_RADIUS); } return radius; }
One of the main differences is that the field radius is not final anymore. It is initialized with null and we will only create an object and assign it to radius once it is needed. That is lazy initialization.
In this approach, the DoubleProperty needs to be available if either the user calls radiusProperty() to use the advanced features or if the value is set to something different than the default value. (In the example above the default value is stored in DEFAULT_RADIUS.)
The getter changed only slightly compared to the simple approach. We first check if a DoubleProperty was created for radius (radius != null) and if it was, we call the getter of the property as we did in the simple approach. If radius is still null, we know for sure, that it still carries the DEFAULT_VALUE, because setting another value or binding it to something else would have created the property. Therefore we return DEFAULT_VALUE, if radius is still null.
The DoubleProperty is created in the radiusProperty() method. First it checks, if it has been created already. If not, a new DoubleProperty is created and assigned to radius. From that moment on, the field radius will not change anymore, it will always point to the DoubleProperty we just created.
The setter calls radiusProperty() to create the property if needed and calls the setter on that object. The if-statement makes sure, we do not create an object if the setter is called with the default value.
The main advantage of this pattern is, that it has almost no performance penalty, only a minor increase in static footprint. One might wonder, if it really has any substantial impact, because already changing the value of the property causes the instantiation of the DoubleProperty. But to our own surprise it works better than we expected. My impression is, that in general the more properties a class has, the more properties are usually not changed. For example, if a class has only two properties, usually both are changed. But if a class has 20 properties, it is very likely that a number of them are never touched. For that reason, I would always recommend this approach for objects with many properties.
Usually no advanced features used
The second pattern works well for properties, which advanced features are usually not used. Here is the implementation for the field radius.
private DoubleProperty radius; private double _radius = 20; public double getRadius() { return (radius != null)? radius.get() : _radius; } public void setRadius(double value) { if (radius != null) { radius.set(value); } else { _radius = value; } } public DoubleProperty radiusProperty() { if (radius == null) { radius = DoubleProperty(this, "radius", _radius); } return radius; }
This pattern is very similar to the one above. Again we do not create radius upfront, but wait until it is needed. With this approach, the DoubleProperty is only needed, if a user wants to use the advanced features of JavaFX properties. In other words, just setting a different value will not cause the creation of the DoubleProperty.
For this approach to work, we introduce a second field _radius, that contains the value until the DoubleProperty radius is created. The getter and setter first check, if radius was already created and use then either the DoubleProperty radius or the double _radius. The method radiusProperty() works exactly as in the previous approach.
This approach is kind of a mixture between a typical implementation for traditional Java Beans and the simple implementation of JavaFX properties. The main advantage is, that creating the DoubleProperty object can be avoided even more often than in the approach above, but this comes with the price of an additional field. It is a trade-off. If you expect that a property is usually changed, but the advanced features like attaching a listener or binding the property are usually not used, this approach is recommended.
14 responses to “Creating JavaFX Properties”
Hello,
I created a properties project that is kind of similar to this a couple of years ago, when properties was talked about for Java. It’s at http://java.net/projects/properties in case you want to look at it for ideas and/or what not to do.
Why do you use radiusProperty() instead of the more obvious and easier on the eye/keyboard radius()? It feels like you are optimizing for int 0.1% case where there’s already a method with that name.. Just curious as I guess you have talked about it a lot inhouse.
Cheers,
Mikael
Hi Mikael,
that is a very good question. The name you are suggesting is preferred by almost everybody including me, but unfortunately it would not work well with other languages. Think about JavaScript for example, where var r = balloon.radius is translated to var r = ballon.getRadius() if such a method exists. But if Ballon had a method radius(), the function would be assigned to r. And using ballon.radius = r would not work at all if there is a method radius(). But with the current pattern this is translated to ballon.setRadius(r). The same issue would arise with many languages that translate their properties to Java Bean getters and setters when dealing with Java objects. Does that answer your question?
It does indeed. However, with that kind of scope it’s hard to do anything good and good is how it’d need to be done to be successful.
I think everybody will think like we both do regarding the Java naming, and only very few will know the reason. Even less will accept it as acceptable. This means a lot of people will be thinking “What the heck were they smoking?”. 🙂
Maybe it’s the alternate languages that should “pay” for being different than Java? Just add some automatic mangling to translators, eg in JavaFX’s own Web Runtime. In some language this will be necessary anyway for other purposes, e.g. in a language that has a real property facility (including JavaFX Script, aka Visage if they move forward), it’s mot likely that users will want to deal with three methods per property, they’ll want a mapping to the “native” properties anyway.
radiusProperty() is so un-JavaBeans… what about some pattern that looks like an extension of JavaBeans (a short prefix instead of a big suffix), like propRadius().
[…] Heinrichs has blogged about creating JavaFX 2.0 properties. This is a good read for anyone wanting to get to know some of the new JavaFX 2.0 […]
Actually, I prefer the xxProperty() convention. It makes it clear that it’s part of a convention and relates to the getXx(), setXx() methods.
I don’t like the propXx() suggestion – it just sounds lazy, and it doesn’t read properly.
Far more important, in my opinion, is that all of this boilerplate should be able to be simplified into a single-line definition:
property bindable lazy Double radius;
If we don’t do this in the Java language proper, I think an extension should be developed whereby files (for example with .javax extensions) are pre-parsed. This could solve other UI-related issues also, such as providing a way of specifying object trees, similar to the way JavaFX Script did it.
The goal should always be clarity of expression
My comment got too long, so now its a blog post http://www.jroller.com/scolebourne/entry/beans_and_properties
Basically, I worry about stateful properties. They may be fine for the client side, but they performed terribly on the server side when I tried them (too many objects being created/destroyed).
[…] Heinrichs has blogged about creating JavaFX 2.0 properties. This is a good read for anyone wanting to get to know some of the new JavaFX 2.0 […]
What about this on?
private Object radius = 20;
public double getRadius() {
return (radius instanceof DoubleProperty )? radius.get(): radius.doubleValue();
}
public void setRadius(double value) {
if (radius instanceof DoubleProperty) {
radius.set(value);
} else {
radius = value;
}
}
public DoubleProperty radiusProperty() {
if ( !(radius instanceof DoubleProperty)) {
radius = DoubleProperty(this, “radius”, radius.doubleValue());
}
return radius;
}
At first, I suggests you that in UI classes and in setter methods by changing return type from void to current class type and returning “this” from all setters you can avoids
from builder pattens, and reduce core library size. This approach has many advantages:
1) improves static footprint: get rid of many builder classes in core library
2) dynamic footprint: No need to instantiate two object instead of One
3) Simplifying API and improves Code readability
…
Edited by Mike:
I removed large part of this comment, because it is off topic and merely duplicates a feature request in our issue tracking system. If you are interested, you can read the whole discussion in JIRA. (You probably have to create an account for that.)
First of all, thank you very much for all of your comments. Be assured, I read each and every one of them thoroughly and consider them while thinking about ways to improve the JavaFX APIs.
Sorry for the late reply. I was traveling last week and had not much time for my blog. Hopefully I catch everything.
@Mikael Grev:
You wrote a very interesting proposal. I think the two approaches are not that far apart.
We kept the Java Bean getters and setters, because we considered them essential for our API to work with existing tools and frameworks. And we added a new method to access the property, mainly to allow lazy initialization.
I like the idea to define additional constraints in annotations and I will think about it some more. Best part is, that adding this functionality looks like a compatible change, which means we do not have to rush things and can add this later.
I will read your proposal more thoroughly during my upcoming vacation.
@Osvaldo Doederlein:
The translators for other languages are out of our control. We need a solution, that works with other languages out-of-the-box.
Certainly we hope, that other languages will be extended to provide native access to the advanced features of JavaFX properties. For example it would be nice, if bindings in Visage take advantage of the Binding API.
Changing the naming pattern is a huge change at this point, but if we get overwhelming feedback that it is required and we have a better suggestion, we will certainly do it. We do not use abbreviations in our names, except for widely used ones like HTTP, SOAP etc. Thus propRadius() cannot be used.
I actually like the fact that the name starts with the property name, because I just have to type the first one or two letters and code completion will give me the rest of the method name.
@Rhys Parsons:
We tried something like this. In our first implementation, we used annotations to declare the attributes of a property and then Lombok to add the additional code. It was not very well perceived. As much as developers do not like to look at verbose boilerplate code, they really hate not to be able to look at code when they want to. For example debugging became really painful with this approach. Thus we rewrote everything and made all code accessible to developers. In the long run, we expect IDEs to be able to generate the boilerplate code easily and hide it. The NetBeans team already started with this.
Adding property support to the Java language is needed, but this is a long term change.
@Stephen Colebourne:
Interesting post, I will take it with me during my vacation. 🙂
I can very well imagine that the approach has its limitations on the server side. We never tried that. Running on the server was not a requirement for us, JavaFX is intended for the client.
@Ali Ebrahimi:
What advantage should your approach have? It requires a lot of instanceof checks, which are expensive. I can imagine this can easily become a bottleneck if the property is often used.
If you estimate the memory usage, you have to consider not only the reference, but also the Number object itself as long as the property is not inflated. I think the approaches presented in the post will show lower memory consumption.
Mike,
I consider my own proposal without the small language changes to be an interim and not extensible solution. I concur with Stephen on this.
I think the property support should be done right, so that it will work for server side as well and so we don’t have to live with the mistakes for 20 years because we short cut two years of development time.
Have you considered “DoubleProperty Radius()”, where the first letter is capitalized? I know, not how we normally do methods in Java, but it might be something to consider. I use that naming convention when I use my properties from my proposal.
Actually propertyRadius() has an advantage. You can do bean.prop and press your favorite key combo to get ALL properties on a bean.
How do you intend to solve the problem where the been need direct access to the raw value? I haven’t solved that to my full satisfaction in my own proposal either (unsolvable in a practical fully contained way) but with compiler support property values could be inlined to the bean.
Have you developed this in a way that makes it long term? I mean, do you have some property support outlined where this new naming convention will help, and not be in the way, in the future?
Cheers,
Mikael
Michael,
Do you know if javafx.beans.binding is going to be in separate jar file? It might be useful as a migration path from a Swing app. First you modify your GUI Model to use javafx.beans.binding, and if that’s successful, then try out JavaFx.
Nathan,
I do not know of such a plan. But then again, I am not really involved in these kind of discussions. I suggest, you create a feature request for this in our issue tracking system.