December 30, 2015

How do you import static in Eclipse?

When you press Ctrl+Shift+O new imports are added and organized. But that will not work for static imports.

But if you place the cursor on the static import method and press Ctrl+Shift+M, then it will be imported.

Example

package se.magnuskkarlsson.example.timer;

import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.junit.Test;

public class TimerTest {

    @Test
    public void test() throws Exception {
        Assert.assertThat("hello world", CoreMatchers.is(CoreMatchers.containsString("ell")));
    }
}

Now place cursor on each static method and press Ctrl+Shift+M and it will look like.

package se.magnuskkarlsson.example.timer;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import org.junit.Test;

public class TimerTest {

    @Test
    public void test() throws Exception {
        assertThat("hello world", is(containsString("ell")));
    }
}

UTF-8 Charset as Constant in Java 7

Since Java 7 UTF-8 as a constant has been introduced with java.nio.charset.StandardCharsets

Example

new LineNumberReader(new InputStreamReader(new FileInputStream("foo.ini"), StandardCharsets.UTF_8));

Composite Primary Key with Generated and Unique Value with JPA 2.0

Introduction

Sometime you need several column for you primary keys. The background for that can very. There are two solution for that in JPA:

  • @IdClass as inline columns
  • @EmbeddedId with extract column in separate class

Databas Design

  _____________
 |             |
 |   Student   |
 |_____________|
 |             |
 | *studentId  |
 | *groupId    |
 |  firstName  |
 |             |
 |_____________|

@IdClass

@Entity
@IdClass(StudentPK.class)
public class Student implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    private Long studentId;

    @Id
    private Long groupId;

    // the rest is left out for brevity
}
public class StudentPK implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long studentId;

    private Long groupId;

    @Override
    public int hashCode() {
        return (int) (studentId + groupId);
    }

    @Override
    public boolean equals(Object object) {
        if (object instanceof StudentPK) {
            StudentPK otherId = (StudentPK) object;
            return (otherId.studentId == this.studentId)
                    && (otherId.groupId == this.groupId);
        }
        return false;
    }

    public Long getStudentId() {
        return studentId;
    }

    public void setStudentId(Long studentId) {
        this.studentId = studentId;
    }

    public Long getGroupId() {
        return groupId;
    }

    public void setGroupId(Long groupId) {
        this.groupId = groupId;
    }
}

@EmbeddedId

@Entity
public class Student implements Serializable {

    private static final long serialVersionUID = 1L;

    @EmbeddedId
    private StudentPK studentPK;

    // the rest is left out for brevity
}

The StudentPK class remains the same.

Conclusion

The two above option is very much the same and I cannot see any clear advantage for one solution over the other, so I would recommend use the solution that resembles the real world, i.e. SQL and use IdClass.

Automatic Generated Values

When having composite primary key you cannot use @GeneratedValue, but you can use @TableGenerator. Remember there are three strategies for automatic primary key generation values and the only database vendor neutral solution is TABLE.

  • @GeneratedValue(strategy = IDENTITY), with automatic generated value on column. Works only for MySQL and MS SQL.
  • @GeneratedValue(strategy = SEQUENCE), separate sequence. Works only for PostgreSQL and Oracle.
  • @GeneratedValue(strategy = TABLE), the ONLY database vendor neutral solution. ORM specific implementation, does not rely on any database specific technique. Uses separate table to persist increment value and handles increment by it self.
@Entity
@IdClass(StudentPK.class)
public class Student implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @TableGenerator(name = "TABLE_STUDENT_GEN", table = "SEQ_TABLE", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "STUDENT_SEQ")
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_STUDENT_GEN")
    @Column(unique = true)
    private Long studentId;

    @Id
    @TableGenerator(name = "TABLE_GROUP_GEN", table = "SEQ_TABLE", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "GROUP_SEQ")
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GROUP_GEN")
    private Long groupId;

    // the rest is left out for brevity
}

The StudentPK class remains the same.

