Introduction to EclipseLink

In this tutorial, we learn the basics of EclipseLink. We use Derby and Spring Boot in our examples. The projects are built with NetBeans.

EclipseLink

EclipseLink is an open source Eclipse Persistence Services Project from the Eclipse Foundation. The software provides an extensible framework that allows Java developers to interact with various data services, including databases, web services, Object XML mapping, and Enterprise Information Systems. EclipseLink is based on the TopLink product from which Oracle contributed the source code to create the EclipseLink project. EclipseLink is the reference implementation of the Java Persistence API.

The Java Persistence API (JPA) is a Java application programming interface specification that describes the management of relational data in applications using Java. Java Persistence Query Language (JPQL) is a platform-independent object-oriented query language. It is a part of the JPA specification. JPQL is used to make queries against entities stored in a relational database. It is heavily inspired by SQL, and its queries resemble SQL queries in syntax, but operate against JPA entity objects rather than directly with database tables.

Entity is a Java class that is to be persisted with JPA. It must be decorated with the javax.persistence.Entity annotation. In addition, it must have the @Id annotation, which defines the unique ID of the primary key of the entity, and the @GeneratedValue, which defines strategies for generation of primary keys. The @Table annotation specifies the database table to which the entity is mapped.

The persistence.xml is a standard configuration file in JPA. It has to be included in the META-INF directory inside the JAR file that contains the entity beans. In this file we define persistence units which define a set of all entity classes that are managed by entity manager instances in an application. EntityManager is a class that manages the persistent state of entities.

EclipseLink reading data

The first example is a Java command line program, which retrieves all rows from the Cars table. We create a new NetBeans Java Maven project.

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.zetcode</groupId>
    <artifactId>Persistence</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    
    <dependencies>
        
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>eclipselink</artifactId>
            <version>2.6.4</version>
        </dependency>
        
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.40</version>
        </dependency>

    </dependencies>
    
</project>

In the pom.xml file, we define two dependencies: eclipselink and derbyclient.

Creating persistence.xml file
Figure: Creating persistence.xml file

To create the persistence.xml, we righ-click on the project file, select New — Other, and choose the Persistence category. There is a Persistence unit option.

persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="cars-pu" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>

        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:derby://localhost:1527/testdb"/>
            <property name="javax.persistence.jdbc.user" value="app"/>
            <property name="javax.persistence.jdbc.password" value="app"/>
      
            <property name="javax.persistence.schema-generation.database.action"
                      value="drop-and-create"/>
            <property name="javax.persistence.sql-load-script-source" value="META-INF/sql/data.sql"/>            

        </properties>
    </persistence-unit>
  
</persistence>

In the persistence.xml file we define a persistence unit named cars-pu. We define a persistence provider, which is a Derby database.

<property name="javax.persistence.schema-generation.database.action"
            value="drop-and-create"/>

With this property set, EclipseLink will drop and create a database table. The Cars table is created from the provided metadata.

<property name="javax.persistence.sql-load-script-source" value="META-INF/sql/data.sql"/>       

Here we specify the SQL file, which fills the table with data.

The persistence.xml file
Figure: The persistence.xml file

The persistence.xml file is located in the META-INF subdirectory

data.sql
INSERT INTO CARS(Name, Price) VALUES('Audi', 52642);
INSERT INTO CARS(Name, Price) VALUES('Mercedes', 57127);
INSERT INTO CARS(Name, Price) VALUES('Skoda', 9000);
INSERT INTO CARS(Name, Price) VALUES('Volvo', 29000);
INSERT INTO CARS(Name, Price) VALUES('Bentley', 350000);
INSERT INTO CARS(Name, Price) VALUES('Citroen', 21000);
INSERT INTO CARS(Name, Price) VALUES('Hummer', 41400);
INSERT INTO CARS(Name, Price) VALUES('Volkswagen', 21600);

This is the SQL to fill the Cars table with eight rows.

Car.java
package com.zetcode;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="Cars")
public class Car implements Serializable {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long Id;
    private String name;
    private int price;

    public Long getId() {
        return Id;
    }

    public void setId(Long Id) {
        this.Id = Id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}

This is our entity class. It is decorated with the @Entity annotation.

@Table(name="Cars")

The @Table annotation refers to the Cars table in the Derby database.

DBClient.java
package com.zetcode;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

public class DBClient {

    public static void main(String[] args) {

        EntityManagerFactory emf = Persistence.createEntityManagerFactory("cars-pu");
        EntityManager eman = emf.createEntityManager();

        try {

            String sql = "SELECT c FROM Car c";

            Query query = eman.createQuery(sql);
            List<Car> cars = query.getResultList();

            for (Car car : cars) {
                System.out.printf("%d ", car.getId());
                System.out.printf("%s ", car.getName());
                System.out.println(car.getPrice());
            }
            
        } finally {

            eman.close();
            emf.close();
        }
    }
}

This is a Java console application, which retrieves all rows from the Cars table with the help of the entity manager.

EntityManagerFactory emf = Persistence.createEntityManagerFactory("cars-pu");

When using a JPA provider like EclipseLink outside JEE containers, we have to create an entity manager via the EntityManagerFactory. The factory is created with the Persistence.createEntityManagerFactory() method, taking the persistence unit name as a parameter.

EntityManager eman = emf.createEntityManager();

From the EntityManagerFactory, we create an EntityManager with the createEntityManager() method. The created EntityManager is an application-managed entity manager.

String sql = "SELECT c FROM Car c";

This looks like SQL code but it is not. It is an example of a Java Persistence Query Language (JPQL) statement. It returns all Car entities from the database table.

Query query = eman.createQuery(sql);

A Query object is created with the createQuery() method.

List<Car> cars = query.getResultList();

From the query object, we get the list of Car objects.

} finally {

    eman.close();
    emf.close();
}

