This post is simply a summary of a simple proof of concept. It shows how to:
- create a stateless EJB3 bean
- persist an entity using JPA with Hibernate as a JPA provider
- configure JPA to use a datastore defined on Glassfish (uses pre-installed java/__default datastore, which uses pre-installed Derby/JavaDB)
Entity
@Entity public class Book implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) private int id; private String title; private float price; public Book() { super(); } ... }Here, I have annotated the property, rather than the getter (not shown for brevity), since it feels more intuitive to me. I don't know if there is any advantage/difference of one vs the other other than my personal preference. The "@GeneratedValue(...)" annotation for primary key in JPA entity definition is not optional, as I expected. Using just the "@Id" annotation results in the primary key being not set (set to 0).
EJB Bean
The interface:
@Remote public interface BookManager { public abstract int addBook(Book book); public abstract Book find(int bookId); }
And the bean implementation:
@Stateless(name="BookManager", mappedName = "ejb/BookManagerJNDI") @TransactionAttribute(TransactionAttributeType.REQUIRED) public class BookManagerImpl implements BookManager { // Dependency injection of Entity Manager for // the given persistence unit @PersistenceContext(unitName="pu1") EntityManager em; public int addBook(Book book) { // Transitions new instances to managed. On the // next flush or commit, the newly persisted // instances will be inserted into the datastore. em.persist(book); return book.getId(); } @Override public Book find(int bookId) { return em.find(Book.class, bookId); } }
The annotation @Stateless with the mappedName make the bean to get registered with JNDI. The
TransactionAttributeType.REQUIRED tells the container to wrap each method in the class with a transaction.
JPA SetupThe persistence.xml file (put it into META-INF folder under src folder so it will be deployed onto the server)
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> <persistence-unit name="pu1"> <!-- Persistence provider --> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>jdbc/__default</jta-data-source> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect" /> <property name="hibernate.hbm2ddl.auto" value="create" /> <property name="hibernate.show_sql" value="true" /> </properties> </persistence-unit> </persistence>
The "hibernate." prefix in persistence.xml file is not optional when adding properties of the JPA provider (Hibernate in this case). They are ignored without it, without a warning.
Glassfish Setup
Nothing other than installing the Hibernate component using the Glassfish console.
Unit Tests
The unit test:
try { InitialContext ctx = new InitialContext(); BookManager bean = (BookManager) ctx.lookup("ejb/BookManagerJNDI"); Book book = new Book("Chocolate Rain", 25.10f); int bookId = bean.addBook(book ); book = null; book = bean.find(bookId); Assert.assertEquals("Chocolate Rain", book.getTitle()); } catch (NamingException e) { // TODO Auto-generated catch block e.printStackTrace(); Assert.fail("Failed. Exception thrown."); }
A Few Notes
- Can JPA be used to create and index? Yes and no. Not in general. But it provides a limited capability. To create a unique constrain on a table, use @UniqueConstraint(columnNames={"EMP_BDAY", "EMP_NAME"})
- How to specify the character column type length? Use @Column(length=50).
- What the client can understand about the remote exception, in case the EJB bean fails? The remote exception is wrapped in a EJBException and returned to the client. For example, if the password for the DB is incorrect, the org.hibernate.exception.GenericJDBCException will be returned with a message "Cannot open connection" (when Hibernate is used as JPA provider).
A few things to try in the next proof of concept:
- test the rollback function, if second of two persistence operations failed when both are in the same method of the BookManager class.
- do a parent/child relationship.
1 comment:
thanks for this good post
Post a Comment