Which will generate the following database.

    _____________        _____________
   |             |      |             |
   |   Student   |      |   SEQ_TABLE |
   |_____________|      |_____________|
   |             |      |             |
   | *studentId  |      |  SEQ_NAME   |
   | *groupId    |      |  SEQ_COUNT  |
   |  firstName  |      |             |
   |_____________|      |_____________|

NOTE You do not need to have automatic generated values for both columns.

NOTE You do not need to have unique constraint for id column, I just added it to show that you can, because sometimes you want to have it.

December 29, 2015

Mapping OneToMany with JPA 2.0

Introduction

Mapping one-to-many relationship with JPA 2.0, can be done in 2 ways:

  • @OneToMany, with optional @JoinColumn
  • @OneToMany with @JoinTable

Here I will look closer on option one, which is most common. @JoinTable is more common with @ManyToMany relationship/mapping.

Databas Design

    _____________        _____________
   |             |      |             |
   |   Employee  |      |   Phone     |
   |_____________|      |_____________|
   |             |      |             |
   | *employeeId | -->  | *phoneId    |
   |  firstName  |      | *employeeId |
   |_____________|      | areaCode    |
                        |             |
                        |_____________|

Bidrectional OneToMany Mapping

package se.magnuskkarlsson.example.jpa;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;

@Entity
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long employeeId;

    @OneToMany(mappedBy = "owner")
    private List<Phone> phones;

    @Column
    private String firstName;

    // ----------------------- Logic Methods -----------------------

    public void addPhone(Phone phone) {
        this.getPhones().add(phone);
        if (phone.getOwner() != this) {
            phone.setOwner(this);
        }
    }

    // ----------------------- Helper Methods -----------------------

    // ----------------------- Get and Set Methods -----------------------

    public Long getEmployeeId() {
        return employeeId;
    }

    public void setEmployeeId(Long employeeId) {
        this.employeeId = employeeId;
    }

    public List<Phone> getPhones() {
        if (phones == null) {
            phones = new ArrayList<Phone>();
        }
        return phones;
    }

    public void setPhones(List<Phone> phones) {
        this.phones = phones;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
}
package se.magnuskkarlsson.example.jpa;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Phone {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long phoneId;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "OWNER_ID")
    private Employee owner;

    @Column
    private int areaCode;

    // ----------------------- Logic Methods -----------------------

    // ----------------------- Helper Methods -----------------------

    // ----------------------- Get and Set Methods -----------------------

    public Long getPhoneId() {
        return phoneId;
    }

    public void setPhoneId(Long phoneId) {
        this.phoneId = phoneId;
    }

    public Employee getOwner() {
        return owner;
    }

    public void setOwner(Employee employee) {
        this.owner = employee;
        if (!employee.getPhones().contains(this)) {
            // warning this may cause performance issues if you have a large
            // data set since this operation is O(n)
            employee.getPhones().add(this);
        }
    }

    public int getAreaCode() {
        return areaCode;
    }

    public void setAreaCode(int areaCode) {
        this.areaCode = areaCode;
    }
}

Now lets write some test code to test this.


    private EntityManagerFactory emf;

    private EntityManager em;

    @Before
    public void setUp() throws Exception {
        emf = Persistence.createEntityManagerFactory("it");
        em = emf.createEntityManager();
    }

    @After
    public void tearDown() throws Exception {
        em.close();
        emf.close();
    }

    @Test
    public void testRelationship() throws Exception {
        em.getTransaction().begin();

        Phone phone1 = new Phone();
        em.persist(phone1);
       
        Phone phone2 = new Phone();
        em.persist(phone2);
       
        Employee emp = new Employee();
        emp.addPhone(phone1);
        emp.addPhone(phone2);
        em.persist(emp);

        em.getTransaction().commit();

        em.getTransaction().begin();

        // SELECT DISTINCT
        // http://stackoverflow.com/questions/8199512/jpql-inner-join-without-duplicate-records
        // JOIN FETCH
        // https://en.wikibooks.org/wiki/Java_Persistence/Relationships#Join_Fetching
        String sql = "SELECT DISTINCT e FROM Employee e JOIN FETCH e.phones";
        TypedQuery<Employee> query = em.createQuery(sql, Employee.class);
        List<Employee> list = query.getResultList();
        System.out.println("QUERY RESULT");
        for (Employee e : list) {
            System.out.println(e);
            for (Phone p : e.getPhones()) {
                System.out.println("   " + p);
            }
        }

        em.getTransaction().commit();
    }

