« Feedback for Java EE... | Main | First Workshop with... »
 20070926 Wednesday September 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.

Gesendet von admin [Java EE 5 Architectures] ( September 26, 2007 09:21 AM ) Permalink | Kommentare [11]
[my website] [This entry is based on / extends my books: Enterprise Architekturen, Leitfaden fuer effiziente Software-Entwicklung and: Java EE 5 Architekturen, Patterns und Idiome]

Kommentare:

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

Gesendet von dont_repeat_the_dao am September 26, 2007 at 10:20 AM 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.

Gesendet von Markus Junginger am September 26, 2007 at 11:51 AM 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).

Gesendet von Philipp Meier am September 26, 2007 at 04: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

Gesendet von Adam Bien am September 26, 2007 at 07: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

Gesendet von Adam Bien am September 26, 2007 at 07: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

Gesendet von Adam Bien am September 26, 2007 at 07: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

Gesendet von Robert Herschke am September 27, 2007 at 02:24 PM CEST #

Hello all,

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

Regards,

malte.

Gesendet von Malte Schnack am September 27, 2007 at 03: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.

Gesendet von Philipp Meier am September 28, 2007 at 10:50 AM 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.

Gesendet von Sandro Sonntag am October 13, 2007 at 09: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.

Gesendet von Wanja Gayk am May 27, 2008 at 02:42 PM CEST #

Senden Sie einen Kommentar:

Name:
E-Mail:
URL:

Ihr Kommentar:

HTML Syntax: Ausgeschaltet



License
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 2.0 License.