If I use a facade class with generic methods to access the JPA API, how should I provide additional processing for specific types?

StackOverflow https://stackoverflow.com/questions/11218883

Question

Let's say I'm making a fairly simple web application using JAVA EE specs (I've heard this is possible). In this app, I only have about 10 domain/data objects, and these are represented by JPA Entities. Architecturally, I would consider the JPA API to perform the role of a DAO. Of course, I don't want to use the EntityManager directly in my UI (JSF) and I need to manage transactions, so I delegate these tasks to the so-called service layer.

More specifically, I would like to be able to handle these tasks in a single DataService class (often also called CrudService) with generic methods. See this article by Adam Bien for an example interface: http://www.adam-bien.com/roller/abien/entry/generic_crud_service_aka_dao

My project differs from that article in that I can't use EJBs, so my service classes are essentially just named beans and I handle transactions manually. Regardless, what I want is a single interface for simple CRUD operations on my data objects because having a different class for each data type would lead to a lot of duplicate and/or unnecessary code.

Ideally, my views would be able to use a method such as

public <T> List<T> findAll(Class<T> type) { ... }

to retrieve data. Using JSF, it might look something like this:

<h:dataTable value="#{dataService.findAll(data.class)}" var="d">
  ...
</h:dataTable>

Similarly, after validating forms, my controller could submit the data with a method such as:

public <T> void add(T entity) { ... }

Granted, you'd probably actually want to return something useful to the caller.

In any case, this works well if your data can be treated as homogenous in this manner. Alas, it breaks down when you need to perform additional processing on certain objects before passing them on to JPA.

For example, let's say I'm dealing with Books and Authors which have a many-to-many relationship. Each Book has a set of IDs referring to its authors, and each Author has a set of IDs referring to their books. Normally, JPA can manage this kind of relationship for you, but in some cases it can't (for example, the google app engine JPA provider doesn't support this). Thus, when I persist a new book for example, I may need to update the corresponding author entities.

My question, then, is if there's an elegant way to handle this or if I should reconsider the sanity of my whole design. Here's a couple ways I see of dealing with it:

  1. The instanceof operator. I could use this to target certain classes when special processing is needed. Perhaps maintainability suffers and it isn't beautiful code, but if there's only 10 or so domain objects it can't be all that bad... could it?

  2. Make a different service for each entity type (ie, BookService and AuthorService). All services would inherit from a generic DataService base class and override methods if special processing is needed. At this point, you could probably also just call them DAOs instead.

As always, I appreciate the help. Let me know if any clarifications are needed, as I left out many smaller details.

Was it helpful?

Solution

The service layer is mainly justified by the need for transactions, and by the need of specific business logic for every use-case. Making it generic doesn't make much sense, IMHO. And having a service per entity doesn't make much sense either, still IMHO: some entities are tightly linked together, and can't just be created or updated independently by a service. And most of the services involve several entities.

The service layer, as its name indicates, is there to provide services to the above layer (the presentation layer). So it should not have some generic interface disconnected from the reality of what the application needs to do. It should provide the services that the UI layer needs. I find it much more logical to split the services based on use-cases or groups of related use-cases rather than entities. And I also find it more logical to start implementing the UI layer, see what services it needs, and implement those services, rather than designing generic services, then start implementing the UI layer, and fall in one of those commonly seen traps:

  • a whole lot of services don't have any use and are implemented but never used
  • the UI layer start calling N low-lever services for each button click, forgets about transactional integrity, and contains the logic that should be in the service layer.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top