And the debug output from Hibernate

Hibernate: 
    insert 
    into
        Phone
        (OWNER_ID) 
    values
        (?)
Hibernate: 
    insert 
    into
        Phone
        (OWNER_ID) 
    values
        (?)
Hibernate: 
    insert 
    into
        Employee
        
    values
        ( )
Hibernate: 
    update
        Phone 
    set
        OWNER_ID=? 
    where
        id=?
Hibernate: 
    update
        Phone 
    set
        OWNER_ID=? 
    where
        id=?
Hibernate: 
    select
        distinct employee0_.EMP_ID as EMP_ID1_1_0_,
        phones1_.id as id1_2_1_,
        phones1_.OWNER_ID as OWNER_ID2_2_1_,
        phones1_.OWNER_ID as OWNER_ID2_1_0__,
        phones1_.id as id1_2_0__ 
    from
        Employee employee0_ 
    inner join
        Phone phones1_ 
            on employee0_.EMP_ID=phones1_.OWNER_ID
QUERY RESULT
se.magnuskkarlsson.example.jpa.Employee@232864a3
   se.magnuskkarlsson.example.jpa.Phone@84c5310
   se.magnuskkarlsson.example.jpa.Phone@32dcce09

As we can see the above create operation, generates 5 SQL statements (3 INSERTS and 2 UPDATES).

The same behavior with multiple INSERT followed by UPDATE, happens when you want to create a new Phone. Then you need to load the Employee class and then call addPhone(Phone). This is not optimal as you can see. Now lets consider another approach with unidirectional mapping.

First Attempt Unidirectional OneToMany Mapping

First we update our mapping annotations./p>

@Entity
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long employeeId;

    // @OneToMany(mappedBy = "owner")
    @OneToMany
    @JoinColumn(name = "employeeId", referencedColumnName = "employeeId")
    private List<Phone> phones;

    @Column
    private String firstName;

    public void addPhone(Phone phone) {
        this.getPhones().add(phone);
        phone.setEmployeeId(getEmployeeId());
    }

    // the rest is left out for brevity
}
@Entity
public class Phone {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long phoneId;

    @Column(nullable = false)
    private Long employeeId;

    @Column
    private int areaCode;

    // the rest is left out for brevity
Hibernate: 
    insert 
    into
        Phone
        (OWNER_ID) 
    values
        (?)
Hibernate: 
    insert 
    into
        Phone
        (OWNER_ID) 
    values
        (?)
Hibernate: 
    insert 
    into
        Employee
        
    values
        ( )
Hibernate: 
    update
        Phone 
    set
        OWNER_ID=? 
    where
        id=?
Hibernate: 
    update
        Phone 
    set
        OWNER_ID=? 
    where
        id=?
Hibernate: 
    select
        distinct employee0_.EMP_ID as EMP_ID1_1_0_,
        phones1_.id as id1_2_1_,
        phones1_.OWNER_ID as OWNER_ID2_2_1_,
        phones1_.OWNER_ID as OWNER_ID2_1_0__,
        phones1_.id as id1_2_0__ 
    from
        Employee employee0_ 
    inner join
        Phone phones1_ 
            on employee0_.EMP_ID=phones1_.OWNER_ID
QUERY RESULT
se.magnuskkarlsson.example.jpa.Employee@46764885
   se.magnuskkarlsson.example.jpa.Phone@6ecc295c
   se.magnuskkarlsson.example.jpa.Phone@7c2a88f4

As we can see, we still need 5 SQL operations. But we can do better. Think how the underlying SQL is working. There is nothing magic when JPA or ORM. Lets first create parent Employee and then create children Phone and explicit set foreign key.

Second Attempt Unidirectional OneToMany Mapping

Mapping is the same, but "business logic" is changed.

