JPA Entities are plain old java objects with decoupled states (DETACHED, MANAGED) and there would be no problem using them in the presentation layer.
In most applications it makes no sence to copy the fields of an JPA entity to an additional presentation object that provides the same state.
You could use JPA entities in combination with interfaces, so that your able to introduce additional transfer objects only if they are really needed and if no existing jpa entity matches the requirements of the target view.
For relations with interfaces the targetType attribute of @OneToMany, @OneToOne or @ManyToOne is needed (e. g. @OneToMany(targetType = SomeJPAEntity.class)).
Here is some example code for the Items entity used in both the persistence and the presentation layer of a Java FX application:
// Service definition for obtaining IItem objects.
public interface IItemService {
IItem getItemById(Integer id);
IItemWithAdditionalState getItemWithAdditionalStateById(Integer id);
}
// Definition of the item.
public interface IItem {
StringProperty nameProperty();
ObservableList subItems();
List getSubItems();
}
// Definition for the item with additional state.
public interface IItemWithAdditionalState extends IItem {
String getAdditionalState();
}
// Represents a sub item used in both the persistence and the presentation layer.
@Table(name = SubItem.TABLE_NAME)
@Entity
public class SubItem extends AbstractEntity implements ISubItem, Serializable {
public static final String TABLE_NAME = "SUB_ITEM";
}
// Represents an item used in both the persistence and the presentation layer.
@Access(AccessType.PROPERTY)
@Table(name = Item.TABLE_NAME)
@Entity
public class Item extends AbstractEntity implements IItem, Serializable {
public static final String TABLE_NAME = "ITEM";
private StringProperty nameProperty;
private String _name; // Shadow field for lazy loading of java fx properties.
private ObservableList<ISubItem> subItems = FXCollections.observableArrayList();
public StringProperty nameProperty() {
if (null == nameProperty) {
nameProperty = new SimpleStringProperty(this, "name");
}
return nameProperty;
}
public String getName() {
return null == nameProperty ? _name : nameProperty.get();
}
public void setName(String name) {
if (null == nameProperty) {
_name = name;
} else {
_name = null;
nameProperty.set(name);
}
}
@Override
public ObservableList<ISubItem> subItems() {
return subItems;
}
@JoinColumn(name = "ID")
@OneToMany(targetEntity = SubItem.class)
@Override
public List<ISubItem> getSubItems() {
return subItems;
}
public void setSubItems(List<ISubItem> subItems) {
this.subItems.setAll(subItems)
}
}
// New added presentation data transfer object for matching the requirements of a special view.
public class ItemWithAdditionalState extends Item implements IItemWithAdditionalState {
String getAdditionalState();
}