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

Joh*_*nny 24 java persistence hibernate model javafx

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

我想知道在模型类中使用属​​性是否能够更容易地使用视图组件绑定它们是一个好习惯.我不担心将来这些库的可用性,因为我的程序将在JRE8或更高版本上运行,但在模型类中使用JavaFX库的性质让我持怀疑态度,我担心当前和未来的不兼容性,特别是因为我想使用Hibernate来持久保存这些属性.

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

Jam*_*s_D 19

我将在这里提出一些不同意见.

JavaFX属性和JPA

正如我对jewelsea的回答所评论的那样,只要您使用"属性访问"而不是"字段访问",就可以使用基于JavaFX属性的bean和JPA.我在那里链接的博客文章详细介绍了这一点,但基本思路是任何注释都应该在get...()方法上,而不是在字段上.据我所知,这确实阻止了任何只读JavaFX属性模式与JPA的结合使用,但我从来没有真正觉得JPA在只读属性(即获取方法和没有设置方法)方面表现良好.

序列化

与我对jewelsea的答案的评论相反,并且利用几个星期的时间来处理这个问题(并且我已经被置于一个使用JavaFX属性在JavaFX客户端上复制几个实体类的位置),我认为缺乏可以解决JavaFX属性的序列化问题.关键的观察是你真的只需要序列化属性的包装状态(例如,不是任何监听器).你可以通过实施来做到这一点java.io.Externalizable.Externalizable是一个子接口Serializable,需要您填写readExternal(...)writeExternal(...)方法.可以实现这些方法来仅外化属性包装的状态,而不是属性本身.这意味着如果您的实体被序列化然后反序列化,您将最终得到一个新的属性实例,并且不会保留任何侦听器(即听众有效地成为transient),但据我所知,这将是想要的在任何合理的用例中.

我尝试用这种方式定义的bean,这一切似乎都运行得很好.另外,我在客户端和一个安静的Web服务之间进行了一个小实验,使用Jackson映射器转换为JSON表示和从JSON表示转换.由于mapper只依赖于使用get和set方法,所以这很好用.

一些警告

需要注意几点.与任何序列化一样,拥有无参数构造函数非常重要.当然,JavaFX属性包装的所有值本身都必须是可序列化的 - 这与任何可序列化bean的规则相同.

关于通过副作用工作的JavaFX属性的观点很好,在将这些属性(在某种程度上,设计时考虑了单线程模型)移动到潜在的多线程服务器时需要谨慎.一个好的经验法则可能是,如果您使用此策略,则只应在客户端注册侦听器(并且请记住,这些侦听器在传输回服务器方面是瞬态的,无论是通过序列化还是通过JSON表示).当然,这表明在服务器端使用这些可能是一个糟糕的设计; 在单个实体"为所有人提供所有东西"(JavaFX客户端的可观察属性,持久性和/或远程访问可序列化,以及JPA的持久映射)与公开功能之间的便利之间,它成为一种权衡(例如可观察性)它可能不完全合适(在服务器上).

最后,如果您使用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());
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 如何映射到JavaFX集合?Hibernate有映射到Lists/Sets的方法,但AFAIK它不会映射JavaFX集合.是否有实现OneToMany/ManyToMany关系并使用FXCollections(ObservableList或其他)来支持它们的模式? (4认同)

jew*_*sea 9

JavaFX Property Design

JavaFX属性的设计使您无需运行JavaFX程序即可使用它们.在的部分使用JavaFX属性和绑定教程甲骨文,证明这样的用法(如比尔类法案的属性模型).本教程中的示例只运行标准Java程序,main而不是JavaFX应用程序.因此,您可以通常使用属性和绑定,而无需对JavaFX运行时进行额外要求.这意味着您可以在服务器端应用程序中使用JavaFX属性和绑定.

"正确"的做法

好的,所以你可以做到,但这是"正确"的做法吗?

我不认为很多人以这种方式使用JavaFX属性.这样做的一个原因仅仅是因为JavaFX属性非常新.我不认为在模型对象中使用JavaFX属性是"错误的".

注意事项

JavaFX属性不支持Java序列化(我的意思是直接支持Serializable接口).许多服务器端Java技术可能需要模型序列化,并且它们无法序列化任何使用JavaFX属性的对象.

JavaFX属性本身不是容器感知的,并且通过副作用工作(例如,更改属性可能会触发对另一个绑定值的更新),因此请注意这一点,并确保这种处理在您的环境中是可接受的方法.特别要注意的是,在多线程服务器环境中不要产生不必要的竞争条件(JavaFX客户端应用程序通常需要不那么小心,因为JavaFX通常主要作为单线程环境运行).

JavaFX属性和Hibernate/JPA

我不认为将JavaFX属性混合到Hibernate(或JPA)实体类中是一个好主意.我没见过有人那样做过.Hibernate本身并不了解JavaFX属性,并且通常设计用于处理像Strings和ints这样的Java原语,因此我不知道如何将JavaFX属性自动映射到数据库字段.

您可能需要一个设置,它定义您的实体类层次结构和基于JavaFX属性的模型类的并行层次结构,最后是映射两者之间的映射器层.这种架构设置本质上是MVVM模型.模型(M)是您的Hibernate实体类,视图模型(VM)是基于JavaFX属性的模型.

  • 对于它的价值,我[已经看到JavaFX属性与JPA一起使用](http://asipofjava.blogspot.com/2013/05/javafx-properties-in-jpa-entity-classes.html).它工作正常,因为JPA尊重JFX属性扩展的标准JavaBean模式(get/setXXX).但是,由于序列化问题,我不相信它在任何真实场景中都特别有用. (3认同)