Kohei Nozaki's blog 

Working example of EclipseLink static weaving


Posted on Saturday Oct 24, 2015 at 03:37AM in JPA


These days I’m using EclipseLink at work. It runs on Servlet containers, unfortunately not Java EE containers at there so I have experienced some difference between them. A significant one is class weaving. The dynamic weaving is enabled by default in Java EE containers but not for Java SE environment. Weaving is a prerequisite of using some important functions such as Lazy Loading but it doesn’t work for default Java SE environment. In Java SE environment, EclipseLink requires a special prerequisite that set an agent in the time of launching JVM, or use static weaving to enable Lazy Loading.

Static weaving offers some performance benefit over Dynamic weaving because it doesn’t require runtime weaving step. I think it’s preferable so I tried it over another.

Environment

  • EclipseLink 2.6.1

  • Apache Derby 10.12.1.1

  • Oracle JDK8u60

Projects

This project contains three simple entity classes. Dept has many Employee, and Employee has one Phone.

Dept

@Entity
public class Dept implements Serializable {
    @Id
    private Long id;
    private String deptName;
    @OneToMany(mappedBy = "dept")
    private List<Employee> employees;

    // accessors omitted

Employee

@Entity
public class Employee implements Serializable {
    @Id
    private Long id;
    @ManyToOne(fetch = FetchType.EAGER) // default
    @JoinColumn(nullable = false)
    private Dept dept;
    private String firstName;
    private String lastName;
    @OneToOne(mappedBy = "employee", fetch = FetchType.LAZY) // overridden by LAZY
    private Phone phone;

    // accessors omitted

Note that the relation Employee.dept is set to EAGER, and Employee.phone is set to LAZY as FetchType.

Phone

@Entity
public class Phone implements Serializable {
    @Id
    @OneToOne
    @JoinColumn(nullable = false)
    private Employee employee;
    private String phoneNumber;

    // accessors omitted

persistence.xml

The persistence descriptor requires a property called eclipselink.weaving with the value static to enable static weaving.

<?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="myPU" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <shared-cache-mode>NONE</shared-cache-mode>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:derby:memory:myDB;create=true"/>
            <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="eclipselink.weaving" value="static"/>
            <property name="eclipselink.logging.level" value="FINE"/>
            <property name="eclipselink.logging.parameters" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

pom.xml

The static weaving will be done by a convenient Maven plugin. Just put following plugin definition in your pom.xml and execute mvn clean install.

<build>
    <plugins>
        <plugin>
            <groupId>de.empulse.eclipselink</groupId>
            <artifactId>staticweave-maven-plugin</artifactId>
            <version>1.0.0</version>
            <executions>
                <execution>
                    <phase>process-classes</phase>
                    <goals>
                        <goal>weave</goal>
                    </goals>
                    <configuration>
                        <persistenceXMLLocation>META-INF/persistence.xml</persistenceXMLLocation>
                        <logLevel>FINE</logLevel>
                    </configuration>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>org.eclipse.persistence</groupId>
                    <artifactId>org.eclipse.persistence.jpa</artifactId>
                    <version>${eclipselink.version}</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

This project is a client of the preceding eclipselink-entity project. It has a Main class which simply populates some records then fetches them.

public class Main {
    public static void main(String[] args) {
        EntityManagerFactory emf = null;
        try {
            emf = Persistence.createEntityManagerFactory("myPU");
            EntityManager em = null;

            // Populating data
            try {
                em = emf.createEntityManager();
                final EntityTransaction tx = em.getTransaction();
                tx.begin();

                Dept dept = new Dept();
                dept.setId(1l);
                dept.setDeptName("Engineering");
                dept.setEmployees(new ArrayList<>());
                em.persist(dept);

                Employee emp = new Employee();
                emp.setId(1l);
                emp.setFirstName("Jane");
                emp.setLastName("Doe");
                dept.getEmployees().add(emp);
                emp.setDept(dept);
                em.persist(emp);

                Phone phone = new Phone();
                phone.setPhoneNumber("000-1111-2222");
                phone.setEmployee(emp);
                emp.setPhone(phone);
                em.persist(phone);

                tx.commit();
            } finally { if (em != null) { em.close(); } }

            System.out.println("<<< Populating done >>>");

            try {
                em = emf.createEntityManager();
                final Employee emp = em.find(Employee.class, 1l);

                System.out.println(emp.getFirstName() + " " + emp.getLastName());

                // EAGER
                System.out.println(emp.getDept().getDeptName());
                // LAZY
                System.out.println(emp.getPhone().getPhoneNumber());
            } finally { if (em != null) { em.close(); } }
        } finally { if (emf != null) { emf.close(); } }
    }
}

Here you can see the Phone entity has lazily fetched while Dept entity was eagerly fetched:

<<< Populating done >>>
[EL Fine]: sql: 2015-10-24 03:18:23.389--ServerSession(1216590855)--Connection(1488298739)--Thread(Thread[main,5,main])--SELECT ID, FIRSTNAME, LASTNAME, DEPT_ID FROM EMPLOYEE WHERE (ID = ?)
	bind => [1]
[EL Fine]: sql: 2015-10-24 03:18:23.408--ServerSession(1216590855)--Connection(1488298739)--Thread(Thread[main,5,main])--SELECT ID, DEPTNAME FROM DEPT WHERE (ID = ?)
	bind => [1]
Jane Doe
Engineering
[EL Fine]: sql: 2015-10-24 03:18:23.413--ServerSession(1216590855)--Connection(1488298739)--Thread(Thread[main,5,main])--SELECT PHONENUMBER, EMPLOYEE_ID FROM PHONE WHERE (EMPLOYEE_ID = ?)
	bind => [1]
000-1111-2222

This example uses in-memory Apache Derby so you don’t need to set up any databases to execute this example. complete projects can be obtained from following GitHub repositories: