Thanks, John. It would be helpful if you could create an issue in jira to track 
this. 

On Jan 8, 2014, at 4:18 PM, John Hendrikx <hj...@xs4all.nl> wrote:

> On 8/01/2014 14:28, David Grieve wrote:
>> The reason things are as they are is because most properties in the core 
>> classes are lazily created and I didn't want cause the property to be 
>> created just to see if it was bound. But that is a particular concern for 
>> the core classes and not so much for controls.
> I see, this mechanism certainly doesn't try to do that.  It only works when 
> the properties are created in advance.
>> I'm not sure if you are aware of the javafx.css.SimpleStyleableXXXProperty 
>> classes. I'd be interested to see how your custom classes dovetail into 
>> these as I'd be more than willing to consider taking  your additions and 
>> calling them my own… uh, um, I mean, rolling them into the source code.
> I wasn't aware of those, but I just took a look at them.  They do make the 
> process a little bit easier, although still require creating a CssMetaData 
> object yourself.  If you want to use the code or just the idea, please feel 
> free -- it would be very nice for creating custom controls if it was part of 
> JavaFX.
>> Have you looked at the initialization-on-demand holder pattern for creating 
>> the List?
> That's the "Super-lazy instantiation pattern from Bill Pugh" ?  I've seen it 
> several times in the JavaFX sources, and I think it is a neat way to avoid 
> certain statics from being created immediately after the class loads.
> 
> However, I'm not sure if it applies here, the first getCssMetaData call 
> basically is the trigger that causes all CssMetaData objects and the List to 
> get created...  I'm not sure how I could make it any more lazy than that.  
> The Map I use in the properties themselves is static, so shouldn't cause too 
> much footprint.
> 
> The code I use for the one of the SimpleStyleableXXXProperty is below.  It 
> relies on a Map that will cache CssMetaData objects (for different instances 
> of the same property in a Control) and are only created when they're needed.  
> CssMetaData objects only get created one time on access, after that further 
> calls just do a quick map lookup.
> 
> It makes assumptions about the kind of converter needed, which could be 
> parameterized further with another constructor option.
> 
> public class SimpleStyleableDoubleProperty extends StyleableDoubleProperty {
>  private static final Map<Class<?>, Map<String, CssMetaData<? extends 
> Styleable, Number>>> CSS_META_DATA_BY_NAME_BY_CLASS = new HashMap<>();
> 
>  private final Object bean;
>  private final String name;
>  private final String cssName;
>  private final double initialValue;
> 
>  public SimpleStyleableDoubleProperty(Object bean, String name, String 
> cssName, double initialValue) {
>    super(initialValue);
> 
>    this.bean = bean;
>    this.name = name;
>    this.cssName = cssName;
>    this.initialValue = initialValue;
>  }
> 
>  @Override
>  public CssMetaData<? extends Styleable, Number> getCssMetaData() {
>    // TODO consider synchronizing CSS_META_DATA_BY_NAME_BY_CLASS -- depends 
> on whether or not this ever gets called by more than one thread.
>    Map<String, CssMetaData<?, Number>> cssMetaDataByName = 
> CSS_META_DATA_BY_NAME_BY_CLASS.get(bean.getClass());
> 
>    if(cssMetaDataByName == null) {
>      cssMetaDataByName = new HashMap<>();
>      CSS_META_DATA_BY_NAME_BY_CLASS.put(bean.getClass(), cssMetaDataByName);
>    }
> 
>    CssMetaData<? extends Styleable, Number> cssMetaData = 
> cssMetaDataByName.get(cssName);
> 
>    if(cssMetaData == null) {
>      cssMetaData = new CssMetaData<Styleable, Number>(cssName, 
> StyleConverter.getSizeConverter(), initialValue) {
>        @Override
>        public boolean isSettable(Styleable styleable) {
>          return !SimpleStyleableDoubleProperty.this.isBound();
>        }
> 
>        @Override
>        public StyleableDoubleProperty getStyleableProperty(Styleable 
> styleable) {
>          return SimpleStyleableDoubleProperty.this;
>        }
>      };
>    }
> 
>    return cssMetaData;
>  }
> 
>  @Override
>  public Object getBean() {
>    return bean;
>  }
> 
>  @Override
>  public String getName() {
>    return name;
>  }
> }
> 
> --John
> 
> 
>> 
>> On Jan 7, 2014, at 9:34 PM, John Hendrikx<hj...@xs4all.nl>  wrote:
>> 
>>> Hi List,
>>> 
>>> I'm in the process of adding CSS metadata to a new control, and I noticed 
>>> there is a lot of boilerplate.
>>> 
>>> In order to reduce this, I've created some custom classes StyleableProperty 
>>> classes (SimpleStyleableXXXProperty), which reduces the boilerplate 
>>> significantly without sacrificing much (if any) performance.  The only 
>>> thing that I cannot easily provide in this fashion is the static 
>>> getClassCssMetaData method.  From the documentation I understand it is 
>>> there just for convience for subclass creators and is not used by the CSS 
>>> engine at all -- atleast, everything seems to work.
>>> 
>>> The shortened version for CSS aware properties basically looks like:
>>> 
>>>  private final SimpleStyleableDoubleProperty cellAlignment = new 
>>> SimpleStyleableDoubleProperty(this, "cellAlignment", "-fx-cell-alignment", 
>>> 0.8);
>>>  private final SimpleStyleableDoubleProperty density= new 
>>> SimpleStyleableDoubleProperty(this, "density", "-fx-density", 0.02);
>>>  private final SimpleStyleableBooleanProperty reflectionEnabled= new 
>>> SimpleStyleableBooleanProperty(this, "reflectionEnabled", 
>>> "-fx-reflection-enabled", true);
>>>  private final SimpleStyleableBooleanProperty clipReflections= new 
>>> SimpleStyleableBooleanProperty(this, "clipReflections", 
>>> "-fx-clip-reflections", true);
>>> 
>>> With one small bit of supporting code in the relevant class (Skin or 
>>> Control), which is basically a non-static implementation of the standard 
>>> CSS List example code:
>>> 
>>>  private static List<CssMetaData<? extends Styleable, ?>>  cssMetaData;
>>> 
>>>  @Override
>>>  public List<CssMetaData<? extends Styleable, ?>>  getCssMetaData() {  // 
>>> Unsynchronized. WC: list gets initialized multiple times.
>>>    if(cssMetaData == null) {
>>>      List<CssMetaData<? extends Styleable, ?>>  metaData = new 
>>> ArrayList<>(super.getCssMetaData());
>>>      Collections.addAll(metaData,
>>>          cellAlignment.getCssMetaData(),
>>>          density.getCssMetaData(),
>>>          reflectionEnabled.getCssMetaData(),
>>>          clipReflections.getCssMetaData()
>>>      );
>>>      cssMetaData = Collections.unmodifiableList(metaData);
>>>    }
>>> 
>>>    return cssMetaData;
>>>  }
>>> 
>>> Note that the List is static and lazy-final.  The same goes for the 
>>> getCssMetaData method in the SimpleStyleableXXXProperty classes.  There is 
>>> a slight performance decrease in those classes as getCssMetaData is looked 
>>> up from a static Map (indexed by Class + css property name) and lazily 
>>> created as needed -- a Map lookup however should be quite fast enough.
>>> 
>>> I'm sure the design had good reason to do things as they are, and I'm 
>>> wondering if reducing the boilerplate has left me missing something 
>>> important.
>>> 
>>> I welcome any insights!
>>> 
>>> --John
> 

Reply via email to