1

It seems almost trivial to use JPA entities in the presentation layer.

XHTML:

<h:outputText value="#{catalog.item.name}:"/>

Controller:

@SessonScoped
@ManagedBean
class Catalog {
    @EJB
    private Item item = null;
    public Item getItem(){
        ...
    }
    ....
}

Entity JPA:

@Entity
class Item {
    @Id
    private Integer identifier;
    @Column
    private String name;
    //gets and sets
}

Are there any restrictions for medium/large systems? Does it scale? Are there any gotchas?

Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
danilo
  • 7,680
  • 7
  • 43
  • 46
  • In my swing presentation layer I was forced to add hibernate dependencies because some of the mapping classes requires them on client side. So that's a big disadvantage. I am considering adding the DTO layer but I will try it with some annotations on source level so I wouldn't rewrite same attributes twice. – Daniel Jipa Dec 15 '15 at 06:40

3 Answers3

2

JSF and Java EE experts such as Bauke Scholtz and Adam Bien recommend using Entities in the presentation layer as opposed to making some typically useless intermediary object.

I'm going to quote them below, but note that they sometimes use the term "DTO" (Data Transfer Object) to describe the intermediary object that some designs introduce between the Entities and presentation layer.

Adam Bien writes:

On the other hand considering a dedicated DTO layer as an investment, rarely pays off and often lead to over-engineered and bloated architectures. At the beginning the DTOs will be identical to your domain layer - without any impedance mismatch. If you are 'lucky', you will get few differences over the time. Especially with lightweight platforms like Java EE 6, the introduction of a DTO is a bottom-up, rather than top-down approach." ~ How evil are Data Transfer Objects

(Note that the above quoted article also suggests when it is appropriate to use an intermediary object: "It is perfectly valid to introduce a dedicated DTO to adapt an incompatible domain layer...")

Bien's description makes perfect sense to me. Having worked on projects where intermediary objects identical to the Entities are immediately introduced because "it's good design because it has low coupling" has been a huge, comical waste of time. It's possible to waste time converting DTOs to Entities, and it takes good team discipline to make sure developers treat the DTOs and Entities according to some project policy, e.g. on which objects do you perform validations, business logic, etc.

Bauke Scholtz writes:

However, for the average webapplication you don't need DTO's. You're already using JPA entities. You can just go ahead with using them in your JSF bean/view. This question already indicate that you don't need DTOs at all. You are not blocked by some specific business restrictions. You should not then search for design patterns so that you can apply it on your project. You should rather search for real problems in form of overcomplicated/unmaintainable code so that you can ask/find a suitable design pattern for it. ~ How to use DTO in JSF + Spring + Hibernate

Community
  • 1
  • 1
DavidS
  • 5,022
  • 2
  • 28
  • 55
  • Thanks for these quotes. I totally agree with Adam Bien & Bauke Scholtz. I have answered this recently: [Best way to specify fields returned by a service using jax-rs](http://stackoverflow.com/questions/34165948/best-way-to-specify-fields-returned-by-a-service#answer-34166477). I proposed to combine jaxb annotations with jpa ones for domain entities / pojos, and to use them directly in jax-rs resource methods. I use to do this and it saves me a lot of time, boiler plate code and unnecessary complexity (with dto / mappings & tests). – Rémi Bantos Dec 18 '15 at 18:34
1

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

}

Patrick Leitermann
  • 2,144
  • 2
  • 13
  • 13
0

From a technical point of view, nothing stops you from querying your entities in your data layer and allowing them to flow all the way through the business tier and into your presentation layer. In fact, it's a plausible solution for very small scale applications or proofs of concept work.

The problem with that approach is that you now have a tightly coupled relationship between the domain entity classes and your view. Any change to your domain model immediately impacts your views or any view requirement changes could immediately impact your domain model. This tight coupling isn't desirable in any complex application.

Naros
  • 19,928
  • 3
  • 41
  • 71
  • Naros makes an excellent point here but it doesn't have to be that big of application in fact to suffer from tight coupling. You may feel the impact of the coupling even in a small application. Presentation models or intermediary objects between you data layer and your presentation layer make it possible for two views of the same data to be different. Example: building software that needs to present account numbers. In one view you want the users to see the full account number and in another view you want to see the only truncated data. You wouldn't want this data in your data layer. – Chuck Lowery Dec 14 '15 at 03:17
  • Chuck, but if I use an additional step to present these truncated informations? Isn't it more easy than use one more layer? – danilo Dec 22 '15 at 13:16