- to setup Hibernate to use a datasource defined under Glassfish, see my other post.
- usefull Jersey annotations:
- for the resource class: @Path("/person/")
- for a method: @GET @Path("{personId}/") @Produces("application/json"). Then, you can use public Person getUser(@PathParam("personId") int personId) for method declaration.
- add @Consumes("application/json") with public Person post(Person person) method declaration. Jersey takes care of unmarshaling the Json into Person object.
- to return an error code from the restfull webservice, throw a new WebApplicationException(Response.Status.NOT_FOUND), for example. This one would return 404 error. No Need to declare the jersey handler method as "throws ...".
- to unit test the service, use com.sun.jersey.api.client.Client:
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());
- To pass an object retrieved via Hibernate as a response from a webservice, it needs to be serializable. But objects retrieved this way have additional members and so they need to be converted to a pure entity object (Person, in my case). I have used the Dozer library for this purpose (see the code below).
- The entity classes (Person and PersonCollection, in my example)need to be annotated with @XmlRootElement.
Code:
Complete web service implementation class code (in RESTfull, call a resource):
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; } }
Open Questions:
- I'm not sure where the Hibernate session should be closed. I don't think this can be done at the end of each handler method.
- How to use JTA for transaction management instead of direct JDBC transaction management?
- Most of the Hibernate-specific code should go into a DAO, with most of it into a generic DAO. But the recommended by Hibernate documentation generic DAO is defined in terms of state-oriented data access API (makePersistent() and makeTransient() methods), which are less intuitive for me. What is the advantage of using them and how to use them from CRUD operations?