Additional Blogs by SAP
cancel
Showing results for 
Search instead for 
Did you mean: 
Former Member

Here is a short and simple example of how to use JPA outside of EJB container and provide JSON rest output.

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.

Project structure.

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.

Creating entities.

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;
          }
}

Describing persistence.xml

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:

  • Persistence Unit name
  • JPA entity provider, in this case EclipseLink
  • List of entity classes
  • jdbc connection settings
  • EclipseLink related properties
<?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&amp;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>

Deployment descriptor web.xml

All stuff is quite important here:

  • Including Jersey servlet taking care of Rest Services (listens specific package) and parameter, producing the json output

<?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>

Adding WebListener, taking care of JPA initialization: LocalEntityManagerFactory.java

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();
    }
}

Web Controller, Web Service and JSON output

There are some points here:

  • Rest service can be call by GET HTTP method, using path /employee/412731
  • 412731 is used as parameter to read() method
  • we are taking EntityManager, make call to database
  • Method return Employee type which is transformed to JSON because of @Produces(MediaType.APPLICATION_JSON) annotation
  • btw, you can easily access database even without deployment to web container, see main() method as an example.
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

2 Comments