在模型类中使用javafx.beans属性 [英] Using javafx.beans properties in model classes

查看:114
本文介绍了在模型类中使用javafx.beans属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我想知道在模型类中使用属​​性是否是一个好习惯使它们与视图组件更容易绑定。我不担心未来这些库的可用性,因为我的程序将在JRE8或更高版本上运行,但在模型类中使用JavaFX库的本质使我感到怀疑,并且我特别担心当前和未来的不兼容问题,因为我希望使用Hibernate来保持这些属性。



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

解决方案

我会在这里提出一些不同意见。

JavaFX属性和JPA



当我评论jewelsea的答案时,只要您使用属性访问而不是字段访问,使用JPA的JavaFX基于属性的Bean也是可能的。我链接的博文在这方面更详细,但基本的想法是任何注释应该在 get ...()方法上,而不是在字段上。据我所知,这确实阻止了与JPA结合使用任何只读JavaFX属性模式,但我从来没有真正感觉到JPA在只读属性(即获取方法和无set方法)方面表现良好。

序列化

与我对jewelsea的回答的评论相反, (我已经被放置在一个位置上,在这个位置上我正在使用JavaFX属性在JavaFX客户端复制几个实体类),我认为可以解决JavaFX属性缺乏序列化的问题。关键的观察是,你真的只需要序列化属性的包装状态(不是,例如,任何监听器)。你可以通过执行 java.io.Externalizable 来实现。 Externalizable Serializable 的子接口,它要求您填写 readExternal(。 ..) writeExternal(...)方法。这些方法可以被实现为只将属性包装的状态而不是属性本身。这意味着如果您的实体被序列化然后反序列化,您将最终得到一个新的属性实例,并且任何侦听器都不会被保留(即,侦听器实际上成为 transient ) ,但据我所见,这将是任何合理用例所要求的。



我尝试用这种方式定义bean,并且它似乎都很好地工作。另外,我运行了一个小实验,在客户端和一个安静的Web服务之间传输它们,使用Jackson映射器转换为JSON表示并从中转换。由于该映射器只依赖于使用get和set方法,因此这种方法很好。

一些注意事项

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



有关通过JavaFX属性工作的一点在将这些属性(在某种程度上,设计时考虑到单线程模型)转移到潜在的多线程服务器时,可以很好地考虑副作用,并且需要注意。一个很好的经验法则是,如果你使用这种策略,监听器只能在客户端注册(并且记住,无论是通过序列化还是通过JSON表示,这些监听器都是暂时的,以便传输回服务器)。当然,这表明在服务器端使用这些可能是一个糟糕的设计;它成为一种单一实体的便利之间的平衡,即对所有人来说都是一切事物(JavaFX客户端的可观察属性,可持续化和/或远程访问的可序列化,以及JPA的持久映射)与公开功能(如可观察性),它可能不完全适合(在服务器上)。

最后,如果您确实使用JPA注释,那么这些注释会具有运行时保留,这意味着认为)你的JavaFX客户端将需要classpath上的javax.persistence规范)。

下面是这样一个适合所有季节的人实例的示例:

p>

  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;
$ b $ **
*实体的实体实现类:Person
*
* /
@Entity

公共类Person实现Externalizable {


private static final long serialVersionUID = 1L;
$ b 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);

//冗余,但是在这里表示注解必须位于属性访问器上:
@Column(name =name)
public final String getName(){
返回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(){
返回生日;
}

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

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

}


Is it a correct practice to use JavaFX beans properties in the model classes?

I wonder if it is a good practice to use properties in model classes to be able to bind them easier with the view components. I'm not worried about the availability of those libraries in future because my program will be run on JRE8 or later but the nature of using the JavaFX libraries in the model classes make me skeptical and I'm worried about current and future incompabilities specially because I want to use Hibernate to persist those attributes.

Note: I use a pure JavaFX environment and I will never need Swing compability in my application.

解决方案

I'm going to offer something of a dissenting opinion here.

JavaFX Properties and JPA

As I commented on jewelsea's answer, using a JavaFX property-based bean with JPA is possible as long as you use "property access" rather than "field access". The blog post I linked there goes into more detail on this, but the basic idea is that any annotations should be on the get...() methods and not on the fields. As far as I can see, this does prevent use of any of the read-only JavaFX property patterns in conjunction with JPA, but I've never really felt JPA played well with read only properties (i.e. get methods and no set method) anyway.

Serialization

Contrary to my comment on jewelsea's answer, and with the benefit of a few weeks to work with this (and having been placed in a position where I was facing replicating several entity classes on a JavaFX client side using JavaFX properties), I think the lack of serialization of JavaFX properties can be worked around. The key observation is that you really only need to serialize the wrapped state of the property (not, for example, any listeners). You can do this by implementing java.io.Externalizable. Externalizable is a sub-interface of Serializable that requires you to fill in the readExternal(...) and writeExternal(...) methods. These methods can be implemented to externalize just the state wrapped by the property, rather than the property itself. This means that if your entity is serialized and then deserialized, you will end up with a new property instance, and any listeners will not be preserved (i.e. the listeners effectively become transient), but as far as I can see this would be what was wanted in any reasonable use case.

I experimented with beans defined this way and it all seems to work nicely. Additionally, I ran a small experiment in transferring them between the client and a restful web service, using the Jackson mapper to convert to and from a JSON representation. Since the mapper just relies on using the get and set methods, this works just fine.

Some caveats

A couple of points need to be observed. As with any Serialization, it's important to have a no-argument constructor. And of course, all values wrapped by the JavaFX properties must themselves be serializable - again this is the same rule as for any serializable bean.

The point about JavaFX properties working via side-effects is well taken, and care needs to be exercised when moving these properties (which are, to some extent, designed with a single-threaded model in mind) to a potentially multi-threaded server. A good rule of thumb is probably that if you use this strategy, listeners should only be registered on the client side (and remember, those listeners are transient with respect to transfer back to the server, whether by serialization or by JSON representation). Of course, that suggests that using these on the server side then might be a bad design; it becomes a trade-off between the convenience of having a single entity that is "all things to all people" (observable properties for the JavaFX client, serializable for persistence and/or remote access, and with persistent mappings for JPA) versus exposing functionality (e.g. observability) where it might not be fully appropriate (on the server).

Finally, if you do use the JPA annotations, those have runtime retention which implies (I think) that your JavaFX client will need the a javax.persistence specification on the classpath).

Here's an example of such a "man for all seasons" entity:

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());
    }

}

这篇关于在模型类中使用javafx.beans属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