Adam Bien's Weblog

Monday Jul 07, 2008

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.


NEW: Java EE 7 Testing and Quality Workshop

A book about rethinking Java EE Patterns

Comments:

An easier way:

class Book < ActiveRecord::Base; end

Done!

Posted by Anonymous on July 08, 2008 at 02:54 AM CEST #

top down approach. Very nice.
But what about bottom up. If there is a database already ?

Posted by 213.61.99.230 on July 08, 2008 at 11:04 AM CEST #

I was contemplating for a while about what 'Configuration over Configuration' might mean, until I figured out that it most likely should be 'Convention over Configuration'.

Posted by Frank on July 08, 2008 at 11:33 AM CEST #

Frank,

absolutely: "Convention Over Configuration" or "Configuration By Exception" -> thank you for the hint. I fixed that,

adam

Posted by Adam Bien on July 08, 2008 at 01:11 PM CEST #

Hi 213.61.99.230,

in Netbeans 6.1: right click: New -> "Entity Classes From Database". It works really well,

thank you for the comment!,

adam

Posted by Adam Bien on July 08, 2008 at 01:17 PM CEST #

Anonymous,

Active Record is not comparable to JPA. However, it is similar to RowSets. Then you can just drag a DataSource to a JSF-Table - and you are done. So you will have actually no code. So Rails seems to be somehow verbose :-).

regards,

adam

Posted by Adam Bien on July 08, 2008 at 01:20 PM CEST #

Hi. I don't like the idea that I must create the interface for DAO objects (BookService in your example). Why not just use JPA directly in servlets etc? Is it possible in EJB3?

Posted by Artur on July 09, 2008 at 11:48 AM CEST #

Hi Artur,

1. In EJB 3.1 the interface becomes optional.
2. It hard to use EntityManager in Servlets directly. EntityManager is not threadsafe, see: http://www.adam-bien.com/roller/abien/entry/are_plain_old_webcontainers_still

thank you for your comment!,
adam

Posted by Adam Bien on July 09, 2008 at 02:03 PM CEST #

I see. And what about passing JPA queries in some form from servlets to EJBs? I want to avoid duplicating JPA API by delegating EJB calls to JPA calls. I simply want to use JPA as a regular end-user DAO.

I'm currenlty on a project where DB access is implemented with EJB 3.0 + JPA and I see that developers implementing it often use simple delegation to JPA API. I also don't like methods like getObjectInfos() which gives objects with 'name' and 'id', and that 'id' must be passed to getObject() which fetches the full object. When I use eg. Hibernate there is no problem with using ORM queries by servlets/other clients, so there is no need for duplicating API/get...Infos() methods.

It seems to me that centralized access to DB in EJB3 is not a good idea.

Posted by Artur on July 09, 2008 at 03:37 PM CEST #

good info

Posted by Krishna Srinivasan on July 30, 2008 at 01:20 PM CEST #

"Configuration over configuration" :) There can be no better phrase to explain old J2EE style development.

Posted by Ercan on November 20, 2010 at 01:58 AM CET #

@Ercan,

but is true - in all of my Java EE 5 / 6 projects I didn't used any XML-configuration beside an empty beans.xml and default persistence.xml. Defaults are in most cases good enough - so you don't have to use annotations as well.

thanks!,

adam

Posted by adam-bien.com on November 20, 2010 at 09:16 AM CET #

Working with generic value objects and jpa is also shown by the implementation of the ImixsEntityService EJB. This service ejb is provided by the Imixs Workflow Project. It can be used to store objects independent from a specific Entity Bean. Also queries with JPQL are possible.
See: http://www.imixs.org/jee/examples/entityservice.html

Posted by Ralph on March 05, 2011 at 12:57 AM CET #

good

Posted by 62.189.77.47 on May 23, 2011 at 11:13 AM CEST #

It would be helpful if you had a link to your jar file (Maybe minus all the libs). Hard to follow for EJB newbies since it does not run as is (Missing imports, and does not deploy as stated).

Posted by Jesus on December 06, 2011 at 08:30 PM CET #

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