JavaBeanProperty: jdk7 vs jdk 8 - WeakOnTheFeet vs StrongInTheArm

A long-term problem (some call it - maybe - a function :) is the weakness of all listeners set by all fx bindings. As a result, we cannot build “chains” of properties without maintaining a strong link to each link in the chain.

The specific type of such a chain link is JavaBeanProperty: its purpose is to adapt the javabean property to the fx property. As a rule, no one is interested in the adapter as such, so using it will do something like

private Parent createContentBean() {
    ...
    // local ref only
    Property property = createJavaBeanProperty();
    Bindings.bindBidirectional(label.textProperty(), property, NumberFormat.getInstance());

.. wonders why the tag is not updating. Changing the property to a strong link will work as expected (leaving me puzzeld as to who is responsible for submitting the dummy, but this is another question):

Property property;
private Parent createContentBean() {
    ...
    // instantiate the field
    property = createJavaBeanProperty();
    Bindings.bindBidirectional(label.textProperty(), property, NumberFormat.getInstance());

A long introduction, but almost there: jdk8 somehow changed the implementation, so the first approach now works, there is no longer any need to maintain a strong reference to JavaBeanProperty. Custom chain links, on the other hand, still need a strong link.

Questions:

  • Is this a deliberate change in behavior, and if so, why?
  • How is this achieved? The code looks very similar ... and I would like to try something like this in user adapters.

Full example game with:

public class BeanAdapterExample extends Application {

    private Counter counter;

    public BeanAdapterExample() {
        this.counter = new Counter();
    }

    Property property;
    private Parent createContentBean() {
        VBox content = new VBox();
        Label label = new Label();
        // strong ref
        property = createJavaBeanProperty();
        // local property
        Property property = createJavaBeanProperty();
        Bindings.bindBidirectional(label.textProperty(), property, NumberFormat.getInstance());
        Slider slider = new Slider();
        slider.valueProperty().bindBidirectional(property);
        Button button = new Button("increase");
        button.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent paramT) {
                counter.increase();
            }

        });
        content.getChildren().add(label);
        content.getChildren().add(slider);
        content.getChildren().add(button);
        return content;
    }

    protected JavaBeanDoubleProperty createJavaBeanProperty(){
        try {
            return JavaBeanDoublePropertyBuilder.create()
                    .bean(counter).name("count").build();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void start(Stage stage) throws Exception {
        Scene scene = new Scene(createContentBean());
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        Application.launch(args);
    }


    public static class Counter {

        private double count;

        public Counter() {
            this(0);
        }

        public Counter(double count) {
            this.count = count;
        }

        /**
         * Increases the counter by 1.
         */
        public void increase() {
            setCount(getCount()+ 1.);
        }

        /**
         * @return the count
         */
        public double getCount() {
            return count;
        }

        /**
         * @param count the count to set
         */
        public void setCount(double count) {
            double old = getCount();
            this.count = count;
            firePropertyChange("count", old, getCount());
        }

        PropertyChangeSupport support = new PropertyChangeSupport(this);

        public void addPropertyChangeListener(PropertyChangeListener l) {
            support.addPropertyChangeListener(l);
        }

        public void removePropertyChangeListener(PropertyChangeListener l) {
            support.removePropertyChangeListener(l);
        }

        protected void firePropertyChange(String name, Object oldValue,
                Object newValue) {
            support.firePropertyChange(name, oldValue, newValue);
        }

    }

}

BTW: Swing, beans

+3
2

issue - , , .

+2

:

  • : . , JavaBeanProperty , .
  • , , - phantomReference (Cleaner in the snippet) , : , , (?) . , "" , . , .

jdk8 :

JavaBeanDoubleProperty(PropertyDescriptor descriptor, Object bean) {
    this.descriptor = descriptor;
    this.listener = descriptor.new Listener<Number>(bean, this);
    descriptor.addListener(listener);
    Cleaner.create(this, new Runnable() {
        @Override
        public void run() {
            JavaBeanDoubleProperty.this.descriptor.removeListener(listener);
        }
    });
}

: ​​ , , javabeanProperty:

protected SimpleDoubleProperty createPhantomedProperty(final boolean phantomed) {
    SimpleDoubleProperty adapter = new SimpleDoubleProperty(){
        {
            // prevents the property from being garbage collected
            // must be done here in the constructor
            // otherwise reclaimed immediately
            if (phantomed) {
                Cleaner.create(this, new Runnable() {
                    @Override
                    public void run() {
                        // empty, could do what here?
                        LOG.info("runnable in cleaner");
                    }
                });
            }
        }

    };

    return adapter;
}

, , jdk7/8 ( VisualVM): "", 100k JavaBeanProperties. jdk7 . jdk8 (sloooowly! ) . , bean .

Button create100K = new Button("create 100k properties");
create100K.setOnAction(new EventHandler<ActionEvent>() {

    @Override
    public void handle(ActionEvent paramT) {
        Property propertyFX;
        /// can't measure any effect
        for (int i = 0; i < 100000; i++) {
            propertyFX = createCountProperty();
        }
        LOG.info("created 100k adapters");
    }

});
Button releaseCounter = new Button("release counter");
releaseCounter.setOnAction(new EventHandler<ActionEvent>() {

    @Override
    public void handle(ActionEvent paramT) {
        counter = null;
    }

});

FYI: - , ! , ​​ 8u20, , . , - c & p JavaBeanXXProperty/Builders . . , jdk7 ( , : -)

+1

All Articles