For application-managed entity managers, we have to explicitly close the resources.

1 Audi 52642
2 Mercedes 57127
3 Skoda 9000
4 Volvo 29000
5 Bentley 350000
6 Citroen 21000
7 Hummer 41400
8 Volkswagen 21600

After we start Derby, build the application, and execute it, we get this output.

EclipseLink saving a new row

In the second example, we save a new car object into the database. The pom.xml, persistence.xml, Car.java are identical to those used in the previous example.

DBClient2.java
package com.zetcode;

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

public class DBClient2 {

    public static void main(String[] args) {

        EntityManagerFactory efact = Persistence.createEntityManagerFactory("cars-pu");
        EntityManager eman = efact.createEntityManager();

        try {

            eman.getTransaction().begin();

            Car car = new Car();
            car.setName("Toyota");
            car.setPrice(26700);

            eman.persist(car);
            eman.getTransaction().commit();
            
        } finally {
            
            eman.close();
            efact.close();
        }
    }
}

The example creates a new car object and saves it in the database.

eman.getTransaction().begin();

Automatic transaction management is not available outside JEE container; therefore, we have to manually create a new transaction.

Car car = new Car();
car.setName("Toyota");
car.setPrice(26700);

A new car entity is created. The ID will be generated by Derby.

eman.persist(car);

The persist() method saves the entity into the database.

eman.getTransaction().commit();

The transaction is committed.

Spring Boot example with EclipseLink

In this example, we integrate EclipseLink in a Spring Boot application. Spring is a popular Java application framework. Spring Boot is a Spring's solution to create stand-alone, production-grade Spring based applications. It is a new solution to create Spring applications with minimal effort.

The sources for the following example are also available on author's Github repository.

Spring Boot project
Figure: Spring Boot project

This is the Spring Boot project in NetBeans.

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
            
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.zetcode</groupId>
    <artifactId>SpringBootEclipseLink</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.3.RELEASE</version>
        <relativePath />
    </parent>  
    
    <dependencies>
        
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>eclipselink</artifactId>
            <version>2.6.4</version>
        </dependency>
     
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>    
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>hibernate-entitymanager</artifactId>
                    <groupId>org.hibernate</groupId>
                </exclusion>
            </exclusions>
        </dependency>       
        
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
        </dependency>                        
                                             
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>
                org.eclipse.persistence.jpa.modelgen.processor
            </artifactId>
            <version>2.5.2</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>    
    
</project>

This is the Maven project file. We have dependencies for EclipseLink, Derby, Hibernate Validator, and Spring Boot.

application.properties
# Derby
spring.datasource.driverClassName=org.apache.derby.jdbc.ClientDriver
spring.datasource.url=jdbc:derby://localhost:1527/testdb
spring.datasource.username=app
spring.datasource.password=app

In the application.properties file, we define the datasource for Derby.

persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    
    <persistence-unit name="cars-pu" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>

        <properties>
            <property name="javax.persistence.jdbc.url" value="jdbc:derby://localhost:1527/testdb"/>
            <property name="javax.persistence.jdbc.user" value="app"/>
            <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
            <property name="javax.persistence.jdbc.password" value="app"/>
            <property name="javax.persistence.schema-generation.database.action"
                      value="drop-and-create"/>
            <property name="javax.persistence.sql-load-script-source" value="META-INF/sql/data.sql"/>       
        </properties>
    </persistence-unit>
  
</persistence>

In the persistence.xml file, we create a persistence unit. It is called cars-pu. We also let the EclipseLink create a database table for us.

data.sql
INSERT INTO CARS(Name, Price) VALUES('Audi', 52642)
INSERT INTO CARS(Name, Price) VALUES('Mercedes', 57127)
INSERT INTO CARS(Name, Price) VALUES('Skoda', 9000)
INSERT INTO CARS(Name, Price) VALUES('Volvo', 29000)
INSERT INTO CARS(Name, Price) VALUES('Bentley', 350000)
INSERT INTO CARS(Name, Price) VALUES('Citroen', 21000)
INSERT INTO CARS(Name, Price) VALUES('Hummer', 41400)
INSERT INTO CARS(Name, Price) VALUES('Volkswagen', 21600)

EclipseLink will use this SQL file to fill the automatically created table with data.

AppConf.java
package com.zetcode.conf;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConf {

    @Bean
    public EntityManager entityManager(EntityManagerFactory entityManagerFactory) {
        return entityManagerFactory.createEntityManager();
    }
    
    @Bean
    public EntityManagerFactory createEntityManagerFactory() {
        return Persistence.createEntityManagerFactory("cars-pu");
    }
}

