Saturday, July 10, 2010

Using JPA and Hibernate

So yes. Hibernate is one of the most important actors in JPA specification. Emmanuel Bernard from JBoss presented some new things on Hibernate especially its relationship to JPA on SophiaConf last Friday.  As he said in his tweeter, if you were not there, you've wasted your time. I was there, so I didn't waste my time :-)


OK. That's one thing. Now, let's see how things work with JPA and Hibernate. First, you will need at least 3.5.0 version of Hibernate Entity Manager. The POM looks like the following:


<dependencies>
  ...
   <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>3.5.1-Final</version>
        <scope>compile</scope>
    </dependency>   
 </dependencies>


You may need to define the repository:
 <repositories>
   <repository> 
       <id>hibernate</id>
   <url>https://repository.jboss.org/nexus/content/groups/public</url>
   </repository>
  </repositories>   


OK. 


And, here is my boring Flight class:


package com.arizal.flight;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;


@Entity
public class Flight {
  private String number;
  private String airline;


  @ManyToOne
  @JoinColumn(name="DEPARTURE")
  private Airport departure;


  @ManyToOne
  @JoinColumn(name="ARRIVAL")
  private Airport arrival;

  @Id private int id;
...
}
And Airport:

@Entity
public class Airport {
  @Id private String code;
  private String name;

  public void setCode(String code) {
    this.code = code;
  }

  public String getCode() {
    return code;
  }


  public void setName(String name) {
    this.name = name;
  }


  public String getName() {
    return name;
  }
}

Then, put the HSQL DB in runtime dependency:
   <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>3.5.1-Final</version>
        <scope>compile</scope>
    </dependency>


This should be enough for us to write the code to persist flight, for example the following:


public static void main(String args[]) {
    try {
      Flight flight = new Flight();
      flight.setId(0);
      flight.setArrival(createAirport("SYD","Sydney"));
      flight.setDeparture(createAirport("MEL""Melbourne"));
      flight.setNumber("123");
      flight.setAirline("QF");

      EntityManagerFactory emf = 
        Persistence.createEntityManagerFactory("jpa");
      EntityManager em = emf.createEntityManager();

      em.getTransaction().begin();
      em.persist(flight);
      em.getTransaction().commit();
    }
    catch (Exception ex) {
      ex.printStackTrace();
    }
  }
I ran the code, but got this error:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/impl/StaticLoggerBinder
at org.slf4j.LoggerFactory.getSingleton(LoggerFactory.java:223)
at org.slf4j.LoggerFactory.bind(LoggerFactory.java:120)
at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:111)
at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:269)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:242)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:255)


Not very cool.  OK, I miss something on slf4j. Add it to the pom.xml as follow solves the problem:
  <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.5.6</version>
        <scope>runtime</scope>
    </dependency>
  
Yes. Now it works.


O, yes. I forgot to tell something. The persistence.xml accepts the JPA properties:

<persistence-unit name="jpa" >  
   <provider>org.hibernate.ejb.HibernatePersistence</provider>  
   <class>com.arizal.flight.Flight</class>
   <class>com.arizal.flight.Airport</class>
   <properties>
            <property name="javax.persistence.jdbc.driver
                      value="org.hsqldb.jdbcDriver"/>
            <property name="javax.persistence.jdbc.url
                      value="jdbc:hsqldb:hsql://localhost/xdb"/>
            <property name="javax.persistence.jdbc.user" value="SA"/>
            <property name="javax.persistence.jdbc.password" value=""/>
             <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
        </properties>
    </persistence-unit>

It was not the case in older version of hibernate entity manager that requires the following properties instead:
    <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver" />
    <property name="hibernate.connection.url" value="jdbc:hsqldb:hsql://localhost/xdb" />
    <property name="hibernate.connection.username" value="sa" />
    <property name="hibernate.connection.password" value="" />

Pretty cool, isn't it ?

No comments: