Tuesday, July 6, 2010

A Generic CRUD Facade For Your @Entity Beans

CRUD (create-read-update-delete) is a repetitive code in
Java EE projects but it can be isolated in a unique class
through the usage of JPA annotations and Generics – a class I call CRUDEntityFacade.
This is not a new pattern and the goal of this blog entry is just to
prepare you to read my next entries about JAXB and JPA together. I am
doing really nice things with Jersey and Glassfish, and before to expose
complicated inventions I decided to register the basics of the
persistence layer (also very nice for my own future reference).

Complete sample projects

The code I am publishing here is just to avoid you to checkout a
full project and to dig to inspect my CRUD strategy. But if you want to
see this technique in action, please be my guest to checkout one of my
open-source projects. The projects are built by Maven and were created
in Eclipse – but you should be able to run it on your preferred IDE
without any problems. Both projects requires minimum Java 6.

  • Example #1: the Footprint project, what
    includes a RESTful service coded with the Jersey framework. Subversion
    checkout:

    svn checkout
    https://footprint.dev.java.net/svn/footprint/trunk footprint –username
    username

  • Example #2: the Cejug-Classifieds
    project, a WSDL first web-service coded with the JAX-WS framework. Subversion
    checkout:

    svn checkout

    https://cejug-classifieds.dev.java.net/svn/cejug-classifieds/trunk

    cejug-classifieds –username username

username is your java.net login, or you can use
guest without password to get a read only copy.

The generic CRUD implemented with generics and JPA annotations

  1. Defining the persistence interface containing the persistence
    operations we want to share between all entities. Note that I
    replicated the runtime exceptions because it is an interface and we
    expect interfaces to be the most document and self-understandable
    artifacts in our project.

    public interface FootprintEntityFacade { 
    T create(T entity) throws EntityExistsException, IllegalStateException,  
     IllegalArgumentException, TransactionRequiredException;   T read(Serializable primaryKey) throws IllegalStateException, 
      IllegalArgumentException;   void update(T entity) throws IllegalStateException,
     IllegalArgumentException, TransactionRequiredException;   void deleteO(T entity) throws IllegalStateException,  
     IllegalArgumentException, TransactionRequiredException,  
     PersistenceException;}

  2. To define a superclass of all entities. This is an important
    step, since we want to use generics we must have a unique type to pass
    in our interface implementation. The mapped superclass is also useful
    to share the ID attribute.

    @MappedSuperclasspublic abstract class AbstractFootprintEntity 
    implements Serializable {
     @Transient public static final long serialVersionUID = 196919661993L;   @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id;   // getters & setters}

  3. Then we need some entities. I will use an example of the
    Footprint entity that represents Events (JUG meetings, courses or conferences).

    @Entitypublic class FpEvent extends AbstractFootprintEntity { 
    @Transient private static final long serialVersionUID = 196919661993L;   @Column(nullable = false) private String name;   @Column(nullable = true) private String website;   @Version private long updatedTime;   // getters & setters}

  4. Now an important step, the realization of our generic CRUD
    interface to our Event Entity. In theory this empty interface is not
    necessary, but my experiments proved that this is the best way to
    go. It opens a chance for the customization of the persistence
    interface and – the main reason – it avoids conflicts between different
    entity instances using a same interface. You will have 1 empty interface
    for each Entity in your project, an oddity I couldn’t rid off – if you
    know how to avoid it, please tell me.

    @Localpublic interface EventFacadeLocal extends FootprintEntityFacade {}

  5. Now we just need to implement the CRUD. A special note about the
    empty constructor, that uses reflection to get the class of the generic
    type – this is the hidden trick that makes the magic possible.

    @Statelesspublic class CRUDEntityFacade 
    implements FootprintEntityFacade {   private transient final Class entityClass;   @SuppressWarnings("unchecked") public CRUDEntityFacade() { 
     entityClass = (Class) ((java.lang.reflect.ParameterizedType) this    .getClass().getGenericSuperclass()).getActualTypeArguments()[0]; }   @PersistenceContext(name = "footprint") protected transient EntityManager manager;   public T create(final T entity) throws EntityExistsException,  
     IllegalStateException, IllegalArgumentException, 
      TransactionRequiredException {  manager.persist(entity);
      manager.flush();  return entity; }   public T read(final Serializable primaryKey) throws IllegalStateException,
       IllegalArgumentException { 
     return manager.find(entityClass, primaryKey); }   public void update(final T entity) throws IllegalStateException, 
      IllegalArgumentException, TransactionRequiredException { 
     manager.merge(entity);  manager.flush(); }   public void delete(final T entity) throws IllegalStateException,
       IllegalArgumentException, TransactionRequiredException,  
     PersistenceException {  manager.remove(entity);  
    manager.flush(); }}

  6. It is done, now we can persist any entity of the type
    AbstractFootprintEntity (remember to create the empty sub-interface for
    each new entity you want to persist). Below you find an example of the
    CRUD usage in a Jersey resource:

    @Path("/event")public class EventResource { 
    @EJB private EventFacadeLocal eventFacade;   @Produces( { MediaType.APPLICATION_XML })
     @Consumes(MediaType.APPLICATION_XML) 
    @POST @Path("/test2") public FpEvent postJAXBElement(FpEvent e) { 
     return eventFacade.create(e); }}

In my next entries I will show you how to use dual annotation
(JAXB + JPA) in order to minimize the impedance mismatch between the
persistence layer and the serialization of element used in the services
endpoints – REST or SOAP.

From http://weblogs.java.net/blog/felipegaucho

No comments:

Post a Comment