Using Eclipse with Google plugin:
- to run application locally: Google->Compile GWT (red toolbox toolbar icon) and run as Run As->Web Application
JpaDao { public void persist(E entity) { if (entity.getId() == null) { entityManager.persist(entity); } else { entityManager.merge(entity); } } }as suggested by Marcell Manfrin (in a comment).
@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).
@Remote public interface BookManager { public abstract int addBook(Book book); public abstract Book find(int bookId); }
@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); } }
TransactionAttributeType.REQUIRED tells the container to wrap each method in the class with a transaction.
JPA Setup<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>
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."); }
Session session = factory.openSession(); Transaction tx = null; try { tx = session.beginTransaction(); // Do some work session.load(...); session.persist(...); tx.commit(); // Flush happens automatically } catch (RuntimeException e) { tx.rollback(); throw e; // or display error message } finally { session.close(); }You choose the approach.
UserTransaction tx = (UserTransaction)new InitialContext() .lookup("java:comp/UserTransaction"); SessionFactory factory = HibernateUtil.getSessionFactory(); PersonDao dao = new PersonDao(factory); try{ tx.begin(); dao.saveOrUpdate(person); tx.commit(); } catch( Exception ex) { tx.rollback(); }while the only thing that the Dao needs to do is to request the session via: factory.getCurrentSession().
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory name="hibernate/sessionFactory"> <property name="transaction.manager_lookup_class">org.hibernate.transaction.SunONETransactionManagerLookup</property> <property name="transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property> <property name="connection.datasource">jdbc/xaderby</property> <property name="dialect">org.hibernate.dialect.DerbyDialect</property> <property name="current_session_context_class">jta</property> <property name="hbm2ddl.auto">create</property> <mapping resource="olcc/entity/Person.hbm.xml"/> </session-factory> </hibernate-configuration>where jdbc/xaderby is a data source defined on Glassfish, of type javax.sql.XADataSource.
FINEST: saving transient instance FINE: surrounding JTA transaction suspended [JavaEETransactionImpl: txId=1 nonXAResource=null jtsTx=null localTxStatus=0 syncs=[org.hibernate.transaction.CacheSynchronization, org.hibernate.context.JTASessionContext$CleanupSynch@1d069e4]] FINE: opening JDBC connection INFO: JTS5014: Recoverable JTS instance, serverId = [100] FINE: select next_hi from hibernate_unique_key for read only with rs FINE: update hibernate_unique_key set next_hi = ? where next_hi = ? FINE: closing JDBC connection (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0) SEVERE: org.hibernate.HibernateException: unable to resume previously suspended transaction at org.hibernate.engine.transaction.Isolater$JtaDelegate.delegateWork(Isolater.java:179) at org.hibernate.engine.transaction.Isolater.doIsolatedWork(Isolater.java:64) at org.hibernate.engine.TransactionHelper.doWorkInNewTransaction(TransactionHelper.java:74) at org.hibernate.id.TableGenerator.generate(TableGenerator.java:118) at org.hibernate.id.TableHiLoGenerator.generate(TableHiLoGenerator.java:84) at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:122)When I tried using a plain javax.sql.DataSource instead of XADataSource, I was getting XAResource.start error.
Person result = Client.create().resource("http://localhost:8080/myapp/person") .type("application/json") .post(Person.class,new Person("Jon Smith",133)); Assert.assertEquals("Jon Smith", result.getName());
package olcc.jersey.service; import java.util.List; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response; import olcc.entity.HibernateUtil; import olcc.entity.Person; import olcc.entity.PersonCollection; import org.dozer.DozerBeanMapper; import org.dozer.Mapper; import org.hibernate.Transaction; import org.hibernate.classic.Session; @Path("/person/") public class PersonResource { @GET @Path("{personId}/") @Produces("application/json") public Person getPerson(@PathParam("personId") int personId) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); Transaction tx = null; Person personClean; try{ tx = session.beginTransaction(); Person person = (Person) session.load(Person.class,personId); Mapper mapper = new DozerBeanMapper(); personClean = mapper.map(person,Person.class); session.getTransaction().commit(); } catch( Exception ex) { if( tx != null ) tx.rollback(); throw new WebApplicationException(Response.Status.NOT_FOUND); } return personClean; } @GET @Produces("application/json") public PersonCollection get() { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); List<person> result = session.createQuery("from Person").list(); Mapper mapper = new DozerBeanMapper(); PersonCollection persons = new PersonCollection(); for( Person person : result ) { persons.add(mapper.map(person,Person.class)); } session.getTransaction().commit(); return persons; } @POST @Consumes("application/json") @Produces("application/json") public Person post(Person person) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); session.save(person); session.getTransaction().commit(); return person; } @GET @Path("delete/{personId}/") @Produces("application/json") public Person deleteOne(@PathParam("personId") int personId) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Transaction tx = null; Person personClean; try{ tx = session.beginTransaction(); Person person = (Person) session.load(Person.class,personId); session.delete(person); Mapper mapper = new DozerBeanMapper(); personClean = mapper.map(person,Person.class); session.getTransaction().commit(); } catch( Exception ex) { if( tx != null ) tx.rollback(); throw new WebApplicationException(Response.Status.NOT_FOUND); } return personClean; } }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory name="hibernate/sessionFactory"> <property name="connection.datasource">jdbc/derbydb</property> <property name="dialect">org.hibernate.dialect.DerbyDialect</property> <property name="current_session_context_class">thread</property> <property name="hbm2ddl.auto">create</property> <mapping resource="olcc/entity/Person.hbm.xml"/> </session-factory> </hibernate-configuration>
private static SessionFactory buildSessionFactory() { return new Configuration().configure().buildSessionFactory(); }
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
import org.junit.Test; import org.junit.runner.RunWith; import static org.easymock.EasyMock.expect; import static org.powermock.api.easymock.PowerMock.*; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.legacy.PowerMockRunner; @RunWith(PowerMockRunner.class) @PrepareForTest({Person.class }) public class PersonResourceTest { @Test public void testPost() { Person personMock = createMock(Person.class); expect(personMock.getName()).andReturn("Jon Smith"); replay(personMock); // do the test... Assert.assertEquals("Jon Smith", result.name); } }
create rule pub_idrule as @pub_id in ("1389", "0736", "0877", "1622", "1756") or @pub_id like "99[0-9][0-9]"