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.


[my tweets]  Rss My book: Real World Java EE - Rethinking Best Practices

Kommentare:

An easier way:

class Book < ActiveRecord::Base; end

Done!

Gesendet von Anonymous am July 08, 2008 at 12:54 AM CEST #

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

Gesendet von 213.61.99.230 am July 08, 2008 at 09: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'.

Gesendet von Frank am July 08, 2008 at 09:33 AM CEST #

Frank,

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

adam

Gesendet von Adam Bien am July 08, 2008 at 11:11 AM 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

Gesendet von Adam Bien am July 08, 2008 at 11:17 AM 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

Gesendet von Adam Bien am July 08, 2008 at 11:20 AM 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?

Gesendet von Artur am July 09, 2008 at 09: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

Gesendet von Adam Bien am July 09, 2008 at 12: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.

Gesendet von Artur am July 09, 2008 at 01:37 PM CEST #

good info

Gesendet von Krishna Srinivasan am July 30, 2008 at 11:20 AM CEST #

Senden Sie einen Kommentar:
  • HTML Syntax: Ausgeschaltet
About
My Recent Books
Conferences
CommunityOne East N.Y.C
JavaONE 2008 Interview
Adverts
Search
Links
greenfire.dev.java.net
...the last 150 posts
...the last 10 comments
my.netbeans.org
Visitors
License