Usando javafx.propiedades de los frijoles en las clases modelo


¿Es una práctica correcta usar las propiedades de JavaFX beans en las clases modelo?

Me pregunto si es una buena práctica usar propiedades en clases de modelos para poder enlazarlas más fácilmente con los componentes de la vista. No me preocupa la disponibilidad de esas bibliotecas en el futuro porque mi programa se ejecutará en JRE8 o posterior, pero la naturaleza de usar las bibliotecas JavaFX en las clases modelo me hace escéptico y me preocupan las incompabilidades actuales y futuras, especialmente porque Quiero usar Hibernar para persistir esos atributos.

Nota: Utilizo un entorno JavaFX puro y nunca necesitaré compatibilidad con Swing en mi aplicación.

Author: Francesco Menzani, 2014-04-21

3 answers

Voy a ofrecer algo de una opinión disidente aquí.

Propiedades JavaFX y JPA

Como comenté en la respuesta de jewelsea, usar un bean basado en propiedades JavaFX con JPA es posible siempre y cuando uses "acceso a propiedades" en lugar de "acceso a campos". La entrada del blog que enlacé allí entra en más detalles sobre esto, pero la idea básica es que cualquier anotación debe estar en los métodos get...() y no en los campos. Por lo que puedo ver, esto evita el uso de cualquiera de los patrones de propiedad JavaFX de solo lectura en conjunto con JPA, pero nunca me he sentido realmente JPA jugó bien con propiedades de solo lectura (es decir, métodos get y ningún método set) de todos modos.

Serialización

Contrariamente a mi comentario sobre la respuesta de jewelsea, y con el beneficio de unas pocas semanas para trabajar con esto (y habiendo sido colocado en una posición donde me enfrentaba a replicar varias clases de entidades en un lado del cliente JavaFX usando propiedades JavaFX), creo que la falta de la serialización de las propiedades de JavaFX se puede solucionar. La observación clave es que realmente solo necesita serializar el estado envuelto de la propiedad (no, por ejemplo, ningún oyente). Puede hacer esto implementando java.io.Externalizable. Externalizable es una sub-interfaz de Serializable que requiere que rellenes los métodos readExternal(...) y writeExternal(...). Estos métodos se pueden implementar para externalizar solo el estado envuelto por la propiedad, en lugar de la propiedad en sí. Esto significa que si su entidad está serializada y luego deserializado, terminará con una nueva instancia de propiedad, y cualquier oyente no se conservará (es decir, los oyentes efectivamente se convierten en transient), pero por lo que puedo ver esto sería lo que se quería en cualquier caso de uso razonable.

Experimenté con frijoles definidos de esta manera y todo parece funcionar bien. Además, ejecuté un pequeño experimento para transferirlos entre el cliente y un servicio web restful, utilizando el Jackson mapper para convertir hacia y desde una representación JSON. Ya el mapeador solo se basa en el uso de los métodos get y set, esto funciona bien.

Algunas advertencias

Es necesario observar un par de puntos. Como con cualquier serialización, es importante tener un constructor sin argumento. Y, por supuesto, todos los valores envueltos por las propiedades JavaFX deben ser serializables, de nuevo esta es la misma regla que para cualquier bean serializable.

El punto sobre las propiedades de JavaFX que funcionan a través de los efectos secundarios está bien tomado, y hay que tener cuidado para se ejercerá al mover estas propiedades (que, en cierta medida, están diseñadas con un modelo de subproceso único en mente) a un servidor potencialmente multiproceso. Una buena regla general es probablemente que si utiliza esta estrategia, los oyentes solo deben registrarse en el lado del cliente (y recuerde, esos oyentes son transitorios con respecto a la transferencia de nuevo al servidor, ya sea por serialización o por representación JSON). Por supuesto, que sugiere que el uso de estos en el lado del servidor entonces podría ser un mal diseño; se convierte en una compensación entre la conveniencia de tener una sola entidad que es "todas las cosas para todas las personas" (propiedades observables para el cliente JavaFX, serializable para persistencia y/o acceso remoto, y con asignaciones persistentes para JPA) versus exponer la funcionalidad (por ejemplo, observabilidad) donde podría no ser completamente apropiada (en el servidor).

Finalmente, si usa las anotaciones de JPA, tienen retención de tiempo de ejecución, lo que implica (creo) que su cliente JavaFX necesitará el javax.especificación de persistencia en el classpath).

Aquí hay un ejemplo de tal entidad" hombre para todas las estaciones":

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

}
 18
Author: James_D,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-07 20:35:00

JavaFX Property Design

Las propiedades de JavaFX están diseñadas de tal manera que no es necesario ejecutar un programa JavaFX para usarlas. Las secciones del Tutorial Oracle Using JavaFX Properties and Binding, demuestran dicho uso (por ejemplo, una clase de factura para modelar las propiedades de una factura). El ejemplo del tutorial simplemente ejecuta un programa Java estándar con una main y no una Aplicación JavaFX. Por lo tanto, puede usar propiedades y enlaces genéricamente sin tener un requisito adicional en el tiempo de ejecución de JavaFX. Esto significa que podría, por ejemplo, hacer uso de propiedades y enlaces JavaFX en una aplicación del lado del servidor.

"Prácticas correctas

OK, entonces puedes hacerlo, pero ¿es una práctica "correcta"?

No creo que mucha gente use las propiedades de JavaFX de esta manera. Una razón para esto es simplemente porque las propiedades de JavaFX son bastante nuevas. No creo que sea" incorrecto " usar propiedades JavaFX en el modelo objeto.

Advertencias

Las propiedades JavaFX no admiten la serialización Java (con esto me refiero al soporte directo para la interfaz Serializable). Numerosas tecnologías Java del lado del servidor podrían requerir serialización del modelo y no podrían serializar ningún objeto que hiciera uso de las propiedades JavaFX.

Las propiedades JavaFX en sí mismas no son conscientes del contenedor y funcionan a través de efectos secundarios (por ejemplo, cambiar una propiedad puede desencadenar una actualización a otro valor enlazado), así que tenga en cuenta esto y asegúrese de que este tipo de procesamiento sea un enfoque aceptable en su entorno. En particular, tenga cuidado de no generar condiciones de carrera no deseadas en un entorno de servidor multihilo (las aplicaciones cliente JavaFX generalmente requieren menos cuidado con respecto a esto, ya que JavaFX en general se ejecuta principalmente como un entorno de subproceso único).

Propiedades de JavaFX e Hibernación/JPA

No creo que mezclar propiedades JavaFX en Hibernar (o JPA) entity classes es una buena idea. No he visto a nadie hacer eso. Hibernate en sí no es consciente de las propiedades de JavaFX y, en general, está diseñado para funcionar contra primitivas de Java como Cadenas e ints, por lo que no se cómo podría asignar automáticamente una propiedad JavaFX a un campo de base de datos.

Es probable que necesite una configuración que defina su jerarquía de clases de entidad y una jerarquía paralela para sus clases de modelos basadas en propiedades JavaFX y, finalmente, una capa de mapeador que mapee entre los dos. Este tipo de configuración arquitectónica es esencialmente un modelo MVVM . El modelo (M) es sus clases de entidad de Hibernación, y el modelo de vista (VM) es su modelo basado en propiedades JavaFX.

 8
Author: jewelsea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-20 23:30:37

Para persistir colecciones jpa solo use esta firma para el método getter..

@OneToMany
List<Person> getAll()
{
return observableList;
}
 0
Author: user2768310,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-19 10:41:30