adam bien's blog

EJB 3 Persistence (JPA) For Absolute Beginners - Or Create Read Update Delete (CRUD) in 2 Minutes And Two (library) Jars 📎

If you already invested the three minutes working through the post "EJB 3 (@Session) For Absolute Beginners - 3 Minutes Bootstrap, 5 Steps", you can skip the requirements section.

Requirements:

  1. Installled JDK 1.5 (better 1.6) 
  2. An IDE of your choice e.g. vi, emacs, netbeans 6.1 (SE or EE), Eclipse Genymede (SE or EE)
  3. @Stateless, @Local, @Entity, @Id Annotations in classpath
  4. An Java EE 5 capable application server of your choice. It will work with Glassfish v1+ (better v2), JBoss 4.2+, WLS 10+ and probably Geronimo (not tried yed)

What is to do:

  1. In the IDE you will have to point to a JAR containing the three annotations. If you have the Reference Implementation installed (Glassfish), put just: glassfish\lib\javaee.jar to the classpath. You will need a persistence provider as well. In case of toplink, there is only one jar: (glassfish\lib\toplink-essentials.jar). IDEs with built in EE support have already everything you need. However for the very first time I would prefer to develop "from scratch" an EJB. 
  2. Start with the Entity class. Just create a class and put @Entity tag on it:

    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;

    @Entity
    public class Book{

        @Id
        @GeneratedValue
        private Long id;
        private String title;

        public Book() {
        }

        public Book(String title) {
            this.title = title;
        }
    }

    The @Id @GeneratedValue annotations denote the id field as a primary key. An entity should contain a parameterless constructor as well.

  3. Setup a DataSource at the application. jdbc/sample already exists in every fresh Glassfish installation (so nothing to do here).
  4. Create an interface with CRUD methods:
    import javax.ejb.Local;

    @Local
    public interface BookService {
        Book createOrUpdate(Book book);
        void remove(Book book);
        Book find(Object id);
    }
  5. Create a class which implements this interface. You will be forced by a good IDE (probly not by vi or emacs) to implement this interface:
    @Stateless
    public class BookServiceBean implements BookService {
        @PersistenceContext
        private EntityManager em;

        public Book createOrUpdate(Book book) {
            return em.merge(book);
        }
        public void remove(Book book) {
            em.remove(em.merge(book));
        }
        public Book find(Object id) {
            return em.find(com.abien.Book.class, id);
        }
    }
    The method merge creates or updates an entity, all other methods should be self-explanatory. Hint: you cannot remove not-attached entities - you have to find them first. This is the "Seek And Destroy" pattern :-).
  6. You have to create a small XML file. However - it will not grow:
      <persistence-unit name="sample" transaction-type="JTA">
        <jta-data-source>jdbc/sample</jta-data-source>
        <properties>
          <property name="toplink.ddl-generation" value="create-tables"/>
        </properties>
      </persistence-unit>
    </persistence>
    There is only one persistence-unit element with the name "sample". EJB 3 Dependency Injection works with the "Convention Over Configuration" principle. This allows us to keep the injection of the EntityManager very lean: if there is only one possibility - you have not to configure it.
  7. Compile everything and JAR (the persistence.xml into META-INF) the output (in Netbeans just "build", in Eclipse "Export -> JAR")
  8. Copy the JAR into the autodeploy folder of WLS 10 (bea10\user_projects\domains\YOUR_DOMAIN\autodeploy), or glassfish\domains\domain1\autodeploy in the case of Glassfish v2, or jboss-4.2.2.GA\server\default\deploy in case of JBoss
  9. Inspect the log files, you are done :-)

What you have gained:

  1. It's threadsafe (in multicore environments as well) 
  2. Remoting: you can access the interface remotely
  3. It's transactional - transactions are started for you
  4. It's pooled - you can control the concurrency and prevent "denial of service" attacks.
  5. It's monitored: and EJB have to be visible through JMX. Application servers provide additional monitoring services as well.
  6. Dependency Injection just works - you can inject persistence, other beans, legacy pojos (I will cover this in some upcomings posts)
  7. It's portalble and so vendor-neutral. Deployment to different application servers just works
  8. There is almost NO XML.
  9. Its easily accessible (via DI), from Restful services, JSF, Servlets etc.
  10. Clustering and security are beneficial as well - but not the main reason to use EJBs
  11. EntityManager is injected in thread-save manner.
  12. Transactions are managed for you - the EntityManager participates in the transactions (no additional setup etc. necessary)

You know any other framework with less lines of code / configuration effort? :-)

However typing CRUD stuff is boring and 2-3 minutes still too long. Netbeans comes with a nice wizzard which generates the Session Bean for you (then the whole exercise can be performed in about 30 seconds...), and you could think about implementing a generic CRUD-service as well.