        Employee emp = new Employee();
        emp.setFirstName("Bob");
        em.persist(emp);

        Phone phone1 = new Phone();
        phone1.setEmployeeId(emp.getEmployeeId());
        phone1.setAreaCode(613);
        em.persist(phone1);

        Phone phone2 = new Phone();
        phone2.setEmployeeId(emp.getEmployeeId());
        phone2.setAreaCode(416);
        em.persist(phone2);

        // Employee is cached in first second cache, since reusing Session
        em.detach(emp);
Hibernate: 
    insert 
    into
        Employee
        
    values
        ( )
Hibernate: 
    insert 
    into
        Phone
        (OWNER_ID) 
    values
        (?)
Hibernate: 
    insert 
    into
        Phone
        (OWNER_ID) 
    values
        (?)
Hibernate: 
    select
        distinct employee0_.EMP_ID as EMP_ID1_1_0_,
        phones1_.id as id1_2_1_,
        phones1_.OWNER_ID as OWNER_ID2_2_1_,
        phones1_.OWNER_ID as OWNER_ID2_1_0__,
        phones1_.id as id1_2_0__ 
    from
        Employee employee0_ 
    inner join
        Phone phones1_ 
            on employee0_.EMP_ID=phones1_.OWNER_ID
QUERY RESULT
se.magnuskkarlsson.example.jpa.Employee@a7072fd
   se.magnuskkarlsson.example.jpa.Phone@232864a3
   se.magnuskkarlsson.example.jpa.Phone@72f1b266

As we can see the number of SQL statement is now reduced to the natural number that is sensible needed. And when we need to create a new child Phone we do not need to load and add it to parent Employee.

Is there any downside with this solution. Not really if we would like bidirectional behavior we could add a @Transient parameter and set it lazy, just as we would have done with if the mapping was bidirectional. One would maybe think of keeping bidirectional mapping eager, but that is not a good pattern/practice, since you could risk to load huge object graphs into memory, which would impact the performance negative.

@Entity
public class Phone {

    @Transient
    private Employee employee;

    // the rest is left out for brevity
}

The Rest of the Files

To make this complete here is the rest of the code.

src/test/resources/META-INF

<?xml version="1.0" encoding="UTF-8"?>
<persistence 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"
    version="2.0">

    <persistence-unit name="it" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <class>se.magnuskkarlsson.example.jpa.Company</class>
        <class>se.magnuskkarlsson.example.jpa.Employee</class>
        <class>se.magnuskkarlsson.example.jpa.Phone</class>
        <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
        <validation-mode>CALLBACK</validation-mode>
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="create-drop" />
<!-- 
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
            <property name="hibernate.connection.driver_class" value="org.h2.Driver" />
            <property name="hibernate.connection.url" value="jdbc:h2:mem:" />
 -->
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/EXAMPLE" />
            <property name="javax.persistence.jdbc.user" value="root" />
            <property name="javax.persistence.jdbc.password" value="root" />

            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true" />
            <property name="hibernate.generate_statistics" value="false" />
        </properties>
    </persistence-unit>
</persistence>

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>se.magnuskkarlsson.examples</groupId>
    <artifactId>example-jpa</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>Example JPA</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.build.outputEncoding>UTF-8</project.build.outputEncoding>
        <hibernate-version>4.2.14.Final</hibernate-version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
            <scope>provided</scope>
        </dependency>

        <!-- Test Support -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.2</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.185</version>
            <scope>test</scope>
        </dependency>

        <!-- <dependency> <groupId>org.apache.derby</groupId> <artifactId>derbyclient</artifactId> 
            <version>10.7.1.1</version> <scope>test</scope> </dependency> -->

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.34</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate-version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-infinispan</artifactId>
            <version>${hibernate-version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>4.3.1.Final</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <debug>true</debug>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.18</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-ejb-plugin</artifactId>
                <version>2.5</version>
                <configuration>
                    <ejbVersion>3.1</ejbVersion>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.5</version>
            </plugin>
        </plugins>
    </build>
</project>