JavaBeanPropertyAdapter Reloaded

Michael Heinrichs michael.heinrichs at oracle.com
Tue Jan 3 01:16:08 PST 2012


Hi Jonathan,

I have not explicitly tested the prototype with ListView or TableView, but I think it can be integrated easily. The adapters for Java Beans will make the PropertyReference API more or less obsolete. The only difference I am aware of right now is, that the PropertyReference class did the reflection in a privileged block. I did not do this in the adapter implementation, because I did not understand the reason. Maybe I will learn very quickly and have to fix it soon. :-)

My feeling is, that the memory footprint of your current solution and a solution using adapters will be roughly the same, in cases where the Java Beans do not support change listeners. There is one object per property (PropertyReference vs. JavaBeanPropertyBuilder) and one object per row (ReadOnlyObjectWrapper vs. JavaBeanObjectProperty) with roughly the same information. Oh, just noticed... Are you sure, you are using ReadOnlyObjectWrapper? In that case you are probably wasting (a small amount of) memory and the new solution would be better.

Without knowing any details, I think it would have been sufficient to use ReadOnlyObjectPropertyBase, which is smaller. Maybe you could go even further up in the hierarchy. What functionality do you need from the cell values? If it is only observability, an ObservableObjectValue is sufficient. That means, you could use com.sun.javafx.binding.ObjectConstant for immutable values.

- Michael



On 03.01.2012, at 02:19, Jonathan Giles wrote:

> Michael,
> 
> I'm interested to learn how you foresee these being used in the UI controls (mainly ListView and TableView). In particular, the TableView control (but any thoughts you have on the simpler ListView control would be appreciated too).
> 
> To give a brief overview, TableView<T> has an items ObservableList<T>. Each TableColumn has a cellValueFactory (not to be confused with cellFactory) which is responsible for retrieving the data for a given column. The most common implementation of the cellValueFactory is javafx.scene.control.cell.PropertyValueFactory. This class uses the old PropertyReference API internally to reflectively get the Property if it is available (and this is then bound to so that changes are automatically reflected visually). If there is no *property() method, we try to call the get/is*() to get the value, and wrap this in a ReadOnlyObjectWrapper. This means that the value will be forever static (unless the developer rebuilds the TableView).
> 
> Can I use the JavaBeanPropertyAdapter to add more functionality here (in particular, observability of JavaBean properties)? If so, is it cheap enough to have many of these bindings (I only create bindings for the visible cells, not for all of them).
> 
> -- Jonathan
> 
> 
> On 3/01/2012 12:32 a.m., Michael Heinrichs wrote:
>> Hi everybody,
>> 
>> I took the feedback for the first version of the Java Bean adapter and created a new design with the feedback incorporated. The general idea is to take whatever is available and use it. For example, if the Java Bean property supports change listeners, this will be used to synchronize changes from the Java Bean property to the JavaFX property. If there is no support for change listeners, you can still create an adapter, but you have to do the synchronization yourself or disallow changing the Java Bean property.
>> 
>> I put everything in separated classes now and added a new package that contains the new classes and interfaces: javafx.beans.property.adapter.
>> 
>> 
>> 
>> There are two new interfaces that define the common functionality of all JavaBeanProperty / ReadOnlyJavaBeanProperty instances:
>> 
>> public interface ReadOnlyJavaBeanProperty<T>  extends ReadOnlyProperty<T>  {
>>     void fireValueChangedEvent();
>>     void dispose();
>> }
>> 
>> public interface JavaBeanProperty<T>  extends ReadOnlyJavaBeanProperty<T>, Property<T>  {}
>> 
>> The method fireValueChangedEvent() can be called to notify the adapter that the Java Bean property changed in case it does not support change listeners. The implementation uses WeakReferences and some automatic cleanup, if there are no references to the property left. But if you want more control, you can call dispose() on an adapter to remove all hooks to the bean.
>> 
>> 
>> 
>> Then we have a bunch of implementations for all types of Java Bean adapters, e.g.:
>> 
>> public final class ReadOnlyJavaBeanBooleanProperty extends ReadOnlyBooleanProperty implements ReadOnlyJavaBeanProperty<Boolean>  {...}
>> 
>> public final class ReadOnlyJavaBeanObjectProperty<T>  extends ReadOnlyObjectProperty<T>  implements ReadOnlyJavaBeanProperty<T>  {...}
>> 
>> public final class JavaBeanBooleanProperty extends BooleanProperty implements JavaBeanProperty<Boolean>  {...}
>> 
>> public final class JavaBeanObjectProperty<T>  extends ObjectProperty<T>  implements JavaBeanProperty<T>  {...}
>> 
>> 
>> 
>> And finally the really interesting part, the builders. There are two possibilities to use them. If you need to create an adapter for the same property of a collection of beans, you should first create the builder and then call createXYZProperty() for each bean. If you need to create just one adapter, there are static methods to do everything with a single call.
>> 
>> public final class ReadOnlyJavaBeanPropertyBuilder {
>>     public static ReadOnlyJavaBeanBooleanProperty createBooleanProperty(Object bean, String propertyName) throws NoSuchMethodException {...}
>>     public static<T>  ReadOnlyJavaBeanObjectProperty<T>  createObjectProperty(Object bean, String propertyName) throws NoSuchMethodException {...}
>>     // same for all other types
>> 
>>     public ReadOnlyJavaBeanPropertyBuilder(String propertyName, Class<?>  beanClass) throws NoSuchMethodException {...}
>>     public ReadOnlyJavaBeanPropertyBuilder(String propertyName, Class<?>  beanClass, String getterName) throws NoSuchMethodException {...}
>>     public ReadOnlyJavaBeanPropertyBuilder(String propertyName, Class<?>  beanClass, Method getter) {...}
>> 
>>     public ReadOnlyJavaBeanBooleanProperty createBooleanProperty(Object bean) {...}
>>     public<T>  ReadOnlyJavaBeanObjectProperty<T>  createObjectProperty(Object bean) {...}
>>     // same for all other types
>> }
>> 
>> public final class JavaBeanPropertyBuilder {
>>     public static JavaBeanBooleanProperty createBooleanProperty(Object bean, String propertyName) throws NoSuchMethodException {...}
>>     public static<T>  JavaBeanObjectProperty<T>  createObjectProperty(Object bean, String propertyName) throws NoSuchMethodException {...}
>>     // same for all other types
>> 
>>     public JavaBeanPropertyBuilder(String propertyName, Class<?>  beanClass) throws NoSuchMethodException {...}
>>     public JavaBeanPropertyBuilder(String propertyName, Class<?>  beanClass, String getterName, String setterName) throws NoSuchMethodException {...}
>>     public JavaBeanPropertyBuilder(String propertyName, Class<?>  beanClass, Method getter, Method setter) {...}
>> 
>>     public JavaBeanBooleanProperty createBooleanProperty(Object bean) {...}
>>     public<T>  JavaBeanObjectProperty<T>  createObjectProperty(Object bean) {...}
>>     // same for all other types
>> }
>> 
>> What do you think?
>> 
>> Thanks,
>> Michael



More information about the openjfx-dev mailing list