DAO's as EJB's. You are doing it wrong...

You will realise that there are tutorials on the web that shows, by example, the implementation of DAO's using the modern Java EE (please, it's no more J2EE) technologies (annotations and CDI). What I find strange, however, is that many of these DAO examples/tutorials are designed to be EJB's as well (particularly Stateless Session Beans). Even Apache, themselves, have a documentation that clearly makes a DAO as an EJB on their TomEE site.

This form of adaptation has crept, also, in business production applications that runs today (shocking, I know and it is still a practice done today by senior developers and architects). There is no separation between the (business) logic tier and the data tier (if you are creating a system using a multi-tier architecture). From my experience, developers do understand how to create DAO's and EJB's from examples that exists on the web, copy-paste the idea from the example and adapt it to their application requirement. As I said on my older post, many do not understand what the EJB container is, what it does and how it manages session beans (do you blame them?)

If you are creating a multi-tier system, you will realize that each tier is maintained as an independent module. This means each module is not dependent on other modules. The advantage of this is that each module can be created and/or deployed on/for different platforms and if each module is designed by contract, communication between each platform can occur between interfaces.

These are my reasons to why I discourage DAO's as EJB's: 
  • EJB's were designed to encapsulate business logic, DAO's were designed to encapsulate data to its persistence layer. I have read arguments that EntityManager is DAO pattern itself. Granted, DAO has been designed to form an ORM approach, the only different between DAO and EntityManager is that EntityManager exposes mechanism to make calls to the persistence layer, (e.g., a Getting a SQL Connection from EntityManager or creating native query by calling EntityManager.createNativeQuery(String sqlQuery);). DAO was designed to encapsulate this mechanism. The EJB should never know where the data is stored and how it is managed, as long as it can request manipulate and pass the data to the DAO to be stored, it's happy.
  • High coupling: The business logic and data persistence are so dependent on one another that a change on the business logic might/will affect the way data is persisted and vice-versa. High coupling classes/modules are bad classes/modules as an independent change to a class/module is not possible without affecting the other dependent classes/modules.
There are various more reasons but I believe you are smart enough to figure it out (please leave your comment below and state whether you agree and disagree to my statement). 

If I (strongly?) disagree on blending DAO's as EJB's, what is my recommended approach? Simple, create a data tier (such as DAO's) and Inject it, thanks to CDI (Contexts and Dependency Injection).

Injecting DAO's

Injecting DAO's is an alternative approach of requesting entity DAO's. For one, you can eliminate DAOFactory completely. 

Here are the steps to achieve DAO injection: 
  • First create a generic DAO interface and relevant subclasses that is tied to a persistence strategy (e.g. JDBCDAO for JDBC DAO, HibernateDAO for using Hibernate Session strategy, JPADAO for using EntityManager as persistence strategy).
  • For each entity, create a DAO entity interface that will provide methods that only return the entity requested. E.g., a CustomerDAO will only return a Customer entity.
  • You can used the @Named qualifier to specify the implementation of the DAO and finally injecting by the named qualifier.
  • An alternative approach that I took is to create 3 types of qualifiers: @HibernateDAO (used for DAO's that uses Hibernate Session), @JPADAO (for JPA persistence) and @JDBCDAO (for JDBC Connection).
It's easy to write a blog, but it's better showing an example (which works):

The DAO interface:


The DAO Implementation:


Note: The class is annotated with @JPADAO. This is the qualifier annotation that we specify for interface injection.

To create a custom CDI qualifier, create a custom annotation and annotate it with @Qualifier. Alternatively, if you're using Eclipse IDE (Eclipse Kepler and newer), you select the option to create a custom qualifier.

Here is the custom @JPADAO (see that it has the @Qualifier annotation, making it a CDI qualifier).



The BaseJPADAO is the DAO class that returns the EntityManager, contained from the persistence unit.


Finally, inject!!!


On my CustomerServiceEJB, I inject the DAO by interface and specifying which type of DAO I want.

And it's this simple. This runs wonderfully on my environment (Java EE 7 with Widfly 8.x). The EJB has no clue of the persistence mechanism of how the entities are stored, nor does it need to care. Since this was coded using a design by contract approach, changes to my DAO's won't affect the EJB at all, unless the interface changes and breaks the contract.

I hope this helps those who are designing a system with a multi-tier architecture.

Comments

  1. @EliteGentleman: This post is simply fantastic. I agree with you, not only is the DAO not dead, it a complex environment where multiple persistence mechanisms are being used it is absolutely essential.

    Absolutely loved the use of custom annotations and CDI. Kudos, Do you mind if I add this post in a link if and when I write about this ?

    ReplyDelete
    Replies
    1. Hi Siddesh, absolutely. You are welcome to post this as a link to your blog (I pressume).

      Delete
  2. Also, just for completeness, please add the beans.xml here and maybe a little description of what purpose it serves will do. Then this post will be novice ready.

    Thanks.

    ReplyDelete
    Replies
    1. The beans.xml is an empty beans.xml. The CDI container will then scan for all classes that can be "injectable" and register it in the BeanManager and make it CDI compliant.

      Delete
  3. I have some problems to do an nested injection of the same object, imagine i have the object A who summon the dao and build an object that summon the same dao but in the children object the injected object is null any solution?

    ReplyDelete
    Replies
    1. I would suggest that the EJB does that. Think of it as a business delegation. If you want an info from another repository based on an entity returned by a DAO, you can simply inject all the relevant DAOs (with their specific repository) and retrieve the entity from there. In essence, you can have a business logic that gets data through JPA, MongoDB, Restful call, etc., and the business logic isn't aware of it. All it knows is that it has reference to a DAO for those entities.

      Delete
  4. I have some issue in this kind of implementation. Although I agree with what you are saying globally, but I have a problem on how you have dsigned your DAOs. By qualifying one implementation (for JPA) with @JPADAO and using that in your service EJB, what you are effectively doing is binding the service layer to use the JPA implementation. If I want to switch my implementtaion from JPA to say plain JDBC sql or native hibernate, I would need to modify my service layer and that goes against the principle of decoupling.

    ReplyDelete
  5. I must have arrived too late; the code samples are not displayed at all.

    ReplyDelete
    Replies
    1. The code can be viewed by removing form parameters from the URL. I don't know why Blogger does this though.

      Delete
  6. I'm new to this topic, but as far as I understood it, when you implement a JPA based DAO using EJB has all the advantages that an EJB container is providing you such as transaction management, thread safty and so on, thus saving me as a developer a lot of plumbing. EJB is just a technology and not a design pattern. Using EJB one can implement different design patterns, one of them being DAO. Just have to apply it on the right place.

    ReplyDelete
    Replies
    1. Fair enough. What I do nowadays is not have annotations such as @JPADAO, @HibernateDAO, etc. Instead, I use what CDI already has, which is using alternatives. That way, I can just add the implementation of the DAO and on my beans.xml I specify the default Alternative, or even annotate it.

      Delete

Post a Comment