Adam Bien's Weblog

Wednesday Sep 26, 2007

Generic CRUD Components with Java EE 5

The mix of EJB 3, JPA and generics makes it possible to build lean and powerful management components with only few lines of code. Especially reusable CRUD components (e.g. masterdata management) do not have to be coded over and over again. The CRUD methods can be defined in a remote or local interface of a stateless session bean:

public interface CrudService<K,T> {
    public  T create(T t);
    public  T find(K id);
    public void delete(T t);
    public  T update(T t);
   //finders...
}
It is a plain interface without the @Remote annotation (a simple POJI).
The CRUD-logic is realized in a stateless session bean which provides the type of the primary key, as well as of the persistent entity:

@Stateless
@Remote(CrudService.class)
public class CrudServiceBean implements CrudService<Integer,Customer> {
   
    @PersistenceContext
    private EntityManager em;

    public Customer create(Customer t) {
        this.em.persist(t);
        return t;
   //remaining methods
    }

In this particular case, the interface is defined only once and realized by specific EJBs (which have to be implemented and deployed for each JPA-entity)
However a type-unsafe variation can be even more flexible.The usage of the java.io.Serializable (or Object), instead of a generic type allows the deployment of only one EJB, which is able then to manage all JPA-entities.

public interface GenericCrudService {
    public  Serializable create(Serializable t);
    public  Serializable find(Serializable id,Class type);
    public void delete(Serializable t);
    public  Serializable update(Serializable t);
    public Collection<Serializable> findByNamedQuery(String queryName);
    public Collection<Serializable> findByNamedQuery(String queryName,int resultLimit);
}

The implementation of the interface is straightforward:

@Stateless
@Remote(GenericCrudService.class)
public class GenericCrudServiceBean implements GenericCrudService {
  
    @PersistenceContext
    private EntityManager em;

    public Serializable create(Serializable t) {
        this.em.persist(t);
        return t;
    }

    @SuppressWarnings("unchecked")
    public Serializable find(Serializable id, Class type) {
       return (Serializable) this.em.find(type, id);
    }

    public void delete(Serializable t) {
       t = this.em.merge(t);
       this.em.remove(t);
    }

    public Serializable update(Serializable t) {
        return this.em.merge(t);
    }

    public Collection<Serializable> findByNamedQuery(String queryName) {
        return this.em.createNamedQuery(queryName).getResultList();
    }

