Felipe Gaúcho works as senior software engineer at Netcetera AG in Switzerland. He is a well known Brazilian JUG leader and open-source evangelist. Felipe works with Java since its early versions and has plans to keep that Java tradition as it is. When he is not coding, he prefers to listen reggae and travel around with his lovely wife Alena and his son Rodrigo. Felipe is a DZone MVB and is not an employee of DZone and has posted 29 posts at DZone. View Full User Profile

A Generic CRUD Facade For Your @Entity Beans

04.20.2009
| 10299 views |
  • submit to reddit

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.

    @MappedSuperclass
    public 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).

    @Entity
    public 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.

    @Local
    public interface EventFacadeLocal extends FootprintEntityFacade<FpEvent> {
    }

     

     

  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.

    @Stateless
    public class CRUDEntityFacade<T extends AbstractFootprintEntity> implements FootprintEntityFacade<T> {

    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

Published at DZone with permission of Felipe Gaúcho, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Kode Ninja replied on Tue, 2009/04/21 - 6:55am

Felipe, couple of points here:
  1. Your code for "update()" should really first do a "find()" to ensure that the entity being updated really exists. Otherwise "merge" just goes ahead and creates the entity, something that you may not want.
  2. get() calls EntityManager.find(), which by default would first check from the 2nd level cache of the JPA vendor to check if the entity is already there. If found, it would simply return it, as part of the persistence context being used. Now, your back-end may get updated by other code (JPA/non-JPA). This could result in stale data getting returned. So, you should call EntityManager.refresh() after a call to find(). The same applies to update() and delete() also.

Just my 2 cents.
-kodeninja

Felipe Gaúcho replied on Tue, 2009/04/21 - 8:27am

Thank you very much kodeninja, I will review my code here... a reference to this tip: http://weblogs.java.net/blog/guruwons/archive/2006/09/understanding_t.html

EG replied on Wed, 2009/04/29 - 11:37pm

I believe this an interesting idea (generic CRUD). You may want to a look at the Jt Pattern Oriented Framework. It features a complete CRUD implementations based on the DAO design pattern:

 

http://freedom.lunarpages.com/Jt/

 

Regards,

Dave 

 

 

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.