小编典典

在模型类中使用javafx.beans属性

hibernate

在模型类中使用JavaFX bean属性是否正确?

我想知道在模型类中使用属​​性是否能够将它们与视图组件轻松绑定是否是一种好习惯。我不担心将来这些库的可用性,因为我的程序将在JRE8或更高版本上运行,但是在模型类中使用JavaFX库的性质使我持怀疑态度,并且我担心当前和将来的不兼容性,尤其是因为我想使用Hibernate来保留这些属性。

注意:我使用纯JavaFX环境,并且我的应用程序永远不需要Swing兼容性。


阅读 517

收藏
2020-06-20

共1个答案

小编典典

我将在这里提出不同意见。

JavaFX属性和JPA

正如我评论jewelsea的答案一样,只要您使用“属性访问”而不是“字段访问”,就可以在JPA中使用基于JavaFX属性的Bean。我链接到那里的博客文章对此进行了更详细的介绍,但是基本思想是任何注释都应该在get...()方法上,而不是在字段上。据我所知,这确实阻止了将任何只读JavaFX属性模式与JPA结合使用,但是我从来没有真正感觉到JPA在只读属性(即get方法和无set方法)中表现良好。

序列化

与我对jewelsea答案的评论相反,并受益于几个星期的工作(并且被安排为我面临使用JavaFX属性在JavaFX客户端上复制多个实体类的位置),我认为缺乏JavaFX属性的序列化可以解决。关键的观察结果是,您实际上只需要序列化属性的包装状态(而不是任何侦听器)。您可以通过实现java.io.ExternalizableExternalizable是的子接口Serializable,要求您填写readExternal(...)writeExternal(...)方法。可以实现这些方法以仅外部化属性包装的状态,而不是属性本身。这意味着,如果您的实体先序列化然后反序列化,您将得到一个新的属性实例,并且将不会保留任何侦听器(即,侦听器实际上变为transient),但是据我所知,这就是所需要的在任何合理的用例中。

我尝试用这种方式定义的bean,并且一切似乎都很好地工作。另外,我进行了一个小实验,使用杰克逊映射器在JSON表示形式之间进行转换,从而在客户端和静态Web服务之间传输它们。由于映射器仅依靠使用get和set方法,因此可以正常工作。

一些警告

需要注意两点。与任何序列化一样,拥有无参数的构造函数也很重要。当然,由JavaFX属性包装的所有值本身必须可序列化-
再次,这与任何可序列化bean的规则相同。

关于JavaFX属性通过副作用起作用的观点已被很好地理解,并且在将这些属性(在某种程度上考虑到单线程模型的设计)移至潜在的多线程服务器时,需要格外小心。一个好的经验法则可能是,如果您使用此策略,则仅应在客户端注册侦听器(请记住,这些侦听器是暂时的,无论是通过序列化还是通过JSON表示,都可以传输回服务器)。当然,这表明在服务器端使用它们可能是一个糟糕的设计。在拥有“所有人的万事万物”的单个实体(JavaFX客户端的可观察属性,可序列化以实现持久性和/或远程访问,

最后,如果您确实使用了JPA批注,则这些批注具有运行时保留,这意味着(我认为)您的JavaFX客户端将需要在类路径上使用javax.persistence规范。

这是一个“四季皆宜的人”实体的示例:

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.time.MonthDay;

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
 * Entity implementation class for Entity: Person
 *
 */
@Entity

public class Person implements Externalizable {


    private static final long serialVersionUID = 1L;

    public Person() {

    }

    public Person(String name, MonthDay birthday) {
        setName(name);
        setBirthday(birthday);
    }

    private final IntegerProperty id = new SimpleIntegerProperty(this, "id");

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    public int getId() {
        return id.get();
    }

    public void setId(int id) {
        this.id.set(id);
    }

    public IntegerProperty idProperty() {
        return id ;
    }

    private final StringProperty name = new SimpleStringProperty(this, "name");

    // redundant, but here to indicate that annotations must be on the property accessors:
    @Column(name="name")
    public final String getName() {
        return name.get();
    }

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

    public StringProperty nameProperty() {
        return name ;
    }

    private final ObjectProperty<MonthDay> birthday = new SimpleObjectProperty<>();

    public final MonthDay getBirthday() {
        return birthday.get();
    }

    public final void setBirthday(MonthDay birthday) {
        this.birthday.set(birthday);
    }

    public ObjectProperty<MonthDay> birthdayProperty() {
        return birthday ;
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeInt(getId());
        out.writeObject(getName());
        out.writeObject(getBirthday());
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {
        setId(in.readInt());
        setName((String) in.readObject());
        setBirthday((MonthDay) in.readObject());
    }

}
2020-06-20