Skip to content

Instantly share code, notes, and snippets.

@james-d
Created May 11, 2014 01:15
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save james-d/e485ac525c71e20bb453 to your computer and use it in GitHub Desktop.
Save james-d/e485ac525c71e20bb453 to your computer and use it in GitHub Desktop.
Example of JPA entities that use JavaFX properties. These use a "super-lazy" idiom for instantiating the properties, and implement Externalizable to work around the lack of Serialization support in the FX property classes.
package edu.marshall.genomics.lims.entities;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
/**
* Entity implementation class for Entity: Investigator
*
*/
@Entity
@Access(AccessType.PROPERTY)
@Table(name="investigators")
@NamedQuery(name="Investigator.findAll", query="SELECT i from Investigator i")
public class Investigator implements Externalizable {
private static final long serialVersionUID = 1L;
private IntegerProperty id ;
private int _id ;
@Id
@Column(name="inv_id")
@GeneratedValue(strategy=GenerationType.AUTO)
public int getId() {
if (id==null) {
return _id ;
} else {
return id.get();
}
}
public void setId(int id) {
if (this.id==null) {
_id=id ;
} else {
this.id.set(id);
}
}
public IntegerProperty idProperty() {
if (id==null) {
id = new SimpleIntegerProperty(this, "id", _id);
}
return id ;
}
private StringProperty email ;
private String _email ;
@Column(name="email")
public String getEmail() {
if (email == null) {
return _email ;
} else {
return email.get() ;
}
}
public void setEmail(String email) {
if (this.email == null) {
_email = email ;
} else {
this.email.set(email);
}
}
public StringProperty emailProperty() {
if (email == null) {
email = new SimpleStringProperty(this, "email", _email);
}
return email ;
}
private StringProperty firstName ;
private String _firstName ;
@Column(name="firstName")
public String getFirstName() {
if (firstName == null) {
return _firstName ;
} else {
return firstName.get();
}
}
public void setFirstName(String firstName) {
if (this.firstName == null) {
_firstName = firstName ;
} else {
this.firstName.set(firstName);
}
}
public StringProperty firstNameProperty() {
if (firstName == null) {
firstName = new SimpleStringProperty(this, "firstName", _firstName);
}
return firstName ;
}
private StringProperty lastName ;
private String _lastName ;
@Column(name="lastName")
public String getLastName() {
if (lastName == null) {
return _lastName ;
} else {
return lastName.get();
}
}
public void setLastName(String lastName) {
if (this.lastName == null) {
_lastName = lastName ;
} else {
this.lastName.set(lastName);
}
}
public StringProperty lastNameProperty() {
if (lastName == null) {
this.lastName = new SimpleStringProperty(this, "lastName", _lastName);
}
return lastName ;
}
private StringProperty institution ;
private String _institution ;
@Column(name="institution")
public String getInstitution() {
if (institution == null) {
return _institution ;
} else {
return institution.get();
}
}
public void setInstitution(String institution) {
if (this.institution == null) {
_institution = institution ;
} else {
this.institution.set(institution);
}
}
public StringProperty institutionProperty() {
if (institution == null) {
institution = new SimpleStringProperty(this, "institution", _institution);
}
return institution ;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt(getId());
out.writeObject(getFirstName());
out.writeObject(getLastName());
out.writeObject(getEmail());
out.writeObject(getInstitution());
}
@Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
setId(in.readInt());
setFirstName((String) in.readObject());
setLastName((String) in.readObject());
setEmail((String) in.readObject());
setInstitution((String) in.readObject());
}
}
package edu.marshall.genomics.lims.entities;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
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.Access;
import javax.persistence.AccessType;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
/**
* Entity implementation class for Entity: Project
*
*/
@Entity
@Access(AccessType.PROPERTY)
@Table(name="projects")
@NamedQueries(
{
@NamedQuery(name="Project.findAll", query="SELECT p from Project p"),
@NamedQuery(name="Project.byInvestigator", query="SELECT p FROM Project p WHERE p.investigator=:investigator"),
}
)
public class Project implements Externalizable {
private static final long serialVersionUID = 1L;
private IntegerProperty id;
private int _id;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name = "project_id")
public final int getId() {
if (id == null) {
return _id;
} else {
return id.get();
}
}
public final void setId(int id) {
if (this.id == null) {
_id = id;
} else {
this.id.set(id);
}
}
public IntegerProperty idProperty() {
if (id == null) {
id = new SimpleIntegerProperty(this, "id", _id);
}
return id ;
}
private StringProperty title ;
private String _title ;
@Column(name="title")
public final String getTitle() {
if (this.title == null) {
return _title ;
} else {
return title.get();
}
}
public final void setTitle(String title) {
if (this.title == null) {
_title = title ;
} else {
this.title.set(title);
}
}
public StringProperty titleProperty() {
if (title == null) {
title = new SimpleStringProperty(this, "title", _title);
}
return title ;
}
private ObjectProperty<Investigator> investigator ;
private Investigator _investigator ;
@ManyToOne(cascade=CascadeType.MERGE, fetch=FetchType.EAGER)
@JoinColumn(name="investigator", referencedColumnName="inv_id")
public final Investigator getInvestigator() {
if (investigator == null) {
return _investigator ;
} else {
return investigator.get();
}
}
public final void setInvestigator(Investigator investigator) {
if (this.investigator == null) {
_investigator = investigator ;
} else {
this.investigator.set(investigator);
}
}
public ObjectProperty<Investigator> investigatorProperty() {
if (investigator == null) {
investigator = new SimpleObjectProperty<>(this, "investigator", _investigator);
}
return investigator ;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt(getId());
out.writeObject(getTitle());
out.writeObject(getInvestigator());
}
@Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
setId(in.readInt());
setTitle((String)in.readObject());
setInvestigator((Investigator) in.readObject());
}
}
package edu.marshall.genomics.lims.entities;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
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.Access;
import javax.persistence.AccessType;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
/**
* Entity implementation class for Entity: samples
*
*/
@Entity
@Access(AccessType.PROPERTY)
@Table(name = "samples")
@NamedQueries({
@NamedQuery(name = "Sample.findAll", query = "SELECT s FROM Sample s"),
@NamedQuery(name = "Sample.byProject", query = "SELECT s FROM Sample s where s.project=:project") })
public class Sample implements Externalizable {
private static final long serialVersionUID = 1L;
private IntegerProperty id;
private int _id;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public final int getId() {
if (this.id == null) {
return _id;
} else {
return id.get();
}
}
public final void setId(int id) {
if (this.id == null) {
_id = id;
} else {
this.id.set(id);
}
}
public IntegerProperty idProperty() {
if (id == null) {
id = new SimpleIntegerProperty(this, "id", _id);
}
return id;
}
private StringProperty sampleId;
private String _sampleId;
@Column(name = "sampleId")
public final String getSampleId() {
if (sampleId == null) {
return _sampleId;
} else {
return sampleId.get();
}
}
public final void setSampleId(String sampleId) {
if (this.sampleId == null) {
_sampleId = sampleId;
} else {
this.sampleId.set(sampleId);
}
}
public StringProperty sampleIdProperty() {
if (sampleId == null) {
sampleId = new SimpleStringProperty(this, "sampleId", _sampleId);
}
return sampleId;
}
private ObjectProperty<Project> project;
private Project _project;
@JoinColumn(name = "project", referencedColumnName = "project_id")
@ManyToOne(cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
public final Project getProject() {
if (project == null) {
return _project;
} else {
return project.get();
}
}
public final void setProject(Project project) {
if (this.project == null) {
_project = project;
} else {
this.project.set(project);
}
}
public ObjectProperty<Project> projectProperty() {
if (project == null) {
project = new SimpleObjectProperty<>(this, "project", _project);
}
return project;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt(getId());
out.writeObject(getSampleId());
out.writeObject(getProject());
}
@Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
setId(in.readInt());
setSampleId((String) in.readObject());
setProject((Project) in.readObject());
}
}
@Mosouley
Copy link

