Developing JPA application for use in Java SE

These are the steps that i followed to create a JPA project using Rational Application Developer 8.0 and executing it. I am executing this project outside application server. In the next entry i will blog about how to use JPA in J2EE application running inside the WebSphere Application Server.

I am assuming that you already have a CUSTOMER table in your database and now you want to use JPA to work with that table. If you dont have Customer table you can use this DDL to create it

CREATE TABLE CUSTOMER (
CUST_ID INTEGER NOT NULL ,
FIRST_NAME VARCHAR(50) NOT NULL,
LAST_NAME VARCHAR(50),
STREET VARCHAR(50),
APPT VARCHAR(20),
CITY VARCHAR(25),
ZIP_CODE VARCHAR(10) NOT NULL,
CUST_TYPE VARCHAR(10) NOT NULL ,
WEBSITE VARCHAR(100),
LAST_UPDATED_TIME TIMESTAMP
);


ALTER TABLE CUSTOMER ADD CONSTRAINT CUSTOMER_PK Primary Key (CUST_ID);

Follow these steps to create JPA project and execute it.

  1. Open RAD and click on Create new Project -< JPA -< JPA Project. On the next screen enter HelloJPA as project name and click on next next. Make sure to select value of Configuration to Minimal JPA 1.0 Configuration


  2. Next on the JPA Facet dialog box, you can select the existing database connection that you have in RAD. In my case i dont have the connection to the Apache Derby Sample database configured so i need to click on Add Connection


  3. Use the steps provided in Accessing Database using Eclipse/ Rational Application Developer for configuring connection to the database

  4. Once your database connection is configured it will bring you back to the Create JPA Project screen like this, In my case name of the connection that i just configured is "New Connection"


  5. With this your JPA project will be ready, the project generated by RAD does not have anything but the persistence.xml.

  6. In my case i already have a database table that i want to interact with. Now i want to generate JPA code for working with project. So right click on the project and click on JPA Tools -< Generate Entities from table. It will open a dialog box like this. As you can see the New Connection is selected in the Connection select box and you can see the tables in that database. I am only interested in CUSTOMER table so select it.


  7. On the next screen it will ask you few more options for generating entity. Change value of Key Generation to auto and change package name to com.webspherenotes.jpa and click next


  8. In the last screen it will ask you for some information related to customer table things like what should be name of the entity class,.. Keep default values like this


  9. If you look at the HelloJPA project you will notice that RAD has generated a Customer.java class which is entity class (Java object representing Customer table) like this

    'package com.webspherenotes.jpa;

    import java.io.Serializable;
    import javax.persistence.*;
    import java.sql.Timestamp;

    /**
    * The persistent class for the CUSTOMER database table.
    *
    */
    @Entity
    public class Customer implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "CUST_ID")
    private int custId;

    private String appt;

    private String city;

    @Column(name = "CUST_TYPE")
    private String custType;

    @Column(name = "FIRST_NAME")
    private String firstName;

    @Column(name = "LAST_NAME")
    private String lastName;

    @Column(name = "LAST_UPDATED_TIME")
    private Timestamp lastUpdatedTime;

    private String street;

    private String website;

    @Column(name = "ZIP_CODE")
    private String zipCode;

    public Customer() {
    }

    public int getCustId() {
    return this.custId;
    }

    public void setCustId(int custId) {
    this.custId = custId;
    }

    public String getAppt() {
    return this.appt;
    }

    public void setAppt(String appt) {
    this.appt = appt;
    }

    public String getCity() {
    return this.city;
    }

    public void setCity(String city) {
    this.city = city;
    }

    public String getCustType() {
    return this.custType;
    }

    public void setCustType(String custType) {
    this.custType = custType;
    }

    public String getFirstName() {
    return this.firstName;
    }

    public void setFirstName(String firstName) {
    this.firstName = firstName;
    }

    public String getLastName() {
    return this.lastName;
    }

    public void setLastName(String lastName) {
    this.lastName = lastName;
    }

    public Timestamp getLastUpdatedTime() {
    return this.lastUpdatedTime;
    }

    public void setLastUpdatedTime(Timestamp lastUpdatedTime) {
    this.lastUpdatedTime = lastUpdatedTime;
    }

    public String getStreet() {
    return this.street;
    }

    public void setStreet(String street) {
    this.street = street;
    }

    public String getWebsite() {
    return this.website;
    }

    public void setWebsite(String website) {
    this.website = website;
    }

    public String getZipCode() {
    return this.zipCode;
    }

    public void setZipCode(String zipCode) {
    this.zipCode = zipCode;
    }

    public String toString() {
    StringBuffer sb = new StringBuffer();
    sb.append("custId : " + custId);
    sb.append(" First Name : " + firstName);
    sb.append(" Last Name : " + lastName);
    sb.append(" customer type : " + custType);

    return sb.toString();
    }
    }

    I copied the toString() method. You can also get RAD to generate the toString() method for you

  10. Now next step will be to configure database connection properties. For that right click on the HelloJPA project say JPA tools -< Configure Project for JDBC Deployment and select "Set Connection Directly Via properties" radio box. This will copy the connection properties that you used for connecting to DB inside your persistence.xml file like this

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="1.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_1_0.xsd">
    <persistence-unit name="HelloJPA1">
    <class>com.webspherenotes.jpa.Customer</class>
    <properties>
    <property name="openjpa.ConnectionDriverName"
    value="org.apache.derby.jdbc.ClientDriver"/>
    <property name="openjpa.ConnectionURL"
    value="jdbc:derby://localhost:1527/C:/work/webspherenotes/db;create=true"/>
    <property name="openjpa.ConnectionUserName" value="admin"/>
    <property name="openjpa.ConnectionPassword" value="admin"/>
    </properties>
    </persistence-unit>
    </persistence>


  11. Now your JPA code is ready you can use it directly. But you can also ask RAD to create Managed Bean which will generate basic JPA methods for performing CRUD operation on the table. FOr that right click on the HelloJPA project -< JPA Tools -< Add JPA Managed Beans it will open a screen like this

    This list the entities in your project. In my case i have only Customer table so select that and click on next.

  12. Here it will allow you to create few more methods like this


  13. Once you click on finish the RAD will generate CustomerManager.java class like this

    package com.webspherenotes.jpa.controller;

    import java.util.List;

    import com.ibm.jpa.web.JPAManager;
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.Query;

    import com.ibm.jpa.web.Action;
    import com.webspherenotes.jpa.Customer;

    @SuppressWarnings("unchecked")
    @JPAManager(targetEntity = com.webspherenotes.jpa.Customer.class)
    public class CustomerManager {

    private EntityManagerFactory emf;

    public CustomerManager() {

    }

    public CustomerManager(EntityManagerFactory emf) {
    this.emf = emf;
    }

    public void setEntityManagerFactory(EntityManagerFactory emf) {
    this.emf = emf;
    }

    private EntityManager getEntityManager() {
    if (emf == null) {
    throw new RuntimeException(
    "The EntityManagerFactory is null.
    This must be passed in to the constructor or
    set using the setEntityManagerFactory() method.");
    }
    return emf.createEntityManager();
    }

    @Action(Action.ACTION_TYPE.CREATE)
    public String createCustomer(Customer customer) throws Exception {
    EntityManager em = getEntityManager();
    try {
    em.getTransaction().begin();
    em.persist(customer);
    em.getTransaction().commit();
    } catch (Exception ex) {
    try {
    if (em.getTransaction().isActive()) {
    em.getTransaction().rollback();
    }
    } catch (Exception e) {
    ex.printStackTrace();
    throw e;
    }
    throw ex;
    } finally {
    em.close();
    }
    return "";
    }

    @Action(Action.ACTION_TYPE.DELETE)
    public String deleteCustomer(Customer customer) throws Exception {
    EntityManager em = getEntityManager();
    try {
    em.getTransaction().begin();
    customer = em.merge(customer);
    em.remove(customer);
    em.getTransaction().commit();
    } catch (Exception ex) {
    try {
    if (em.getTransaction().isActive()) {
    em.getTransaction().rollback();
    }
    } catch (Exception e) {
    ex.printStackTrace();
    throw e;
    }
    throw ex;
    } finally {
    em.close();
    }
    return "";
    }

    @Action(Action.ACTION_TYPE.UPDATE)
    public String updateCustomer(Customer customer) throws Exception {
    EntityManager em = getEntityManager();
    try {
    em.getTransaction().begin();
    customer = em.merge(customer);
    em.getTransaction().commit();
    } catch (Exception ex) {
    try {
    if (em.getTransaction().isActive()) {
    em.getTransaction().rollback();
    }
    } catch (Exception e) {
    ex.printStackTrace();
    throw e;
    }
    throw ex;
    } finally {
    em.close();
    }
    return "";
    }

    @Action(Action.ACTION_TYPE.FIND)
    public Customer findCustomerByCustId(int custId) {
    Customer customer = null;
    EntityManager em = getEntityManager();
    try {
    customer = (Customer) em.find(Customer.class, custId);
    } finally {
    em.close();
    }
    return customer;
    }

    public List getAllCustomers(){
    List customerList = null;
    EntityManager em = getEntityManager();
    try {
    Query q= em.createQuery("SELECT x from Customer x");
    customerList =(List)q.getResultList();
    System.out.println(customerList.size());
    } finally {
    em.close();
    }
    return customerList;
    }

    @Action(Action.ACTION_TYPE.NEW)
    public Customer getNewCustomer() {

    Customer customer = new Customer();

    return customer;
    }

    }


  14. Now you want to create your own class to test your JPA configuration so create a CustomerTest.java class like this

    package com.webspherenotes.jpa;

    import java.util.List;

    import javax.persistence.EntityManagerFactory;
    import javax.persistence.Persistence;

    import com.webspherenotes.jpa.controller.CustomerManager;

    public class CustomerTest {

    /**
    * @param args
    */
    public static void main(String[] args) {
    try {
    EntityManagerFactory entityManagerFactory = Persistence
    .createEntityManagerFactory("HelloJPA1");

    CustomerManager manager = new CustomerManager(entityManagerFactory);
    Customer customer = new Customer();
    customer.setFirstName("James");
    customer.setLastName("Bond");
    customer.setStreet("845 JB Ave");
    customer.setAppt("153");
    customer.setCity("JBCity");
    customer.setZipCode("007");
    customer.setCustType("test");
    customer.setWebsite("http://www.webspherenotes.com");
    manager.createCustomer(customer);

    System.out.println("Customer with id 1 " + manager.findCustomerByCustId(0));

    } catch (Exception e) {
    e.printStackTrace();
    }

    }

    }

    In this class i am using JPA code to get the EntityManagerFactory but after that i am delegating control to CustomerManager for creating new record in CUSTOMER table

  15. Since we want to execute this code outside application server we will have to make one change, At the runtime you will have to make one configuration change which is to set the value of javaagent to the JPA implementation provided by WebSphere Application server like this
    -javaagent:C:/IBM/WebSphere/AppServer/runtimes/com.ibm.ws.jpa.thinclient_7.0.0.jar


2 comments:

Mitesh said...

I am getting this Exception while running.

Initial EntityManagerFactory creation failed.javax.persistence.PersistenceException: No Persistence provider for EntityManager named TestJPA1: Provider named com.ibm.websphere.persistence.PersistenceProviderImpl threw unexpected exception at create EntityManagerFactory:
org.apache.openjpa.util.GeneralException
org.apache.openjpa.util.GeneralException: org.xml.sax.SAXException: file:/C:/Documents%20and%20Settings/mpandya/IBM/rationalsdp/workspace/TestJPA1/src/META-INF/persistence.xml [Location: Line: 2, C: 248]: org.xml.sax.SAXParseException: cvc-complex-type.3.1: Value '2.0' of attribute 'version' of element 'persistence' is not valid with respect to the corresponding attribute use. Attribute 'version' has a fixed value of '1.0'.
at org.apache.openjpa.lib.meta.XMLMetaDataParser.parseNewResource(XMLMetaDataParser.java:379)
at org.apache.openjpa.lib.meta.XMLMetaDataParser.parse(XMLMetaDataParser.java:318)
at org.apache.openjpa.lib.meta.XMLMetaDataParser.parse(XMLMetaDataParser.java:295)
at org.apache.openjpa.lib.meta.XMLMetaDataParser.parse(XMLMetaDataParser.java:268)
at org.apache.openjpa.persistence.PersistenceProductDerivation$ConfigurationParser.parse(PersistenceProductDerivation.java:509)
at org.apache.openjpa.persistence.PersistenceProductDerivation.parseResources(PersistenceProductDerivation.java:359)
at org.apache.openjpa.persistence.PersistenceProductDerivation.load(PersistenceProductDerivation.java:326)
at org.apache.openjpa.persistence.PersistenceProductDerivation.load(PersistenceProductDerivation.java:161)
at org.apache.openjpa.persistence.PersistenceProviderImpl.createEntityManagerFactory(PersistenceProviderImpl.java:77)
at com.ibm.websphere.persistence.PersistenceProviderImpl.createEntityManagerFactory(PersistenceProviderImpl.java:71)
at com.ibm.websphere.persistence.PersistenceProviderImpl.createEntityManagerFactory(PersistenceProviderImpl.java:41)
at org.apache.openjpa.persistence.PersistenceProviderImpl.createEntityManagerFactory(PersistenceProviderImpl.java:109)
at org.apache.openjpa.persistence.PersistenceProviderImpl.createEntityManagerFactory(PersistenceProviderImpl.java:53)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:110)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:83)
at com.cms.Test.Test.main(Test.java:23)

Hicham said...

@Mitesh,

It says that you are using JPA 1.0, while your persistence.xml file is based on JPA 2.0.
Either provide a JPA 1.0 persistence.xml file, or apply JPA 2.0 osgi feature pack to enable JPA 2.0 on your app server.