Two beans are created in AppConf: EntityManagerFactory and EntityManager. The EntityManager will be injected into the CarsServiceImpl.

Car.java
package com.zetcode.bean;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

@Entity
@Table(name="Cars")
@NamedQueries({
    @NamedQuery(name = "Car.findAll", query = "SELECT c FROM Car c"),
    @NamedQuery(name = "Car.findByName", query = "SELECT c FROM Car c WHERE c.name = :name")
})
public class Car {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long Id;
    private String name;
    private int price;

    public Long getId() {
        return Id;
    }

    public void setId(Long Id) {
        this.Id = Id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}

This is our Entity bean.

@NamedQueries({
    @NamedQuery(name = "Car.findAll", query = "SELECT c FROM Car c"),
    @NamedQuery(name = "Car.findByName", query = "SELECT c FROM Car c WHERE c.name = :name")
})

The class is annotated with named queries, which are JPQL statements for retrieving all car objects and finding a car by its name.

CarsService.java
package com.zetcode.service;

import com.zetcode.bean.Car;
import java.util.List;

public interface CarsService {

    public void saveCar(Car car);

    public Car findCarByName(String name);

    public List<Car> findAll();
}

In the CarsService interface, we define the contract methods for accessing the database via entity manager.

CarsServiceImpl.java
package com.zetcode.service;

import com.zetcode.bean.Car;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.springframework.stereotype.Component;

@Component
public class CarsServiceImpl implements CarsService {

    @PersistenceContext
    EntityManager em;

    @Override
    public void saveCar(Car car) {

        em.getTransaction().begin();
        em.persist(car);
        em.getTransaction().commit();
    }

    @Override
    public Car findCarByName(String name) {

        Query query = em.createNamedQuery("Car.findByName");

        query.setParameter("name", name);
        Car car = (Car) query.getSingleResult();

        return car;
    }

    @Override
    public List<Car> findAll() {

        Query query = em.createNamedQuery("Car.findAll");
        
        List<Car> cars = query.getResultList();

        return cars;
    }
}

The CarsServiceImpl is a business service class which implements the methods for saving a car, finding a car by its name, and retrieving all cars from a database.

@PersistenceContext
EntityManager em;

The EntityManager is injected into the class with the @PersistenceContext annotation.

@Override
public void saveCar(Car car) {

    em.getTransaction().begin();
    em.persist(car);
    em.getTransaction().commit();
}

The saveCar() method saves a car into the database with the EntityManager's persist() method. The persist() method is placed inside the manually created transaction.

@Override
public Car findCarByName(String name) {

    Query query = em.createNamedQuery("Car.findByName");

    query.setParameter("name", name);
    Car car = (Car) query.getSingleResult();

    return car;
}

The findCarByName() method finds a car by its name. The createNamedQuery() creates a named query; it refers to the named query defined in the Car entity class. A parameter is set to the named query with the setParameter() method.

@Override
public List<Car> findAll() {

    Query query = em.createNamedQuery("Car.findAll");
    
    List<Car> cars = query.getResultList();

    return cars;
}

A named query Car.findAll is created. The getResultList() of the query returns a list of retrieved cars.

MyRunner.java
package com.zetcode.client;

import com.zetcode.bean.Car;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.stereotype.Component;
import com.zetcode.service.CarsService;

@Component
public class MyRunner implements CommandLineRunner {

    @Autowired
    private CarsService crs;

    @Override
    public void run(String... args) throws Exception {
        
        try {
            Car car = crs.findCarByName("Citroen");
            System.out.printf("ID: %d%n", car.getId());
            System.out.printf("Name: %s%n", car.getName());
            System.out.printf("Price: %d%n", car.getPrice());
            
        } catch (EmptyResultDataAccessException e) {
            System.out.println("Car was not found");
        }

        List<Car> cars = crs.findAll();
        
        for (Car car: cars) {
            System.out.printf("%d ", car.getId());
            System.out.printf("%s ", car.getName());
            System.out.println(car.getPrice());
        }
    }
}

The MyRunner is a command line runner for the Spring Boot CLI application. We look for a Citroen car and retrieve all cars from the database.

@Autowired
private CarsService crs;

The CarsService bean is injected into the MyRunner class.

Car car = crs.findCarByName("Citroen");

The service's findCarByName() looks for a car named Citroen.

List<Car> cars = crs.findAll();

The service's findAll() method retrieves all cars from the database.

SpringDBCLIApp.java
package com.zetcode.client;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;

@EnableAutoConfiguration
@ComponentScan(basePackages="com.zetcode")
public class SpringDBCLIApp {

    public static void main(String[] args) {

        SpringApplication.run(SpringDBCLIApp.class, args);
    }
}

The SpringDBCLIApp sets up the Spring Boot CLI application.

In this tutorial, we have presented the EclipseLink JPA provider. ZetCode has the following related tutorials: Spring JdbcTemplate tutorial, Hibernate Derby tutorial, Java tutorial, and Introduction to EJBs.