    public Collection<Serializable> findByNamedQuery(String queryName, int resultLimit) {
        return this.em.createNamedQuery(queryName).setMaxResults(resultLimit).getResultList();
    }
EJB 3 are even efficient enough for the implementation of really simple use cases. This change a lot, comparing it to the J2EE/EJB 2.0 spec.
The whole example is available in p4j5.


NEW: Java EE 7 Testing and Quality Workshop

A book about rethinking Java EE Patterns

Comments:

looks like the same idea as in "Don't repeat the DAO!-Build a generic typesafe DAO with Hibernate and Spring DAO" http://www-128.ibm.com/developerworks/java/library/j-genericdao.html

Posted by dont_repeat_the_dao on September 26, 2007 at 12:20 PM CEST #

Depending on your application, this seemingly obvious step can save you many classes/EJBs. In my last projects, our experience with this approach was quite positive. Of course it’s not always possible to use the generic version, because sometime it is necessary to do some additional work going beyond CRUD. This may be any domain specific logic like checking constraints, calculating field, etc. In this case, you can let the client another (specific) service. There may be nicer solutions to this problem (maybe offering hooks in the generic CRUD service), but it was pragmatic approach we could effectively work with.

Some comments on your CRUD service:

What about a deleteById method, calling em.find, instead of em.merge? I am not sure how intelligent the current JPA implementations are, but it’s possible the merge really triggers an update to the database before the same data gets deleted. An(other) advantage when using remote communication is that the ID may be significantly smaller than the full object, which may be a whole tree of objects.

In a strict sense, passing named query Strings exposes implementation specific details. Nevertheless, I like this idea for its pragmatism. I would let it return List instead of Collection though. The Query returns a List object itself, and I cannot think of a reason to hide this fact, especially when using ORDER BY.

I would propose two additional finder methods, which could be also offered in a generic way. A findAll method that builds the query strict by a given Class, and findSingleByNamedQuery returning a Serializable object when the result is expected to be unique.

Posted by Markus Junginger on September 26, 2007 at 01:51 PM CEST #

Nice post! I did the same (a little more elaborate) at home. I like the finders for the named queries.

Currently I work on a CRUD / Scaffold swing client framework this will be a perfect match (for those who use swing).

Posted by Philipp Meier on September 26, 2007 at 06:20 PM CEST #

dont_repeat_the_dao,

the IBM article is really interesting. I didn't read this before - it is almost identical. However - now I feel better about this "Pattern",

thanks for the pointer,

adam

Posted by Adam Bien on September 26, 2007 at 09:17 PM CEST #

Markus,

you are absolutely right - but it is just a "clean room" example which I build from scratch to show some ideas. Real World is always slightly more complicated,

thank you very much!,

adam

Posted by Adam Bien on September 26, 2007 at 09:20 PM CEST #

Philipp,

please consider in your framework JSR-296 and JSR-295. I would be really interested in your explorations, I like Swing - it's future is really bright (JavaFX, JSR-295, JSR-296, Consumer JRE and Netbeans RCP):-),

thank you for the nice post,

adam

Posted by Adam Bien on September 26, 2007 at 09:22 PM CEST #

Hello Philipp, Hello Adam,

if it is the question about displaying entities in a generic way in a Swing JTree, then you might have a look at my Generic-Tree idea, posted in my blog at:

http://herschke.de/system-cgi/blog//index.php?itemid=1500

The TreeService interface is very lightweight and returns a set of children-treenodes for a given treenode, that are described in a configuration xml.

With this, you are able to place a tree in your application that you may easy be configured in structure and the kind of data to display.

Contact me, if you need the source or further hints on this.

Regards,
Robert

Posted by Robert Herschke on September 27, 2007 at 04:24 PM CEST #

Hello all,

what about extending this Pattern with Query by Example capabilities? Any experiences in that?

Regards,

malte.

Posted by Malte Schnack on September 27, 2007 at 05:32 PM CEST #

Adam, thank you to remind of of JSR-296 and JSR-295. Altough I don't really like the swing app framework yet, I plan to make my scaffold lib integrate into it as well as I can.

Currently I use JGoodies Binginds from https://jgoodies.dev.java.net/ which is an existent, working and well designed binding library. I don't know why but the discussion about binging seems to forget about JGoodies bindings all the time.

Posted by Philipp Meier on September 28, 2007 at 12:50 PM CEST #

Hi all,

the Article "Einmalige Daos" by Juergen Hoeller in the JavaMag 11.07.
describes a similar concept realized with the Spring Framework. But it has some advantages. It uses typesave finder methods and maps them in a generic way to a NamedQuery. So a dao method "findPersonByName" is mapped to "Person.findPersonByName" NQ. A dynamic proxy realize the generic dao impl. I think it han also applied to JEE 5.

Posted by Sandro Sonntag on October 13, 2007 at 11:23 AM CEST #

If you're using generics, why not go a little step further than that?

public <T extends Serializable> T find(final Serializable id, Class<T> type);

public <T extends Serializable> Collection<T> findByNamedQuery(final String queryName);

That should get rid of a lot of casts.

Posted by Wanja Gayk on May 27, 2008 at 04:42 PM CEST #

Male it simple, It hard to modify....
Philippines, Mabuhay....

Posted by adrian on September 29, 2008 at 09:40 AM CEST #

Hello,

Great posting, just what I was looking for, because I was about to implement a generic Crud Service myself.
However, after some investigation: I found the GenericCrudService is a form of a DAO.
On IBM there's a description: http://www-128.ibm.com/developerworks/java/library/j-genericdao.html

Also a very promising implementation that uses Spring I found on: http://code.google.com/p/krank/wiki/UsingDAO

Posted by Gerbrand van Dieijen on December 09, 2008 at 03:21 PM CET #

Hello,

I have some questions about GenericCrudServiceBean....

Where is the right place to put this bean? Should it be in some utility project/jar on which all others depends?
Or maybe the right approach is to implement CrudService interface in every project?

And what if we must access many persistence units? Not only one.

Thanks,
Miroslav

Posted by 77.105.0.66 on January 30, 2009 at 02:33 PM CET #

Post a Comment:
  • HTML Syntax: NOT allowed
realworldpatterns.com
...the last 150 posts
...the last 10 comments
Links
License