my data base is updated but not the table after implementation of this methodology for my desktop app.

@alamenai
Copy link

Hi @James_D,but in case of collections (One To Many) ?How we can impement these collections ?

@isaquebezerra
Copy link

Hi @XlintXml, i also some problems to implement this with one to many relashionship, you did something?

@lucornulla
Copy link

To create my database, I've created a domain model that uses JavaFX properties (exclusively) with the JPA @access specified as 'PROPERTY', either implicitly (by annotating the 'get' methods) or explicitly (where absolutely necessary). The strategy is to use the domain model to create the database itself using the javax.persistence.Persistence#generateSchema() method.

This exercise serves - in part - to answer the 'can-jpa-and-javafx-coexist' question addressed in your Investigator app. I didn't follow everything your approach exactly, but did hew to the basic concept. I'm using MySQL for the database/schema and Hibernate's implementation of JPA. The results are:

  • The database builds perfectly. This is not nothing, there are a number of many-to-many relationships that are mapped as two @OneToMany entities linked by an intermediate entity mapped as @manytoone (to the two 'outside' entities).

  • Success is highly dependent on which Hibernate 'hibernate-core' version is used. For a long time I used version 5.2.10. By way of trial and error it appears that ver. 5.2.18 (the last in the 5.2 series) works well. Starting with ver. 5.3.x and upward, however, the build fails for different reasons depending on the version that is used. I tracked down what might have been the problem based on the info in the exception messages to the extent possible, but they don't make any sense especially since ver 5.2..18 works perfectly. Not an issue for you here, but it might be useful for you to know.

I have two questions:

  1. Does the fact that the database builds from the JavaFX-based domain model mean that the model will work in practice, i.e. when data is added/modified/deleted? I'm assuming that is the case, but would be grateful for your input.

  2. The Externalizable interface used in the Investigator app addresses the issues raised by JavaFX not implementing Serializable; JPA apparently requires that the data elements be 'wrapped' in a 'serializable' form in order to read/write to the data base. If that is true, then 'externalizing' the data fields makes sense. But if that's not the reason, then why is it necessary to externalize the data elements since the get/set methods return the same data types (e.g. String, int, etc.) in a JavaFX-based domain model as in a pre-JavaFX model?

Hope my comment and questions are clear, and congrats on the brilliant idea and explanation. JavaFX seems to have become something of a child left out in the cold (at least insofar as Oracle is concerned), and to be honest there are a couple of features that are missing that, in my view, would make a world of difference. But those aside it is still a big step forward, at least on the scale of Swing growing out of AWT. As far as desktop applications are concerned (and here I'm thinking about commercial, business-oriented programs), a database capability using JPA like the one I'm working on now would seem to be essential. Yet the common view seems to be that because JavaFX lacks built-in serialization, it's not appropriate for the database world. What a shame! I hope to exploit that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment