As a JPA Provider I selected EclipseLink as it is a reference implementation, but I am sure that Hibernate and other stuff can easily replace EclipseLink. For JAX-RS I used Jersey. Tomcat was my server to test on.
As you can see from screenshot below there are only 5 valuable files and the structure of the project - the typical web project, generating WAR deployment archive. So the project structure for maven build will be a bit different. There are some point here - persistence.xml should be located so class loader can pick it up. So it is placed directly under source folder, under META-INF folder, so we have two META-INF directories in the project.
I created the only one entity as an example: Employee.java
package com.maxud.model;
import javax.persistence.*;
@Entity
@Table(name = "user_")
public class Employee {
@Id
@Column(name = "userId")
private Long id;
@Column(name = "firstName")
private String firstName;
@Column(name = "lastName")
private String lastName;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
We don't want to make the difficult setup, so database connection settings are placed here. Below is the file itself, main points here are:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="EmployeePU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>com.maxud.model.Employee</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost/portal?useUnicode=true&characterEncoding=UTF-8"/>
<property name="javax.persistence.jdbc.user" value="portal"/>
<property name="javax.persistence.jdbc.password" value="portal"/>
<!-- EclipseLink should create the database schema automatically -->
<!--
<property name="eclipselink.ddl-generation" value="create-tables" />
<property name="eclipselink.ddl-generation.output-mode" value="database" />
-->
</properties>
</persistence-unit>
</persistence>
All stuff is quite important here:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>RestProjectTest</display-name>
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.maxud.controller</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
It is taking care of persistence unit initialization so you can get the EntityManager whenever you want from other part of your application.
package com.maxud.listener;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class LocalEntityManagerFactory implements ServletContextListener{
private static EntityManagerFactory emf;
@Override
public void contextInitialized(ServletContextEvent event) {
emf = Persistence.createEntityManagerFactory("EmployeePU");
}
@Override
public void contextDestroyed(ServletContextEvent event) {
emf.close();
}
public static EntityManager createEntityManager() {
if (emf == null) {
throw new IllegalStateException("Context is not initialized yet.");
}
return emf.createEntityManager();
}
}
There are some points here:
package com.maxud.controller;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.maxud.listener.LocalEntityManagerFactory;
import com.maxud.model.Employee;
@Path("/employee")
public class EmployeeController {
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}")
public Employee read(@PathParam("id") long id) {
long start = System.currentTimeMillis();
System.out.println("EmployeeController.read() started");
EntityManager em = LocalEntityManagerFactory.createEntityManager();
try {
return em.find(Employee.class, id);
} finally {
em.close();
System.out.println("Getting data took " + (System.currentTimeMillis() - start) + "ms.");
}
}
public static void main(String ...args) {
Map props = new HashMap();
EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeePU", props);
Employee emp = emf.createEntityManager().find(Employee.class, new Long(23411));
if (emp != null) {
System.out.println("Your user is: " + emp.getFirstName() + " " + emp.getLastName());
}
emf.close();
}
}
That's it.
Best wishes,
Max