JavaBeans属性适配器是如何工作的?

3
如果我按照这里描述的JavaFX属性定义,我试图做的事情可以正常工作。现在,相反,我想使用Java Beans属性适配器从Java Beans对象中定义属性。由于没有文档,我无法弄清楚它是如何工作的。
假设我有一个简单的POJO类:
public class Person {
    private String name;

    public String getName() {
        return name;
    }

    public void setName( String name ) {
        this.name = name;
    }
}

以及一个PersonProperty:

public class PersonProperty {
    private Person person = new Person();

    private JavaBeanStringProperty name;

    public PersonProperty() throws NoSuchMethodException {
        name = JavaBeanStringPropertyBuilder.create().bean( person ).name( "name" ).build();
    }

    public Person getPerson() {
        return person;
    }

    public void setPerson( Person person ) {
        this.person = person;
    }

    public JavaBeanStringProperty nameProperty() {
        return name;
    }
}

最后进行一项测试:
public void personTest() throws NoSuchMethodException {
    PersonProperty pp = new PersonProperty();

    pp.getPerson().setName( "A" );
    pp.getPerson().setName( "B" );

    pp.nameProperty().addListener( new ChangeListener<String>() {
        @Override
        public void changed( ObservableValue<? extends String> ov, String t, String t1 ) {
            System.out.println( "from " + t + " to " + t1 );
        }
    } );

    pp.getPerson().setName( "C" );
    pp.getPerson().setName( "D" );
}

我期望看到的是:
from B to C
from C to D

相反,什么也不会出现。

如果我在 personTest 的结尾添加 pp.nameProperty().set("E"),我会得到 从 B 到 E

1个回答

3
我认为这里的问题在于Person确实是一个POJO,但不是一个JavaBean:它缺少PropertyChangeListeners的hooks。Java无法自动知道Person#name何时更改。 相反地,JavaFX适配器将寻找一种方法来添加PropertyChangeListener并监听名为'name'的属性的事件。如果您将PropertyChangeSupport实例添加到Person类中,则可以按预期工作。
public class Person {
    private String name;
    private PropertyChangeSupport _changeSupport;

    public Person() {
        _changeSupport = new PropertyChangeSupport(this);
    }

    public String getName() {
        return name;
    }

    public void setName( String name ) {
        final String prev = this.name;
        this.name = name;
        _changeSupport.firePropertyChange("name", prev, name);
    }

    public void addPropertyChangeListener(final PropertyChangeListener listener) {
        _changeSupport.addPropertyChangeListener(listener);
    }
}

为什么它不是JavaBean?它有一个没有参数的构造函数和访问器方法(即使它不可序列化,但如果它实现了Serializable也不会改变)。此外,我无法更改Person类,我无法访问它。我想从已经存在的JavaBean类创建一个属性。 - Alf
非常抱歉回复晚了。是的,Person类确实遵循JavaBean约定,但如果您将“name”视为绑定属性,则只部分符合(请参见http://docs.oracle.com/javase/tutorial/javabeans/writing/properties.html)。JavaBeans会在绑定属性更改时通知已注册的侦听器,这是所需的。如果您无法更改Person,则恐怕只剩下两个选择:为Person实例添加代理类或使用方面拦截set方法。 - sarcan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接